diff --git a/simulation/test_http_connection.cpp b/simulation/test_http_connection.cpp index e961a3038..a4ef4a280 100644 --- a/simulation/test_http_connection.cpp +++ b/simulation/test_http_connection.cpp @@ -40,10 +40,14 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/proxy_settings.hpp" #include "libtorrent/http_connection.hpp" #include "libtorrent/resolver.hpp" +#include "libtorrent/io.hpp" + +#include using namespace libtorrent; using namespace sim; namespace lt = libtorrent; +namespace io = lt::detail; using chrono::duration_cast; @@ -174,6 +178,7 @@ enum expect_counters rel_redirect_req = 4, inf_redirect_req = 5, chunked_req = 6, + test_file_gz_req = 7, num_counters }; @@ -208,8 +213,10 @@ TORRENT_TEST(http_connection) // make sure hostname lookup failures are passed through correctly run_test("http://non-existent.com/test_file", 0, -1, asio::error::host_not_found, { 0, 1}); + // make sure we handle gzipped content correctly + run_test(url_base + "/test_file.gz", 1337, 200, error_code(), { 1, 1, 0, 0, 0, 0, 0, 1}); + // run_test(url_base + "/password_protected", 1337, 200, error_code(), { 1, 1, 1}); -// run_test(url_base + "/test_file.gz", 1337, 200, error_code(), { 1, 1, 1}); //#error test all proxies //#error test https @@ -263,6 +270,39 @@ void run_test(std::string url, int expect_size, int expect_status + chunk_string(std::string(data_buffer, 1337)); }); + http.register_handler("/test_file.gz" + , [data_buffer,&counters](std::string method, std::string req + , std::map& headers) + { + ++counters[test_file_gz_req]; + print_http_header(headers); + TEST_EQUAL(method, "GET"); + + char const* extra_headers[4] = {"Content-Encoding: gzip\r\n", "", "", ""}; + unsigned char const gzheader[] = { + 0x1f , 0x8b , 0x08 , 0x00 // ID, compression=deflate, flags=0 + , 0x00 , 0x00 , 0x00 , 0x00 // mtime=0 + , 0x00, 0x01 // extra headers, OS + , 0x01 // last block, uncompressed + , 0x39 , 0x05, 0xc6 , 0xfa // length = 1337 (little endian 16 bit and inverted) + }; + unsigned char trailer[8] = { 0, 0, 0, 0, 0x39, 0x05, 0x00, 0x00 }; + boost::crc_32_type crc; + crc.process_bytes(data_buffer, 1337); + boost::uint32_t checksum = crc.checksum(); + trailer[0] = checksum >> 24; + trailer[1] = (checksum >> 16) & 0xff; + trailer[2] = (checksum >> 8) & 0xff; + trailer[3] = (checksum) & 0xff; + + std::string ret = sim::send_response(200, "OK", 1337 + sizeof(gzheader) + + sizeof(trailer), extra_headers); + ret.append(std::string((char const*)gzheader, sizeof(gzheader))); + ret.append(data_buffer, 1337); + ret.append(std::string((char const*)trailer, sizeof(trailer))); + return ret; + }); + http.register_handler("/redirect" , [data_buffer,&counters](std::string method, std::string req , std::map& headers) diff --git a/src/gzip.cpp b/src/gzip.cpp index 99627c883..c262e6b23 100644 --- a/src/gzip.cpp +++ b/src/gzip.cpp @@ -119,6 +119,8 @@ namespace libtorrent const unsigned char* buffer = reinterpret_cast(buf); const int total_size = size; + // gzip is defined in https://tools.ietf.org/html/rfc1952 + // The zip header cannot be shorter than 10 bytes if (size < 10 || buf == 0) return -1; @@ -129,9 +131,14 @@ namespace libtorrent int flags = buffer[3]; // check for reserved flag and make sure it's compressed with the correct metod + // we only support deflate if (method != 8 || (flags & FRESERVED) != 0) return -1; - // skip time, xflags, OS code + // skip time, xflags, OS code. The first 10 bytes of the header: + // +---+---+---+---+---+---+---+---+---+---+ + // |ID1|ID2|CM |FLG| MTIME |XFL|OS | (more-->) + // +---+---+---+---+---+---+---+---+---+---+ + size -= 10; buffer += 10;