diff --git a/include/libtorrent/http_tracker_connection.hpp b/include/libtorrent/http_tracker_connection.hpp index 76c3aac98..70be3054a 100755 --- a/include/libtorrent/http_tracker_connection.hpp +++ b/include/libtorrent/http_tracker_connection.hpp @@ -69,13 +69,20 @@ namespace libtorrent { public: http_parser(); - template - T header(char const* key) const; + std::string const& header(char const* key) const + { + static std::string empty; + std::map::const_iterator i + = m_header.find(key); + if (i == m_header.end()) return empty; + return i->second; + } + std::string const& protocol() const { return m_protocol; } int status_code() const { return m_status_code; } std::string const& method() const { return m_method; } std::string const& path() const { return m_path; } - std::string message() const { return m_server_message; } + std::string const& message() const { return m_server_message; } buffer::const_interval get_body() const; bool header_finished() const { return m_state == read_body; } bool finished() const { return m_finished; } @@ -103,15 +110,6 @@ namespace libtorrent bool m_finished; }; - template - T http_parser::header(char const* key) const - { - std::map::const_iterator i - = m_header.find(key); - if (i == m_header.end()) return T(); - return boost::lexical_cast(i->second); - } - class TORRENT_EXPORT http_tracker_connection : public tracker_connection { diff --git a/src/http_connection.cpp b/src/http_connection.cpp index 2b306ca6d..5a0cfb741 100644 --- a/src/http_connection.cpp +++ b/src/http_connection.cpp @@ -263,7 +263,7 @@ void http_connection::on_read(asio::error_code const& e if (code >= 300 && code < 400) { // attempt a redirect - std::string url = m_parser.header("location"); + std::string const& url = m_parser.header("location"); if (url.empty()) { // missing location header diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 64dea2e2e..8c54cf7ff 100755 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -679,7 +679,7 @@ namespace libtorrent if (m_parser.header_finished()) { - int cl = m_parser.header("content-length"); + int cl = atoi(m_parser.header("content-length").c_str()); if (cl > m_settings.tracker_maximum_response_length) { fail(-1, "content-length is greater than maximum response length"); @@ -718,7 +718,7 @@ namespace libtorrent return; } - std::string location = m_parser.header("location"); + std::string location = m_parser.header("location"); boost::shared_ptr cb = requester(); @@ -763,7 +763,7 @@ namespace libtorrent buffer::const_interval buf(&m_buffer[0] + m_parser.body_start(), &m_buffer[0] + m_recv_pos); - std::string content_encoding = m_parser.header("content-encoding"); + std::string content_encoding = m_parser.header("content-encoding"); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) if (cb) cb->debug_log("content-encoding: \"" + content_encoding + "\""); diff --git a/src/lsd.cpp b/src/lsd.cpp index d7590ec47..0e55b2e8c 100644 --- a/src/lsd.cpp +++ b/src/lsd.cpp @@ -121,48 +121,53 @@ void lsd::on_announce(udp::endpoint const& from, char* buffer { using namespace libtorrent::detail; - char* p = buffer; - char* end = buffer + bytes_transferred; - char* line = std::find(p, end, '\n'); - for (char* i = p; i < line; ++i) *i = std::tolower(*i); -#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) - m_log << time_now_string() - << " <== announce: " << std::string(p, line) << std::endl; -#endif - if (line == end || (line - p >= 9 && std::memcmp("bt-search", p, 9))) + http_parser p; + + p.incoming(buffer::const_interval(buffer, buffer + bytes_transferred)); + + if (!p.header_finished()) { #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) - m_log << time_now_string() - << " *** assumed 'bt-search', ignoring" << std::endl; + m_log << time_now_string() + << " <== announce: incomplete HTTP message\n"; #endif return; } - p = line + 1; - int port = 0; - sha1_hash ih(0); - while (p != end) + + if (p.method() != "bt-search") { - line = std::find(p, end, '\n'); - if (line == end) break; - *line = 0; - for (char* i = p; i < line; ++i) *i = std::tolower(*i); - if (line - p >= 5 && memcmp(p, "port:", 5) == 0) - { - p += 5; - while (*p == ' ') ++p; - port = atoi(p); - } - else if (line - p >= 9 && memcmp(p, "infohash:", 9) == 0) - { - p += 9; - while (*p == ' ') ++p; - if (line - p > 40) p[40] = 0; - try { ih = boost::lexical_cast(p); } - catch (std::exception&) {} - } - p = line + 1; +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + m_log << time_now_string() + << " <== announce: invalid HTTP method: " << p.method() << std::endl; +#endif + return; } + std::string const& port_str = p.header("port"); + if (port_str.empty()) + { +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + m_log << time_now_string() + << " <== announce: invalid BT-SEARCH, missing port" << std::endl; +#endif + return; + } + + std::string const& ih_str = p.header("infohash"); + if (ih_str.empty()) + { +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + m_log << time_now_string() + << " <== announce: invalid BT-SEARCH, missing infohash" << std::endl; +#endif + return; + } + + sha1_hash ih(0); + std::istringstream ih_sstr(ih_str); + ih_sstr >> ih; + int port = atoi(port_str.c_str()); + if (!ih.is_all_zeros() && port != 0) { #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) diff --git a/src/upnp.cpp b/src/upnp.cpp index 87f950b48..ebb8884e1 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -300,7 +300,7 @@ try return; } - std::string url = p.header("location"); + std::string url = p.header("location"); if (url.empty()) { #ifdef TORRENT_UPNP_LOGGING diff --git a/src/web_peer_connection.cpp b/src/web_peer_connection.cpp index a307fc9cb..24b301e92 100755 --- a/src/web_peer_connection.cpp +++ b/src/web_peer_connection.cpp @@ -387,7 +387,7 @@ namespace libtorrent { // this means we got a redirection request // look for the location header - std::string location = m_parser.header("location"); + std::string location = m_parser.header("location"); if (location.empty()) { @@ -423,7 +423,7 @@ namespace libtorrent throw std::runtime_error("redirecting to " + location); } - std::string server_version = m_parser.header("server"); + std::string const& server_version = m_parser.header("server"); if (!server_version.empty()) { m_server_string = "URL seed @ "; @@ -445,7 +445,7 @@ namespace libtorrent size_type range_end; if (m_parser.status_code() == 206) { - std::stringstream range_str(m_parser.header("content-range")); + std::stringstream range_str(m_parser.header("content-range")); char dummy; std::string bytes; range_str >> bytes >> range_start >> dummy >> range_end; @@ -461,7 +461,7 @@ namespace libtorrent else { range_start = 0; - range_end = m_parser.header("content-length"); + range_end = atol(m_parser.header("content-length").c_str()); if (range_end == -1) { // we should not try this server again. diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index 7aabf593b..0b3fc4eed 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -102,8 +102,8 @@ int test_main() TEST_CHECK(received == make_tuple(4, 64)); 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"); - TEST_CHECK(parser.header("content-length") == 4); + TEST_CHECK(parser.header("content-type") == "text/plain"); + TEST_CHECK(atoi(parser.header("content-length").c_str()) == 4); parser.reset(); @@ -123,11 +123,11 @@ int test_main() TEST_CHECK(received == make_tuple(0, int(strlen(upnp_response)))); TEST_CHECK(parser.get_body().left() == 0); - TEST_CHECK(parser.header("st") == "upnp:rootdevice"); - TEST_CHECK(parser.header("location") + TEST_CHECK(parser.header("st") == "upnp:rootdevice"); + TEST_CHECK(parser.header("location") == "http://192.168.1.1:5431/dyndev/uuid:000f-66d6-7296000099dc"); - TEST_CHECK(parser.header("ext") == ""); - TEST_CHECK(parser.header("date") == "Fri, 02 Jan 1970 08:10:38 GMT"); + TEST_CHECK(parser.header("ext") == ""); + TEST_CHECK(parser.header("date") == "Fri, 02 Jan 1970 08:10:38 GMT"); parser.reset(); TEST_CHECK(!parser.finished()); @@ -148,6 +148,41 @@ int test_main() TEST_CHECK(parser.method() == "notify"); TEST_CHECK(parser.path() == "*"); + parser.reset(); + TEST_CHECK(!parser.finished()); + + char const* bt_lsd = "BT-SEARCH * HTTP/1.1\r\n" + "Host: 239.192.152.143:6771\r\n" + "Port: 6881\r\n" + "Infohash: 12345678901234567890\r\n" + "\r\n\r\n"; + + received = feed_bytes(parser, bt_lsd); + + TEST_CHECK(received == make_tuple(2, int(strlen(bt_lsd) - 2))); + TEST_CHECK(parser.method() == "bt-search"); + TEST_CHECK(parser.path() == "*"); + TEST_CHECK(atoi(parser.header("port").c_str()) == 6881); + TEST_CHECK(parser.header("infohash") == "12345678901234567890"); + + TEST_CHECK(!parser.finished()); + + parser.reset(); + TEST_CHECK(!parser.finished()); + + // make sure we support trackers with incorrect line endings + char const* tracker_response = + "HTTP/1.1 200 OK\n" + "content-length: 5\n" + "content-type: test/plain\n" + "\n" + "\ntest"; + + received = feed_bytes(parser, tracker_response); + + TEST_CHECK(received == make_tuple(5, int(strlen(tracker_response) - 5))); + TEST_CHECK(parser.get_body().left() == 5); + // test xml parser char xml1[] = "foobar";