From c6e46ae305d37502b9f4edd4730c847a1f27f9ee Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 1 Nov 2015 17:22:40 -0500 Subject: [PATCH] improve http_connection simulation test and extend it --- simulation/test_http_connection.cpp | 167 +++++++++++++++++++++------- 1 file changed, 126 insertions(+), 41 deletions(-) diff --git a/simulation/test_http_connection.cpp b/simulation/test_http_connection.cpp index ab08d65d1..9ee6deee6 100644 --- a/simulation/test_http_connection.cpp +++ b/simulation/test_http_connection.cpp @@ -62,25 +62,25 @@ struct sim_config : sim::default_config return duration_cast(chrono::milliseconds(100)); } + if (hostname == "try-next.com") + { + result.push_back(address_v4::from_string("10.0.0.10")); + result.push_back(address_v4::from_string("10.0.0.9")); + result.push_back(address_v4::from_string("10.0.0.8")); + result.push_back(address_v4::from_string("10.0.0.7")); + result.push_back(address_v4::from_string("10.0.0.6")); + result.push_back(address_v4::from_string("10.0.0.5")); + result.push_back(address_v4::from_string("10.0.0.4")); + result.push_back(address_v4::from_string("10.0.0.3")); + result.push_back(address_v4::from_string("10.0.0.2")); + return duration_cast(chrono::milliseconds(100)); + } + return default_config::hostname_lookup(requestor, hostname, result, ec); } }; -void on_alert_notify(lt::session* ses) -{ - std::vector alerts; - ses->pop_alerts(&alerts); - - for (lt::alert* a : alerts) - { - lt::time_duration d = a->timestamp().time_since_epoch(); - boost::uint32_t millis = lt::duration_cast(d).count(); - printf("%4d.%03d: %s\n", millis / 1000, millis % 1000, - a->message().c_str()); - } -} - -boost::shared_ptr run_test(io_service& ios +boost::shared_ptr test_request(io_service& ios , resolver& res , std::string const& url , char const* expected_data @@ -99,20 +99,22 @@ boost::shared_ptr run_test(io_service& ios , [=](error_code const& ec, http_parser const& parser , char const* data, const int size, http_connection& c) { - fprintf(stderr, "RESPONSE: %s\n", url.c_str()); + printf("RESPONSE: %s\n", url.c_str()); ++*handler_called; + + if (ec != expected_ec) + { + printf("ERROR: %s (expected: %s)\n" + , ec.message().c_str() + , expected_ec.message().c_str()); + } + const int http_status = parser.status_code(); if (expected_size != -1) { TEST_EQUAL(size, expected_size); } TEST_EQUAL(ec, expected_ec); - if (ec != expected_ec) - { - fprintf(stderr, "ERROR: %s (expected: %s)\n" - , ec.message().c_str() - , expected_ec.message().c_str()); - } if (expected_status != -1) { TEST_EQUAL(http_status, expected_status); @@ -129,7 +131,7 @@ boost::shared_ptr run_test(io_service& ios { ++*connect_handler_called; TEST_CHECK(c.socket().is_open()); - fprintf(stderr, "CONNECTED: %s\n", url.c_str()); + printf("CONNECTED: %s\n", url.c_str()); }); h->get(url, seconds(1), 0, &ps, 5, "test/user-agent", address_v4::any() @@ -142,39 +144,123 @@ void print_http_header(std::map const& headers) for (std::map::const_iterator i = headers.begin(), end(headers.end()); i != end; ++i) { - std::cerr << i->first << ": " << i->second << std::endl; + printf("%s: %s\n", i->first.c_str(), i->second.c_str()); } } + +void run_test(std::string url, int expect_size, int expect_status + , boost::system::error_code expect_error, std::vector expect_counters); + +enum expect_counters +{ + connect_handler = 0, + handler = 1, + test_file_req = 2, + redirect_req = 3, + rel_redirect_req = 4, + inf_redirect_req = 5, + + num_counters +}; + TORRENT_TEST(http_connection) +{ + std::string url_base = "http://10.0.0.2:8080"; + + run_test(url_base + "/non-existent", 0, 404, error_code(), { 1, 1 }); + run_test(url_base + "/test_file", 1337, 200, error_code(), { 1, 1, 1}); + run_test(url_base + "/redirect", 1337, 200, error_code(), { 2, 1, 1, 1 }); + run_test(url_base + "/relative/redirect", 1337, 200, error_code(), {2, 1, 1, 0, 1}); + run_test(url_base + "/infinite/redirect", 0, 301, error_code(asio::error::eof), {6, 1, 0, 0, 0, 6}); + + // we are on an IPv4 host, we can't connect to IPv6 addresses, make sure that + // error is correctly propagated + run_test("http://[ff::dead:beef]:8080/test_file", 0, -1, error_code(asio::error::address_family_not_supported) + , {0,1}); + + // this hostname will resolve to multiple IPs, all but one that we cannot + // connect to and the second one where we'll get the test file response. Make + // sure the http_connection correcly tries the second IP if the first one + // fails. + run_test("http://try-next.com:8080/test_file", 1337, 200, error_code(), { 1, 1, 1}); + + // 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}); + +// 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 +//#error test chunked encoding + +} + +void run_test(std::string url, int expect_size, int expect_status + , boost::system::error_code expect_error, std::vector expect_counters) { using sim::asio::ip::address_v4; sim_config network_cfg; sim::simulation sim{network_cfg}; + // allow sparse expected counters + expect_counters.resize(num_counters, 0); + sim::asio::io_service web_server(sim, address_v4::from_string("10.0.0.2")); sim::asio::io_service ios(sim, address_v4::from_string("10.0.0.1")); + sim::asio::io_service ipv6_host(sim, address_v6::from_string("ff::dead:beef")); lt::resolver res(ios); sim::http_server http(web_server, 8080); + sim::http_server http_v6(ipv6_host, 8080); char data_buffer[4000]; std::generate(data_buffer, data_buffer + sizeof(data_buffer), &std::rand); + std::vector counters(num_counters, 0); + http.register_handler("/test_file" - , [data_buffer](std::string method, std::string req + , [data_buffer,&counters](std::string method, std::string req , std::map& headers) { + ++counters[test_file_req]; print_http_header(headers); - TEST_EQUAL(headers["user-agent"], "test/user-agent"); TEST_EQUAL(method, "GET"); return sim::send_response(200, "OK", 1337).append(data_buffer, 1337); }); - int connect_handler_called = 0; - int handler_called = 0; + http.register_handler("/redirect" + , [data_buffer,&counters](std::string method, std::string req + , std::map& headers) + { + ++counters[redirect_req]; + TEST_EQUAL(method, "GET"); + return "HTTP/1.1 301 Moved Temporarily\r\n" + "Location: /test_file\r\n" + "\r\n"; + }); - int expect_connect_handler_called = 0; - int expect_handler_called = 0; + http.register_handler("/relative/redirect" + , [data_buffer,&counters](std::string method, std::string req + , std::map& headers) + { + ++counters[rel_redirect_req]; + TEST_EQUAL(method, "GET"); + return "HTTP/1.1 301 Moved Temporarily\r\n" + "Location: ../test_file\r\n" + "\r\n"; + }); + + http.register_handler("/infinite/redirect" + , [data_buffer,&counters](std::string method, std::string req + , std::map& headers) + { + ++counters[inf_redirect_req]; + TEST_EQUAL(method, "GET"); + return "HTTP/1.1 301 Moved Temporarily\r\n" + "Location: /infinite/redirect\r\n" + "\r\n"; + }); lt::aux::proxy_settings ps; ps.hostname = "127.0.0.1"; @@ -182,22 +268,21 @@ TORRENT_TEST(http_connection) ps.password = "testpass"; ps.type = settings_pack::none; - auto c1 = run_test(ios, res, "http://10.0.0.2:8080/non-existent", NULL, 0, 404, error_code() - , ps, &connect_handler_called, &handler_called); - ++expect_connect_handler_called; - ++expect_handler_called; - - auto c2 = run_test(ios, res, "http://10.0.0.2:8080/test_file", data_buffer, 1337, 200, error_code() - , ps, &connect_handler_called, &handler_called); - ++expect_connect_handler_called; - ++expect_handler_called; + auto c = test_request(ios, res, url, data_buffer, expect_size + , expect_status, expect_error, ps, &counters[connect_handler] + , &counters[handler]); error_code e; sim.run(e); if (e) std::cerr << " run failed: " << e.message() << std::endl; + TEST_EQUAL(e, error_code()); - TEST_EQUAL(connect_handler_called, expect_connect_handler_called); - TEST_EQUAL(handler_called, expect_handler_called); + TEST_EQUAL(counters.size(), expect_counters.size()); + for (int i = 0; i < counters.size(); ++i) + { + if (counters[i] != expect_counters[i]) fprintf(stderr, "i=%d\n", i); + TEST_EQUAL(counters[i], expect_counters[i]); + } }