From b4aad2a4815134d30a361fe468c9efb5953bdba4 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 3 Nov 2013 08:15:51 +0000 Subject: [PATCH] move web_server for unit tests over to python --- src/http_seed_connection.cpp | 2 +- test/http.py | 4 +- test/setup_transfer.cpp | 627 +++------------------------------- test/setup_transfer.hpp | 1 - test/socks.py | 6 +- test/test_http_connection.cpp | 2 +- test/test_privacy.cpp | 3 - test/test_tracker.cpp | 9 +- test/web_seed_suite.cpp | 16 +- test/web_seed_suite.hpp | 3 +- test/web_server.py | 145 ++++++++ 11 files changed, 204 insertions(+), 614 deletions(-) create mode 100644 test/web_server.py diff --git a/src/http_seed_connection.cpp b/src/http_seed_connection.cpp index 90d1a19b8..816237e63 100644 --- a/src/http_seed_connection.cpp +++ b/src/http_seed_connection.cpp @@ -116,7 +116,7 @@ namespace libtorrent int receive_buffer_size = receive_buffer().left() - m_parser.body_start(); // TODO: 1 in chunked encoding mode, this assert won't hold. // the chunk headers should be subtracted from the receive_buffer_size - TORRENT_ASSERT(receive_buffer_size <= t->block_size()); + TORRENT_ASSERT_VAL(receive_buffer_size <= t->block_size(), receive_buffer_size); ret.bytes_downloaded = t->block_size() - receive_buffer_size; } // this is used to make sure that the block_index stays within diff --git a/test/http.py b/test/http.py index 8dd055194..8bba4eb63 100644 --- a/test/http.py +++ b/test/http.py @@ -151,12 +151,12 @@ class ConnectionHandler: self.client.send(HTTPVER+' 200 Connection established\n'+ 'Proxy-agent: %s\n\n'%VERSION) self.client_buffer = '' - self._read_write() + self._read_write() def method_others(self): self.path = self.path[7:] i = self.path.find('/') - host = self.path[:i] + host = self.path[:i] path = self.path[i:] self._connect_target(host) self.target.send('%s %s %s\n'%(self.method, path, self.protocol)+ diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index 35e031e24..b6d316cbe 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -1,4 +1,4 @@ - /* +/* Copyright (c) 2008, Arvid Norberg All rights reserved. @@ -85,11 +85,6 @@ void report_failure(char const* err, char const* file, int line) int print_failures() { - for (std::vector::iterator i = failure_strings.begin() - , end(failure_strings.end()); i != end; ++i) - { - fputs(i->c_str(), stderr); - } fprintf(stderr, "\n\n\x1b[41m == %d TEST(S) FAILED ==\x1b[0m\n\n\n", tests_failure); return tests_failure; } @@ -380,20 +375,25 @@ pid_type async_run(char const* cmdline) #endif } +void stop_process(pid_type p) +{ +#ifdef _WIN32 + HANDLE proc = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, p); + TerminateProcess(proc, 138); + CloseHandle(proc); +#else + printf("killing pid: %d\n", p); + kill(p, SIGKILL); +#endif +} + void stop_all_proxies() { std::map proxies = running_proxies; for (std::map::iterator i = proxies.begin() , end(proxies.end()); i != end; ++i) { -#ifdef _WIN32 - HANDLE proc = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, i->second.pid); - TerminateProcess(proc, 138); - CloseHandle(proc); -#else - printf("killing pid: %d\n", i->second.pid); - kill(i->second.pid, SIGKILL); -#endif + stop_process(i->second.pid); running_proxies.erase(i->second.pid); } } @@ -449,7 +449,7 @@ int start_proxy(int proxy_type) fprintf(stderr, "%s starting proxy on port %d (%s %s)...\n", time_now_string(), port, type, auth); fprintf(stderr, "%s\n", buf); - int r = async_run(buf); + pid_type r = async_run(buf); if (r == 0) exit(1); proxy_t t = { r, proxy_type }; running_proxies.insert(std::make_pair(port, t)); @@ -790,7 +790,6 @@ int start_tracker() } boost::detail::atomic_count g_udp_tracker_requests(0); -boost::detail::atomic_count g_http_tracker_requests(0); void on_udp_receive(error_code const& ec, size_t bytes_transferred, udp::endpoint const* from, char* buffer, udp::socket* sock) { @@ -909,584 +908,34 @@ void udp_tracker_thread(int* port) } } -boost::asio::io_service* web_ios = 0; -boost::shared_ptr web_server; -libtorrent::mutex web_lock; -libtorrent::event web_initialized; -bool stop_thread = false; +pid_type web_server_pid = 0; -static void terminate_web_thread() +int start_web_server(bool ssl, bool chunked_encoding) { - stop_thread = true; - web_ios->stop(); - web_ios = 0; + unsigned int seed = total_microseconds(time_now_hires() - min_time()); + printf("random seed: %u\n", seed); + std::srand(seed); + int port = 5000 + (rand() % 55000); + + char buf[200]; + snprintf(buf, sizeof(buf), "python ../web_server.py %d %d %d" + , port, chunked_encoding , ssl); + + fprintf(stderr, "%s starting web_server on port %d...\n", time_now_string(), port); + + fprintf(stderr, "%s\n", buf); + pid_type r = async_run(buf); + if (r == 0) exit(1); + web_server_pid = r; + fprintf(stderr, "%s launched\n", time_now_string()); + test_sleep(500); + return port; } void stop_web_server() { - fprintf(stderr, "%s: stop_web_server()\n", time_now_string()); - if (web_server && web_ios) - { - fprintf(stderr, "%s: stopping web server thread\n", time_now_string()); - web_ios->post(&terminate_web_thread); - web_server->join(); - web_server.reset(); - } - remove("server.pem"); - fprintf(stderr, "%s: stop_web_server() done\n", time_now_string()); + if (web_server_pid == 0) return; + stop_process(web_server_pid); + web_server_pid = 0; } -void web_server_thread(int* port, bool ssl, bool chunked); - -int start_web_server(bool ssl, bool chunked_encoding) -{ - stop_web_server(); - - stop_thread = false; - - { - libtorrent::mutex::scoped_lock l(web_lock); - web_initialized.clear(l); - } - - int port = 0; - - web_server.reset(new libtorrent::thread(boost::bind( - &web_server_thread, &port, ssl, chunked_encoding))); - - { - libtorrent::mutex::scoped_lock l(web_lock); - web_initialized.wait(l); - } - - // create this directory so that the path - // "relative/../test_file" can resolve - error_code ec; - create_directory("relative", ec); -// test_sleep(100); - return port; -} - -void send_response(socket_type& s, error_code& ec - , int code, char const* status_message, char const** extra_header - , int len) -{ - char msg[600]; - int pkt_len = snprintf(msg, sizeof(msg), "HTTP/1.1 %d %s\r\n" - "content-length: %d\r\n" - "%s" - "%s" - "%s" - "%s" - "\r\n" - , code, status_message, len - , extra_header[0] - , extra_header[1] - , extra_header[2] - , extra_header[3]); - DLOG(stderr, ">> %s\n", msg); - write(s, boost::asio::buffer(msg, pkt_len), boost::asio::transfer_all(), ec); - if (ec) fprintf(stderr, "*** send failed: %s\n", ec.message().c_str()); -} - -void on_accept(error_code& accept_ec, error_code const& ec, bool* done) -{ - accept_ec = ec; - *done = true; -} - -void send_content(socket_type& s, char const* file, int size, bool chunked) -{ - error_code ec; - if (chunked) - { - int chunk_size = 13; - char head[20]; - std::vector bufs(3); - bufs[2] = asio::const_buffer("\r\n", 2); - while (chunk_size > 0) - { - chunk_size = std::min(chunk_size, size); - int len = snprintf(head, sizeof(head), "%x\r\n", chunk_size); - bufs[0] = asio::const_buffer(head, len); - if (chunk_size == 0) - { - // terminate - bufs.erase(bufs.begin()+1); - } - else - { - bufs[1] = asio::const_buffer(file, chunk_size); - } - write(s, bufs, boost::asio::transfer_all(), ec); - if (ec) fprintf(stderr, "*** send failed: %s\n", ec.message().c_str()); - size -= chunk_size; - file += chunk_size; - chunk_size *= 2; - } - } - else - { - write(s, boost::asio::buffer(file, size), boost::asio::transfer_all(), ec); -// DLOG(stderr, " >> %s\n", std::string(file, size).c_str()); - if (ec) fprintf(stderr, "*** send failed: %s\n", ec.message().c_str()); - } -} - -void on_read(error_code const& ec, size_t bytes_transferred, size_t* bt, error_code* e, bool* done) -{ - DLOG(stderr, "on_read %d [ ec: %s ]\n", int(bytes_transferred), ec.message().c_str()); - *bt = bytes_transferred; - *e = ec; - *done = true; -} - -void on_read_timeout(error_code const& ec, bool* timed_out) -{ - if (ec) return; - fprintf(stderr, "read timed out\n"); - *timed_out = true; -} - -void web_server_thread(int* port, bool ssl, bool chunked) -{ - io_service ios; - socket_acceptor acceptor(ios); - error_code ec; - acceptor.open(tcp::v4(), ec); - if (ec) - { - fprintf(stderr, "Error opening listen socket: %s\n", ec.message().c_str()); - libtorrent::mutex::scoped_lock l(web_lock); - web_initialized.signal(l); - return; - } - acceptor.set_option(socket_acceptor::reuse_address(true), ec); - if (ec) - { - fprintf(stderr, "Error setting listen socket to reuse addr: %s\n", ec.message().c_str()); - libtorrent::mutex::scoped_lock l(web_lock); - web_initialized.signal(l); - return; - } - acceptor.bind(tcp::endpoint(address_v4::any(), 0), ec); - if (ec) - { - fprintf(stderr, "Error binding listen socket to port 0: %s\n", ec.message().c_str()); - libtorrent::mutex::scoped_lock l(web_lock); - web_initialized.signal(l); - return; - } - *port = acceptor.local_endpoint().port(); - acceptor.listen(10, ec); - if (ec) - { - fprintf(stderr, "Error listening on socket: %s\n", ec.message().c_str()); - libtorrent::mutex::scoped_lock l(web_lock); - web_initialized.signal(l); - return; - } - - web_ios = &ios; - - char buf[10000]; - int len = 0; - int offset = 0; - bool connection_close = false; - socket_type s(ios); - void* ctx = 0; -#ifdef TORRENT_USE_OPENSSL - boost::asio::ssl::context ssl_ctx(ios, boost::asio::ssl::context::sslv23_server); - if (ssl) - { - ssl_ctx.use_certificate_chain_file("../ssl/server.pem"); - ssl_ctx.use_private_key_file("../ssl/server.pem", asio::ssl::context::pem); - ssl_ctx.set_verify_mode(boost::asio::ssl::context::verify_none); - - ctx = &ssl_ctx; - } -#endif - - proxy_settings p; - instantiate_connection(ios, p, s, ctx); - - fprintf(stderr, "web server initialized on port %d%s\n", *port, ssl ? " [SSL]" : ""); - - { - libtorrent::mutex::scoped_lock l(web_lock); - web_initialized.signal(l); - } - - for (;;) - { - if (connection_close) - { - error_code ec; -#ifdef TORRENT_USE_OPENSSL - if (ssl) - { - DLOG(stderr, "shutting down SSL connection\n"); - s.get >()->shutdown(ec); - if (ec) fprintf(stderr, "SSL shutdown failed: %s\n", ec.message().c_str()); - ec.clear(); - } -#endif - DLOG(stderr, "closing connection\n"); - s.close(ec); - if (ec) fprintf(stderr, "close failed: %s\n", ec.message().c_str()); - connection_close = false; - } - - if (!s.is_open()) - { - len = 0; - offset = 0; - - error_code ec; - instantiate_connection(ios, p, s, ctx); - stream_socket* sock; -#ifdef TORRENT_USE_OPENSSL - if (ssl) sock = &s.get >()->next_layer(); - else -#endif - sock = s.get(); - - bool accept_done = false; - fprintf(stderr, "HTTP waiting for incoming connection\n"); - acceptor.async_accept(*sock, boost::bind(&on_accept, boost::ref(ec), _1, &accept_done)); - while (!accept_done) - { - error_code e; - ios.reset(); - if (stop_thread || ios.run_one(e) == 0) - { - fprintf(stderr, "%s: io_service stopped: %s\n", time_now_string(), e.message().c_str()); - break; - } - } - if (stop_thread) break; - - if (ec) - { - fprintf(stderr, "%s: accept failed: %s\n", time_now_string(), ec.message().c_str()); - return; - } - fprintf(stderr, "%s: accepting incoming connection\n", time_now_string()); - if (!s.is_open()) - { - fprintf(stderr, "%s: incoming connection closed\n", time_now_string()); - continue; - } - -#ifdef TORRENT_USE_OPENSSL - if (ssl) - { - DLOG(stderr, "%s: SSL handshake\n", time_now_string()); - s.get >()->accept_handshake(ec); - if (ec) - { - fprintf(stderr, "SSL handshake failed: %s\n", ec.message().c_str()); - connection_close = true; - continue; - } - } -#endif - - } - - http_parser p; - bool failed = false; - - do - { - p.reset(); - bool error = false; - - p.incoming(buffer::const_interval(buf + offset, buf + len), error); - - char const* extra_header[4] = {"","","",""}; - - TEST_CHECK(error == false); - if (error) - { - fprintf(stderr, "HTTP parse failed\n"); - failed = true; - break; - } - - while (!p.finished()) - { - TORRENT_ASSERT(len <= int(sizeof(buf))); - size_t received = 0; - bool done = false; - bool timed_out = false; - DLOG(stderr, "async_read_some %d bytes [ len: %d ]\n", int(sizeof(buf) - len), len); - s.async_read_some(boost::asio::buffer(&buf[len] - , sizeof(buf) - len), boost::bind(&on_read, _1, _2, &received, &ec, &done)); - deadline_timer timer(ios); - timer.expires_at(time_now_hires() + seconds(2)); - timer.async_wait(boost::bind(&on_read_timeout, _1, &timed_out)); - - while (!done && !timed_out) - { - error_code e; - ios.reset(); - if (stop_thread || ios.run_one(e) == 0) - { - fprintf(stderr, "HTTP io_service stopped: %s\n", e.message().c_str()); - break; - } - } - if (timed_out) - { - fprintf(stderr, "HTTP read timed out, closing connection\n"); - failed = true; - break; - } -// fprintf(stderr, "read: %d\n", int(received)); - - if (ec || received <= 0) - { - fprintf(stderr, "HTTP read failed: \"%s\" (%s) received: %d\n" - , ec.message().c_str(), ec.category().name(), int(received)); - failed = true; - break; - } - - timer.cancel(ec); - if (ec) - fprintf(stderr, "HTTP timer.cancel failed: %s\n", ec.message().c_str()); - - len += received; - - p.incoming(buffer::const_interval(buf + offset, buf + len), error); - - TEST_CHECK(error == false); - if (error) - { - fprintf(stderr, "HTTP parse failed\n"); - failed = true; - break; - } - } - - std::string connection = p.header("connection"); - std::string via = p.header("via"); - - if (p.protocol() == "HTTP/1.0") - { - DLOG(stderr, "*** HTTP/1.0, closing connection when done\n"); - connection_close = true; - } - - DLOG(stderr, "REQ: %s", std::string(buf + offset, p.body_start()).c_str()); - - if (failed) - { - fprintf(stderr, "*** connection failed\n"); - connection_close = true; - break; - } - - offset += int(p.body_start() + p.content_length()); -// fprintf(stderr, "offset: %d len: %d\n", offset, len); - - if (p.method() != "get" && p.method() != "post") - { - fprintf(stderr, "*** incorrect method: %s\n", p.method().c_str()); - connection_close = true; - break; - } - - std::string path = p.path(); - - std::vector file_buf; - if (path.substr(0, 4) == "http") - { - // remove the http://hostname and the first / of the path - path = path.substr(path.find("://")+3); - path = path.substr(path.find_first_of('/')+1); - } - else - { - // remove the / from the path - path = path.substr(1); - } - -// fprintf(stderr, "%s: [HTTP] %s\n", time_now_string(), path.c_str()); - - if (path == "redirect") - { - extra_header[0] = "Location: /test_file\r\n"; - send_response(s, ec, 301, "Moved Permanently", extra_header, 0); - break; - } - - if (path == "infinite_redirect") - { - extra_header[0] = "Location: /infinite_redirect\r\n"; - send_response(s, ec, 301, "Moved Permanently", extra_header, 0); - break; - } - - if (path == "relative/redirect") - { - extra_header[0] = "Location: ../test_file\r\n"; - send_response(s, ec, 301, "Moved Permanently", extra_header, 0); - break; - } - - if (path.substr(0, 8) == "announce") - { - fprintf(stderr, "%s\n", path.c_str()); - entry announce; - announce["interval"] = 1800; - announce["complete"] = 1; - announce["incomplete"] = 1; - announce["peers"].string(); - std::vector buf; - bencode(std::back_inserter(buf), announce); - ++g_http_tracker_requests; - fprintf(stderr, "[HTTP]: announce [%d]\n", int(g_http_tracker_requests)); - - send_response(s, ec, 200, "OK", extra_header, buf.size()); - write(s, boost::asio::buffer(&buf[0], buf.size()), boost::asio::transfer_all(), ec); - if (ec) - fprintf(stderr, "[HTTP] *** send response failed: %s\n", ec.message().c_str()); - continue; - } - - if (filename(path).substr(0, 5) == "seed?") - { - char const* piece = strstr(path.c_str(), "&piece="); - if (piece == 0) piece = strstr(path.c_str(), "?piece="); - if (piece == 0) - { - fprintf(stderr, "invalid web seed request: %s\n", path.c_str()); - break; - } - boost::uint64_t idx = atoi(piece + 7); - char const* range = strstr(path.c_str(), "&ranges="); - if (range == 0) range = strstr(path.c_str(), "?ranges="); - int range_end = 0; - int range_start = 0; - if (range) - { - range_start = atoi(range + 8); - range = strchr(range, '-'); - if (range == 0) - { - fprintf(stderr, "invalid web seed request: %s\n", path.c_str()); - break; - } - range_end = atoi(range + 1); - } - else - { - range_start = 0; - // assume piece size of 64kiB - range_end = 64*1024+1; - } - - int size = range_end - range_start + 1; - boost::uint64_t off = idx * 64 * 1024 + range_start; - std::vector file_buf; - error_code ec; - std::string file_path = path.substr(0, path.find_first_of('?')); - int res = load_file(file_path.c_str(), file_buf, ec); - - if (res == -1 || file_buf.empty()) - { - fprintf(stderr, "file not found: %s\n", file_path.c_str()); - send_response(s, ec, 404, "Not Found", extra_header, 0); - continue; - } - send_response(s, ec, 200, "OK", extra_header, size); - DLOG(stderr, "sending %d bytes of payload [%d, %d) piece: %d\n" - , size, int(off), int(off + size), int(idx)); - write(s, boost::asio::buffer(&file_buf[0] + off, size) - , boost::asio::transfer_all(), ec); - if (ec) - fprintf(stderr, "*** send failed: %s\n", ec.message().c_str()); - else - { - DLOG(stderr, "*** done\n"); - } - - memmove(buf, buf + offset, len - offset); - len -= offset; - offset = 0; - continue; - } - - DLOG(stderr, ">> serving file %s\n", path.c_str()); - error_code ec; - int res = load_file(path, file_buf, ec, 8000000); - if (res == -1) - { - fprintf(stderr, ">> file not found: %s\n", path.c_str()); - send_response(s, ec, 404, "Not Found", extra_header, 0); - continue; - } - - if (res != 0) - { - // this means the file was either too big or couldn't be read - fprintf(stderr, ">> file too big: %s\n", path.c_str()); - send_response(s, ec, 503, "Internal Error", extra_header, 0); - continue; - } - - // serve file - - if (extension(path) == ".gz") - { - extra_header[0] = "Content-Encoding: gzip\r\n"; - } - - if (chunked) - { - extra_header[2] = "Transfer-Encoding: chunked\r\n"; - } - - if (!p.header("range").empty()) - { - std::string range = p.header("range"); - int start, end; - sscanf(range.c_str(), "bytes=%d-%d", &start, &end); - char eh[400]; - snprintf(eh, sizeof(eh), "Content-Range: bytes %d-%d\r\n", start, end); - extra_header[1] = eh; - if (end - start + 1 >= 1000) - { - DLOG(stderr, "request size: %.2f kB\n", int(end - start + 1)/1000.f); - } - else - { - DLOG(stderr, "request size: %d Bytes\n", int(end - start + 1)); - } - send_response(s, ec, 206, "Partial", extra_header, end - start + 1); - if (!file_buf.empty()) - { - send_content(s, &file_buf[0] + start, end - start + 1, chunked); - } - DLOG(stderr, "send %d bytes of payload\n", end - start + 1); - } - else - { - send_response(s, ec, 200, "OK", extra_header, file_buf.size()); - if (!file_buf.empty()) - send_content(s, &file_buf[0], file_buf.size(), chunked); - } - DLOG(stderr, "%d bytes left in receive buffer. offset: %d\n", len - offset, offset); - memmove(buf, buf + offset, len - offset); - len -= offset; - offset = 0; - } while (offset < len); - } - - web_ios = 0; - fprintf(stderr, "%s: exiting web server thread\n", time_now_string()); -} - - diff --git a/test/setup_transfer.hpp b/test/setup_transfer.hpp index 949917445..6af5c4cfe 100644 --- a/test/setup_transfer.hpp +++ b/test/setup_transfer.hpp @@ -69,7 +69,6 @@ void EXPORT wait_for_listen(libtorrent::session& ses, char const* name); void EXPORT test_sleep(int millisec); extern EXPORT boost::detail::atomic_count g_udp_tracker_requests; -extern EXPORT boost::detail::atomic_count g_http_tracker_requests; void EXPORT create_random_files(std::string const& path, const int file_sizes[], int num_files); diff --git a/test/socks.py b/test/socks.py index bac4b85b9..a022bf863 100644 --- a/test/socks.py +++ b/test/socks.py @@ -186,7 +186,11 @@ class SocksHandler(StreamRequestHandler): outbound_sock = socket.socket(socket.AF_INET6) else: outbound_sock = socket.socket(socket.AF_INET) - out_address = socket.getaddrinfo(dest_address,dest_port)[0][4] + try: + out_address = socket.getaddrinfo(dest_address,dest_port)[0][4] + except Exception, e: + print e + return debug("Creating forwarder connection to %r", out_address) outbound_sock.connect(out_address) diff --git a/test/test_http_connection.cpp b/test/test_http_connection.cpp index a72ddd94e..9ab21997c 100644 --- a/test/test_http_connection.cpp +++ b/test/test_http_connection.cpp @@ -159,7 +159,7 @@ void run_suite(std::string const& protocol, proxy_settings ps, int port) run_test(url_base + "relative/redirect", 3216, 200, 2, error_code(), ps); run_test(url_base + "redirect", 3216, 200, 2, error_code(), ps); - run_test(url_base + "infinite_redirect", 0, 301, 6, error_code(), ps); + run_test(url_base + "infinite_redirect", 0, 301, 6, error_code(asio::error::eof), ps); run_test(url_base + "test_file", 3216, 200, 1, error_code(), ps); run_test(url_base + "test_file.gz", 3216, 200, 1, error_code(), ps); run_test(url_base + "non-existing-file", -1, 404, 1, err(), ps); diff --git a/test/test_privacy.cpp b/test/test_privacy.cpp index 58e22ff12..46b66f242 100644 --- a/test/test_privacy.cpp +++ b/test/test_privacy.cpp @@ -88,7 +88,6 @@ session_proxy test_proxy(proxy_settings::proxy_type proxy_type, int flags) int peer_port = start_peer(); int prev_udp_announces = g_udp_tracker_requests; - int prev_http_announces = g_http_tracker_requests; int const alert_mask = alert::all_categories & ~alert::progress_notification @@ -161,14 +160,12 @@ session_proxy test_proxy(proxy_settings::proxy_type proxy_type, int flags) test_sleep(100); if (g_udp_tracker_requests >= prev_udp_announces + 1 - && g_http_tracker_requests >= prev_http_announces + 1 && num_peer_hits() > 0) break; } // we should have announced to the tracker by now TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + bool(flags & expect_udp_connection)); - TEST_EQUAL(g_http_tracker_requests, prev_http_announces + bool(flags & expect_http_connection)); if (flags & expect_dht_msg) { TEST_CHECK(num_dht_hits() > 0); diff --git a/test/test_tracker.cpp b/test/test_tracker.cpp index b21233db2..ba0404827 100644 --- a/test/test_tracker.cpp +++ b/test/test_tracker.cpp @@ -46,7 +46,6 @@ int test_main() int udp_port = start_tracker(); int prev_udp_announces = g_udp_tracker_requests; - int prev_http_announces = g_http_tracker_requests; int const alert_mask = alert::all_categories & ~alert::progress_notification @@ -84,15 +83,12 @@ int test_main() { print_alerts(*s, "s"); test_sleep(100); -// fprintf(stderr, "udp_announces: %d http_announces: %d\n", int(g_udp_tracker_requests), int(g_http_tracker_requests)); - if (g_udp_tracker_requests == prev_udp_announces + 1 - && g_http_tracker_requests == prev_http_announces + 1) + if (g_udp_tracker_requests == prev_udp_announces + 1) break; } // we should have announced to the tracker by now TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + 1); - TEST_EQUAL(g_http_tracker_requests, prev_http_announces + 1); fprintf(stderr, "destructing session\n"); delete s; @@ -100,7 +96,6 @@ int test_main() // we should have announced the stopped event now TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + 2); - TEST_EQUAL(g_http_tracker_requests, prev_http_announces + 2); // ======================================== // test that we move on to try the next tier if the first one fails @@ -139,7 +134,6 @@ int test_main() t->add_tracker(tracker_url, 3); prev_udp_announces = g_udp_tracker_requests; - prev_http_announces = g_http_tracker_requests; addp.flags &= ~add_torrent_params::flag_paused; addp.flags &= ~add_torrent_params::flag_auto_managed; @@ -157,7 +151,6 @@ int test_main() test_sleep(1000); TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + 1); - TEST_EQUAL(g_http_tracker_requests, prev_http_announces); fprintf(stderr, "destructing session\n"); delete s; diff --git a/test/web_seed_suite.cpp b/test/web_seed_suite.cpp index e852aabdb..67b530884 100644 --- a/test/web_seed_suite.cpp +++ b/test/web_seed_suite.cpp @@ -175,6 +175,7 @@ static void test_transfer(session& ses, boost::intrusive_ptr torre { TEST_EQUAL(cs.cache_size, 0); TEST_EQUAL(cs.total_used_buffers, 0); + TEST_EQUAL(th.status().is_seeding, true); } std::cerr << "total_size: " << total_size @@ -213,11 +214,11 @@ int EXPORT run_http_suite(int proxy, char const* protocol, bool test_url_seed, b { using namespace libtorrent; - std::string save_path = "tmp1_web_seed"; + std::string save_path = "web_seed"; save_path += proxy_name[proxy]; error_code ec; - create_directories(combine_path(save_path, "test_torrent_dir"), ec); + create_directories(combine_path(save_path, "torrent_dir"), ec); if (ec) { fprintf(stderr, "FAILED TO CREATE DIRECTORY: (%d) %s\n" @@ -235,15 +236,16 @@ int EXPORT run_http_suite(int proxy, char const* protocol, bool test_url_seed, b if (test_url_seed) { - create_random_files(combine_path(save_path, "test_torrent_dir"), file_sizes, sizeof(file_sizes)/sizeof(file_sizes[0])); - add_files(fs, combine_path(save_path, "test_torrent_dir")); + create_random_files(combine_path(save_path, "torrent_dir"), file_sizes, sizeof(file_sizes)/sizeof(file_sizes[0])); + add_files(fs, combine_path(save_path, "torrent_dir")); } else { piece_size = 64 * 1024; char* random_data = (char*)malloc(64 * 1024 * num_pieces); std::generate(random_data, random_data + 64 * 1024 * num_pieces, &std::rand); - save_file(combine_path(save_path, "seed").c_str(), random_data, 64 * 1024 * num_pieces); + std::string seed_filename = combine_path(save_path, "seed"); + save_file(seed_filename.c_str(), random_data, 64 * 1024 * num_pieces); fs.add_file("seed", 64 * 1024 * num_pieces); free(random_data); } @@ -290,7 +292,7 @@ int EXPORT run_http_suite(int proxy, char const* protocol, bool test_url_seed, b // corrupt the files now, so that the web seed will be banned if (test_url_seed) { - create_random_files(combine_path(save_path, "test_torrent_dir"), file_sizes, sizeof(file_sizes)/sizeof(file_sizes[0])); + create_random_files(combine_path(save_path, "torrent_dir"), file_sizes, sizeof(file_sizes)/sizeof(file_sizes[0])); } else { @@ -336,7 +338,7 @@ int EXPORT run_http_suite(int proxy, char const* protocol, bool test_url_seed, b if (test_url_seed) { - torrent_file->rename_file(0, combine_path(save_path, "test_torrent_dir/renamed_test1")); + torrent_file->rename_file(0, combine_path(save_path, combine_path("torrent_dir", "renamed_test1"))); test_transfer(ses, torrent_file, 0, port, protocol, test_url_seed, chunked_encoding, test_ban); } } diff --git a/test/web_seed_suite.hpp b/test/web_seed_suite.hpp index d539c2a5b..405ee8c76 100644 --- a/test/web_seed_suite.hpp +++ b/test/web_seed_suite.hpp @@ -31,5 +31,6 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "test.hpp" -int EXPORT run_http_suite(int proxy, char const* protocol, bool test_url_seed, bool chunked_encoding, bool test_ban); +int EXPORT run_http_suite(int proxy, char const* protocol + , bool test_url_seed, bool chunked_encoding, bool test_ban); diff --git a/test/web_server.py b/test/web_server.py new file mode 100644 index 000000000..47dab4ed2 --- /dev/null +++ b/test/web_server.py @@ -0,0 +1,145 @@ +import BaseHTTPServer +import SimpleHTTPServer +import sys +import os +import ssl + +chunked_encoding = False + +class http_handler(SimpleHTTPServer.SimpleHTTPRequestHandler): + + def do_GET(s): + + #print s.requestline + global chunked_encoding + + # if the request contains the hostname and port. strip it + if s.path.startswith('http://') or s.path.startswith('https://'): + s.path = s.path[8:] + s.path = s.path[s.path.find('/'):] + + s.path = os.path.normpath(s.path) + + if s.path == '/redirect': + s.send_response(301) + s.send_header("Location", "/test_file") + s.send_header("Connection", "close") + s.end_headers() + s.finish() + elif s.path == '/infinite_redirect': + s.send_response(301) + s.send_header("Location", "/infinite_redirect") + s.send_header("Connection", "close") + s.end_headers() + s.finish() + elif s.path == '/relative/redirect': + s.send_response(301) + s.send_header("Location", "../test_file") + s.send_header("Connection", "close") + s.end_headers() + s.finish() + elif s.path.startswith('/announce'): + s.send_response(200) + response = 'd8:intervali1800e8:completei1e10:incompletei1e5:peers0:e' + s.send_header("Content-Length", "%d" % len(response)) + s.send_header("Connection", "close") + s.end_headers() + s.wfile.write(response) + s.finish() + elif os.path.split(s.path)[1].startswith('seed?'): + query = s.path[6:] + args_raw = query.split('&') + args = {} + for a in args_raw: + kvp = a.split('=') + args[kvp[0]] = kvp[1] + piece = int(args['piece']) + ranges = args['ranges'].split('-') + + try: + filename = s.path[1:s.path.find('seed?') + 4] + #print 'filename = %s' % filename + f = open(filename, 'rb') + f.seek(piece * 64 * 1024 + int(ranges[0])) + data = f.read(int(ranges[1]) - int(ranges[0]) + 1) + f.close() + + s.send_response(200) + print 'sending %d bytes' % len(data) + s.send_header("Content-Length", "%d" % len(data)) + s.end_headers() + s.wfile.write(data); + except Exception, e: + print 'FILE NOT FOUND: ', e + s.send_response(404) + s.send_header("Content-Length", "0") + s.end_headers() + else: + try: + filename = s.path[1:] + # serve file by invoking default handler + f = open(filename) + size = int(os.stat(filename).st_size) + start_range = 0 + end_range = size + if 'Range' in s.headers: + s.send_response(206) + s.send_header('Content-Range', 'bytes ' + str(start_range) + '-' + str(end_range - 1) + '/' + str(size)) + st, e = s.headers['range'][6:].split('-', 1) + sl = len(st) + el = len(e) + if sl > 0: + start_range = int(st) + if el > 0: + end_range = int(e) + 1 + elif el > 0: + ei = int(e) + if ei < size: + start_range = size - ei + else: + s.send_response(200) + s.send_header('Accept-Ranges', 'bytes') + if chunked_encoding: + s.send_header('Transfer-Encoding', 'chunked') + s.send_header('Content-Length', end_range - start_range) + if filename.endswith('.gz'): + s.send_header('Content-Encoding', 'gzip') + s.end_headers() + + f.seek(start_range) + length = end_range - start_range + while length > 0: + to_send = min(length, 0x900) + if chunked_encoding: + s.wfile.write('%x\r\n' % to_send) + data = f.read(to_send) + s.wfile.write(data) + if chunked_encoding: + s.wfile.write('\r\n') + length -= to_send + if chunked_encoding: + s.wfile.write('0\r\n\r\n') + except Exception, e: + print 'FILE NOT FOUND: ', e + s.send_response(404) + s.send_header("Content-Length", "0") + s.end_headers() + + +if __name__ == '__main__': + port = int(sys.argv[1]) + chunked_encoding = sys.argv[2] != '0' + ssl = sys.argv[3] != '0' + + # TODO: SSL support + http_handler.protocol_version = 'HTTP/1.1' + httpd = BaseHTTPServer.HTTPServer(('127.0.0.1', port), http_handler) + if ssl: + httpd.socket = ssl.wrap_socket(httpd.socket, certfile='../ssl/server.pem', server_side=True) + + try: + httpd.serve_forever() + except KeyboardInterrupt: + pass + httpd.server_close() +