made http_parser not use exceptions

This commit is contained in:
Arvid Norberg 2007-12-29 18:24:50 +00:00
parent 599ed646f0
commit 6c42830f97
7 changed files with 62 additions and 37 deletions

View File

@ -86,7 +86,8 @@ namespace libtorrent
buffer::const_interval get_body() const;
bool header_finished() const { return m_state == read_body; }
bool finished() const { return m_finished; }
boost::tuple<int, int> incoming(buffer::const_interval recv_buffer);
boost::tuple<int, int> incoming(buffer::const_interval recv_buffer
, bool& error);
int body_start() const { return m_body_start_pos; }
int content_length() const { return m_content_length; }
@ -104,7 +105,7 @@ namespace libtorrent
int m_content_length;
enum { read_status, read_header, read_body } m_state;
enum { read_status, read_header, read_body, error_state } m_state;
std::map<std::string, std::string> m_header;
buffer::const_interval m_recv_buffer;

View File

@ -285,15 +285,13 @@ void http_connection::on_read(asio::error_code const& e
{
libtorrent::buffer::const_interval rcv_buf(&m_recvbuffer[0]
, &m_recvbuffer[0] + m_read_pos);
try
bool error = false;
m_parser.incoming(rcv_buf, error);
if (error)
{
m_parser.incoming(rcv_buf);
}
catch (std::exception& e)
{
m_timer.cancel();
m_handler(asio::error::fault, m_parser, 0, 0);
m_handler.clear();
// HTTP parse error
asio::error_code ec = asio::error::fault;
callback(ec, 0, 0);
return;
}
if (!m_bottled && m_parser.header_finished())

View File

@ -104,7 +104,8 @@ namespace libtorrent
, m_finished(false)
{}
boost::tuple<int, int> http_parser::incoming(buffer::const_interval recv_buffer)
boost::tuple<int, int> http_parser::incoming(
buffer::const_interval recv_buffer, bool& error)
{
TORRENT_ASSERT(recv_buffer.left() >= m_recv_buffer.left());
boost::tuple<int, int> ret(0, 0);
@ -113,6 +114,12 @@ namespace libtorrent
if (recv_buffer.left() == m_recv_buffer.left()) return ret;
m_recv_buffer = recv_buffer;
if (m_state == error_state)
{
error = true;
return ret;
}
char const* pos = recv_buffer.begin + m_recv_pos;
if (m_state == read_status)
{
@ -122,7 +129,11 @@ namespace libtorrent
if (newline == recv_buffer.end) return ret;
if (newline == pos)
throw std::runtime_error("unexpected newline in HTTP response");
{
m_state = error_state;
error = true;
return ret;
}
char const* line_end = newline;
if (pos != line_end && *(line_end - 1) == '\r') --line_end;
@ -211,7 +222,9 @@ namespace libtorrent
range_str >> range_start >> dummy >> range_end;
if (!range_str || range_end < range_start)
{
throw std::runtime_error("invalid content-range in HTTP response: " + range_str.str());
m_state = error_state;
error = true;
return ret;
}
// the http range is inclusive
m_content_length = range_end - range_start + 1;
@ -316,8 +329,11 @@ namespace libtorrent
std::size_t pos = request.find("announce");
if (pos == std::string::npos)
throw std::runtime_error("scrape is not available on url: '"
+ tracker_req().url +"'");
{
fail(-1, ("scrape is not available on url: '"
+ tracker_req().url +"'").c_str());
return;
}
request.replace(pos, 8, "scrape");
}
@ -670,8 +686,13 @@ namespace libtorrent
#endif
m_recv_pos += bytes_transferred;
bool e = false;
m_parser.incoming(buffer::const_interval(&m_buffer[0]
, &m_buffer[0] + m_recv_pos));
, &m_buffer[0] + m_recv_pos), e);
if (e)
{
fail(-1, "incorrect http response");
}
// if the receive buffer is full, expand it with http_buffer_size
if ((int)m_buffer.size() == m_recv_pos)

View File

@ -123,9 +123,11 @@ void lsd::on_announce(udp::endpoint const& from, char* buffer
http_parser p;
p.incoming(buffer::const_interval(buffer, buffer + bytes_transferred));
bool error = false;
p.incoming(buffer::const_interval(buffer, buffer + bytes_transferred)
, error);
if (!p.header_finished())
if (!p.header_finished() || error)
{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
m_log << time_now_string()

View File

@ -266,16 +266,14 @@ try
*/
http_parser p;
try
{
p.incoming(buffer::const_interval(buffer
, buffer + bytes_transferred));
}
catch (std::exception& e)
bool error = false;
p.incoming(buffer::const_interval(buffer
, buffer + bytes_transferred), error);
if (error)
{
#ifdef TORRENT_UPNP_LOGGING
m_log << time_now_string()
<< " <== (" << from << ") Rootdevice responded with incorrect HTTP packet. Ignoring device (" << e.what() << ")" << std::endl;
m_log << time_now_string() << " <== (" << from << ") Rootdevice "
"responded with incorrect HTTP packet. Ignoring device" << std::endl;
#endif
return;
}

View File

@ -315,7 +315,6 @@ namespace libtorrent
}
}
// throws exception when the client should be disconnected
void web_peer_connection::on_receive(asio::error_code const& error
, std::size_t bytes_transferred)
{
@ -344,9 +343,13 @@ namespace libtorrent
bool header_finished = m_parser.header_finished();
if (!header_finished)
{
boost::tie(payload, protocol) = m_parser.incoming(recv_buffer);
bool error = false;
boost::tie(payload, protocol) = m_parser.incoming(recv_buffer, error);
m_statistics.received_bytes(payload, protocol);
if (error)
throw std::runtime_error("failed to parse HTTP response");
TORRENT_ASSERT(recv_buffer.left() == 0 || *recv_buffer.begin == 'H');
TORRENT_ASSERT(recv_buffer.left() <= packet_size());

View File

@ -18,17 +18,19 @@ using namespace libtorrent;
using namespace boost::tuples;
using boost::bind;
tuple<int, int> feed_bytes(http_parser& parser, char const* str)
tuple<int, int, bool> feed_bytes(http_parser& parser, char const* str)
{
tuple<int, int> ret(0, 0);
tuple<int, int, bool> ret(0, 0, false);
buffer::const_interval recv_buf(str, str + 1);
for (; *str; ++str)
{
recv_buf.end = str + 1;
int payload, protocol;
tie(payload, protocol) = parser.incoming(recv_buf);
bool error = false;
tie(payload, protocol) = parser.incoming(recv_buf, error);
ret.get<0>() += payload;
ret.get<1>() += protocol;
ret.get<2>() += error;
}
return ret;
}
@ -135,14 +137,14 @@ int test_main()
// HTTP request parser
http_parser parser;
boost::tuple<int, int> received = feed_bytes(parser
boost::tuple<int, int, bool> received = feed_bytes(parser
, "HTTP/1.1 200 OK\r\n"
"Content-Length: 4\r\n"
"Content-Type: text/plain\r\n"
"\r\n"
"test");
TEST_CHECK(received == make_tuple(4, 64));
TEST_CHECK(received == make_tuple(4, 64, false));
TEST_CHECK(parser.finished());
TEST_CHECK(std::equal(parser.get_body().begin, parser.get_body().end, "test"));
TEST_CHECK(parser.header("content-type") == "text/plain");
@ -164,7 +166,7 @@ int test_main()
received = feed_bytes(parser, upnp_response);
TEST_CHECK(received == make_tuple(0, int(strlen(upnp_response))));
TEST_CHECK(received == make_tuple(0, int(strlen(upnp_response)), false));
TEST_CHECK(parser.get_body().left() == 0);
TEST_CHECK(parser.header("st") == "upnp:rootdevice");
TEST_CHECK(parser.header("location")
@ -187,7 +189,7 @@ int test_main()
received = feed_bytes(parser, upnp_notify);
TEST_CHECK(received == make_tuple(0, int(strlen(upnp_notify))));
TEST_CHECK(received == make_tuple(0, int(strlen(upnp_notify)), false));
TEST_CHECK(parser.method() == "notify");
TEST_CHECK(parser.path() == "*");
@ -202,7 +204,7 @@ int test_main()
received = feed_bytes(parser, bt_lsd);
TEST_CHECK(received == make_tuple(2, int(strlen(bt_lsd) - 2)));
TEST_CHECK(received == make_tuple(2, int(strlen(bt_lsd) - 2), false));
TEST_CHECK(parser.method() == "bt-search");
TEST_CHECK(parser.path() == "*");
TEST_CHECK(atoi(parser.header("port").c_str()) == 6881);
@ -223,7 +225,7 @@ int test_main()
received = feed_bytes(parser, tracker_response);
TEST_CHECK(received == make_tuple(5, int(strlen(tracker_response) - 5)));
TEST_CHECK(received == make_tuple(5, int(strlen(tracker_response) - 5), false));
TEST_CHECK(parser.get_body().left() == 5);
// test xml parser