From 6c42830f97a1823118fa41bf89e2fcb4f90bedc2 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 29 Dec 2007 18:24:50 +0000 Subject: [PATCH] made http_parser not use exceptions --- .../libtorrent/http_tracker_connection.hpp | 5 +-- src/http_connection.cpp | 14 ++++---- src/http_tracker_connection.cpp | 33 +++++++++++++++---- src/lsd.cpp | 6 ++-- src/upnp.cpp | 14 ++++---- src/web_peer_connection.cpp | 7 ++-- test/test_primitives.cpp | 20 ++++++----- 7 files changed, 62 insertions(+), 37 deletions(-) diff --git a/include/libtorrent/http_tracker_connection.hpp b/include/libtorrent/http_tracker_connection.hpp index 41df4c953..5ff28dadb 100755 --- a/include/libtorrent/http_tracker_connection.hpp +++ b/include/libtorrent/http_tracker_connection.hpp @@ -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 incoming(buffer::const_interval recv_buffer); + boost::tuple 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 m_header; buffer::const_interval m_recv_buffer; diff --git a/src/http_connection.cpp b/src/http_connection.cpp index 8d8de6723..3f7272a12 100644 --- a/src/http_connection.cpp +++ b/src/http_connection.cpp @@ -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()) diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 505d8ffb2..5a21e8482 100755 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -104,7 +104,8 @@ namespace libtorrent , m_finished(false) {} - boost::tuple http_parser::incoming(buffer::const_interval recv_buffer) + boost::tuple http_parser::incoming( + buffer::const_interval recv_buffer, bool& error) { TORRENT_ASSERT(recv_buffer.left() >= m_recv_buffer.left()); boost::tuple 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) diff --git a/src/lsd.cpp b/src/lsd.cpp index 06e570f3c..1c3d977c0 100644 --- a/src/lsd.cpp +++ b/src/lsd.cpp @@ -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() diff --git a/src/upnp.cpp b/src/upnp.cpp index 01815b99b..89b5cd8f3 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -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; } diff --git a/src/web_peer_connection.cpp b/src/web_peer_connection.cpp index 71ce2d430..04d8ac252 100755 --- a/src/web_peer_connection.cpp +++ b/src/web_peer_connection.cpp @@ -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()); diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index 654bd3927..15835fe95 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -18,17 +18,19 @@ using namespace libtorrent; using namespace boost::tuples; using boost::bind; -tuple feed_bytes(http_parser& parser, char const* str) +tuple feed_bytes(http_parser& parser, char const* str) { - tuple ret(0, 0); + tuple 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 received = feed_bytes(parser + boost::tuple 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