From 560ef29276cf1b0963b8a111e12aec86b06351e3 Mon Sep 17 00:00:00 2001 From: arvidn Date: Thu, 10 Aug 2017 11:15:46 +0200 Subject: [PATCH] fix issue with very long tracker- and web seed URLs. Instead of using a fixed length stack allocated request buffer, use a dynamically growing stringstream --- ChangeLog | 1 + src/http_connection.cpp | 39 ++++++++++++++--------------------- test/test_http_connection.cpp | 8 +++++++ 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0196ea502..c540d4a80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * fix issue with very long tracker- and web seed URLs * don't attempt to create empty files on startup, if they already exist * fix force-recheck issue (new files would not be picked up) * fix inconsistency in file_priorities and override_resume_data behavior diff --git a/src/http_connection.cpp b/src/http_connection.cpp index f599e8356..5f18b452d 100644 --- a/src/http_connection.cpp +++ b/src/http_connection.cpp @@ -167,13 +167,7 @@ void http_connection::get(std::string const& url, time_duration timeout, int pri bool ssl = false; if (protocol == "https") ssl = true; - char request[4096]; - char* end = request + sizeof(request); - char* ptr = request; - -#define APPEND_FMT(fmt) ptr += snprintf(ptr, end - ptr, fmt) -#define APPEND_FMT1(fmt, arg) ptr += snprintf(ptr, end - ptr, fmt, arg) -#define APPEND_FMT2(fmt, arg1, arg2) ptr += snprintf(ptr, end - ptr, fmt, arg1, arg2) + std::stringstream request; // exclude ssl here, because SSL assumes CONNECT support in the // proxy and is handled at the lower layer @@ -183,40 +177,39 @@ void http_connection::get(std::string const& url, time_duration timeout, int pri { // if we're using an http proxy and not an ssl // connection, just do a regular http proxy request - APPEND_FMT1("GET %s HTTP/1.1\r\n", url.c_str()); + request << "GET " << url << " HTTP/1.1\r\n"; if (ps->type == settings_pack::http_pw) - APPEND_FMT1("Proxy-Authorization: Basic %s\r\n", base64encode( - ps->username + ":" + ps->password).c_str()); + request << "Proxy-Authorization: Basic " << base64encode( + ps->username + ":" + ps->password) << "\r\n"; hostname = ps->hostname; port = ps->port; - APPEND_FMT1("Host: %s", hostname.c_str()); - if (port != default_port) APPEND_FMT1(":%d\r\n", port); - else APPEND_FMT("\r\n"); + request << "Host: " << hostname; + if (port != default_port) request << ":" << port << "\r\n"; + else request << "\r\n"; } else { - APPEND_FMT2("GET %s HTTP/1.1\r\n" - "Host: %s", path.c_str(), hostname.c_str()); - if (port != default_port) APPEND_FMT1(":%d\r\n", port); - else APPEND_FMT("\r\n"); + request << "GET " << path << " HTTP/1.1\r\nHost: " << hostname; + if (port != default_port) request << ":" << port << "\r\n"; + else request << "\r\n"; } -// APPEND_FMT("Accept: */*\r\n"); +// request << "Accept: */*\r\n"; if (!m_user_agent.empty()) - APPEND_FMT1("User-Agent: %s\r\n", m_user_agent.c_str()); + request << "User-Agent: " << m_user_agent << "\r\n"; if (m_bottled) - APPEND_FMT("Accept-Encoding: gzip\r\n"); + request << "Accept-Encoding: gzip\r\n"; if (!auth.empty()) - APPEND_FMT1("Authorization: Basic %s\r\n", base64encode(auth).c_str()); + request << "Authorization: Basic " << base64encode(auth) << "\r\n"; - APPEND_FMT("Connection: close\r\n\r\n"); + request << "Connection: close\r\n\r\n"; - m_sendbuffer.assign(request); + m_sendbuffer.assign(request.str()); m_url = url; start(hostname, port, timeout, prio , ps, ssl, handle_redirects, bind_addr, m_resolve_flags diff --git a/test/test_http_connection.cpp b/test/test_http_connection.cpp index c19bd5990..b68fb85e9 100644 --- a/test/test_http_connection.cpp +++ b/test/test_http_connection.cpp @@ -201,6 +201,14 @@ void run_suite(std::string const& protocol run_test(url_base + "password_protected", 3216, 200, 1, error_code(), ps , "testuser:testpass"); + // try a very long path + std::string path; + for (int i = 0; i < 6000; ++i) + { + path += static_cast(i % 26) + 'a'; + } + run_test(url_base + path, 0, 404, 1, err(), ps); + // only run the tests to handle NX_DOMAIN if we have a proper internet // connection that doesn't inject false DNS responses (like Comcast does) hostent* h = gethostbyname("non-existent-domain.se");