From dd192cfd3c2486b926d2fa4a1dcfed068c97040c Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 1 Sep 2013 01:10:50 +0000 Subject: [PATCH] split up test_primitives into more tests (in an attempt to get the link-time down within the regression test time limit) --- CMakeLists.txt | 3 + include/libtorrent/xml_parse.hpp | 1 + test/Jamfile | 3 + test/Makefile.am | 3 + test/test_dht.cpp | 351 +++++++++ test/test_file.cpp | 126 +++ test/test_http_parser.cpp | 306 ++++++++ test/test_primitives.cpp | 1221 +----------------------------- test/test_string.cpp | 212 ++++++ test/test_xml.cpp | 351 +++++++++ 10 files changed, 1361 insertions(+), 1216 deletions(-) create mode 100644 test/test_http_parser.cpp create mode 100644 test/test_string.cpp create mode 100644 test/test_xml.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 31454773e..280de15ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -323,7 +323,10 @@ if(build_tests) test_peer_priority test_bencoding test_bdecode_performance + test_xml + test_string test_primitives + test_http_parser test_ip_filter test_hasher test_metadata_extension diff --git a/include/libtorrent/xml_parse.hpp b/include/libtorrent/xml_parse.hpp index 63f81c2e4..25273ce81 100644 --- a/include/libtorrent/xml_parse.hpp +++ b/include/libtorrent/xml_parse.hpp @@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include "libtorrent/assert.hpp" #include "libtorrent/escape_string.hpp" namespace libtorrent diff --git a/test/Jamfile b/test/Jamfile index 261266e8a..c51fb4bfa 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -70,6 +70,9 @@ test-suite libtorrent : [ run test_bencoding.cpp ] [ run test_fast_extension.cpp ] [ run test_primitives.cpp ] + [ run test_http_parser.cpp ] + [ run test_string.cpp ] + [ run test_xml.cpp ] [ run test_ip_filter.cpp ] [ run test_hasher.cpp ] [ run test_dht.cpp ] diff --git a/test/Makefile.am b/test/Makefile.am index 7cc5a58e9..0bb3d804d 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -19,7 +19,10 @@ test_programs = \ test_peer_priority \ test_pex \ test_piece_picker \ + test_xml \ + test_string \ test_primitives \ + test_http_parser \ test_rss \ test_storage \ test_swarm \ diff --git a/test/test_dht.cpp b/test/test_dht.cpp index 486a273b7..143061c7d 100644 --- a/test/test_dht.cpp +++ b/test/test_dht.cpp @@ -38,6 +38,9 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket_io.hpp" // for hash_address #include "libtorrent/broadcast_socket.hpp" // for supports_ipv6 #include "libtorrent/alert_dispatcher.hpp" + +#include "libtorrent/kademlia/node_id.hpp" +#include "libtorrent/kademlia/routing_table.hpp" #include #include "test.hpp" @@ -46,6 +49,33 @@ POSSIBILITY OF SUCH DAMAGE. using namespace libtorrent; using namespace libtorrent::dht; +sha1_hash to_hash(char const* s) +{ + sha1_hash ret; + from_hex(s, 40, (char*)&ret[0]); + return ret; +} + +void add_and_replace(libtorrent::dht::node_id& dst, libtorrent::dht::node_id const& add) +{ + bool carry = false; + for (int k = 19; k >= 0; --k) + { + int sum = dst[k] + add[k] + (carry?1:0); + dst[k] = sum & 255; + carry = sum > 255; + } +} + +void node_push_back(void* userdata, libtorrent::dht::node_entry const& n) +{ + using namespace libtorrent::dht; + std::vector* nv = (std::vector*)userdata; + nv->push_back(n); +} + +void nop(void* userdata, libtorrent::dht::node_entry const& n) {} + std::list > g_responses; struct mock_socket : udp_socket_interface @@ -651,6 +681,327 @@ int test_main() #endif } + // test verify_message + const static key_desc_t msg_desc[] = { + {"A", lazy_entry::string_t, 4, 0}, + {"B", lazy_entry::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children}, + {"B1", lazy_entry::string_t, 0, 0}, + {"B2", lazy_entry::string_t, 0, key_desc_t::last_child}, + {"C", lazy_entry::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children}, + {"C1", lazy_entry::string_t, 0, 0}, + {"C2", lazy_entry::string_t, 0, key_desc_t::last_child}, + }; + + lazy_entry const* msg_keys[7]; + + lazy_entry ent; + + error_code ec; + char const test_msg[] = "d1:A4:test1:Bd2:B15:test22:B25:test3ee"; + lazy_bdecode(test_msg, test_msg + sizeof(test_msg)-1, ent, ec); + fprintf(stderr, "%s\n", print_entry(ent).c_str()); + + ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); + TEST_CHECK(ret); + TEST_CHECK(msg_keys[0]); + if (msg_keys[0]) TEST_EQUAL(msg_keys[0]->string_value(), "test"); + TEST_CHECK(msg_keys[1]); + TEST_CHECK(msg_keys[2]); + if (msg_keys[2]) TEST_EQUAL(msg_keys[2]->string_value(), "test2"); + TEST_CHECK(msg_keys[3]); + if (msg_keys[3]) TEST_EQUAL(msg_keys[3]->string_value(), "test3"); + TEST_CHECK(msg_keys[4] == 0); + TEST_CHECK(msg_keys[5] == 0); + TEST_CHECK(msg_keys[6] == 0); + + char const test_msg2[] = "d1:A4:test1:Cd2:C15:test22:C25:test3ee"; + lazy_bdecode(test_msg2, test_msg2 + sizeof(test_msg2)-1, ent, ec); + fprintf(stderr, "%s\n", print_entry(ent).c_str()); + + ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); + TEST_CHECK(ret); + TEST_CHECK(msg_keys[0]); + if (msg_keys[0]) TEST_EQUAL(msg_keys[0]->string_value(), "test"); + TEST_CHECK(msg_keys[1] == 0); + TEST_CHECK(msg_keys[2] == 0); + TEST_CHECK(msg_keys[3] == 0); + TEST_CHECK(msg_keys[4]); + TEST_CHECK(msg_keys[5]); + if (msg_keys[5]) TEST_EQUAL(msg_keys[5]->string_value(), "test2"); + TEST_CHECK(msg_keys[6]); + if (msg_keys[6]) TEST_EQUAL(msg_keys[6]->string_value(), "test3"); + + + char const test_msg3[] = "d1:Cd2:C15:test22:C25:test3ee"; + lazy_bdecode(test_msg3, test_msg3 + sizeof(test_msg3)-1, ent, ec); + fprintf(stderr, "%s\n", print_entry(ent).c_str()); + + ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); + TEST_CHECK(!ret); + fprintf(stderr, "%s\n", error_string); + TEST_EQUAL(error_string, std::string("missing 'A' key")); + + char const test_msg4[] = "d1:A6:foobare"; + lazy_bdecode(test_msg4, test_msg4 + sizeof(test_msg4)-1, ent, ec); + fprintf(stderr, "%s\n", print_entry(ent).c_str()); + + ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); + TEST_CHECK(!ret); + fprintf(stderr, "%s\n", error_string); + TEST_EQUAL(error_string, std::string("invalid value for 'A'")); + + char const test_msg5[] = "d1:A4:test1:Cd2:C15:test2ee"; + lazy_bdecode(test_msg5, test_msg5 + sizeof(test_msg5)-1, ent, ec); + fprintf(stderr, "%s\n", print_entry(ent).c_str()); + + ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); + TEST_CHECK(!ret); + fprintf(stderr, "%s\n", error_string); + TEST_EQUAL(error_string, std::string("missing 'C2' key")); + + // test empty strings [ { "":1 }, "" ] + char const test_msg6[] = "ld0:i1ee0:e"; + lazy_bdecode(test_msg6, test_msg6 + sizeof(test_msg6)-1, ent, ec); + fprintf(stderr, "%s\n", print_entry(ent).c_str()); + TEST_CHECK(ent.type() == lazy_entry::list_t); + if (ent.type() == lazy_entry::list_t) + { + TEST_CHECK(ent.list_size() == 2); + if (ent.list_size() == 2) + { + TEST_CHECK(ent.list_at(0)->dict_find_int_value("") == 1); + TEST_CHECK(ent.list_at(1)->string_value() == ""); + } + } + + // test kademlia functions + + using namespace libtorrent::dht; + + for (int i = 0; i < 160; i += 8) + { + for (int j = 0; j < 160; j += 8) + { + node_id a(0); + a[(159-i) / 8] = 1 << (i & 7); + node_id b(0); + b[(159-j) / 8] = 1 << (j & 7); + int dist = distance_exp(a, b); + + TEST_CHECK(dist >= 0 && dist < 160); + TEST_CHECK(dist == ((i == j)?0:(std::max)(i, j))); + + for (int k = 0; k < 160; k += 8) + { + node_id c(0); + c[(159-k) / 8] = 1 << (k & 7); + + bool cmp = compare_ref(a, b, c); + TEST_CHECK(cmp == (distance(a, c) < distance(b, c))); + } + } + } + + { + // test kademlia routing table + dht_settings s; + // s.restrict_routing_ips = false; + node_id id = to_hash("3123456789abcdef01232456789abcdef0123456"); + dht::routing_table table(id, 10, s); + std::vector nodes; + TEST_EQUAL(table.size().get<0>(), 0); + + node_id tmp = id; + node_id diff = to_hash("15764f7459456a9453f8719b09547c11d5f34061"); + + // test a node with the same IP:port changing ID + add_and_replace(tmp, diff); + table.node_seen(tmp, udp::endpoint(address::from_string("4.4.4.4"), 4), 10); + table.find_node(id, nodes, 0, 10); + TEST_EQUAL(table.bucket_size(0), 1); + TEST_EQUAL(table.size().get<0>(), 1); + TEST_EQUAL(nodes.size(), 1); + if (!nodes.empty()) + { + TEST_EQUAL(nodes[0].id, tmp); + TEST_EQUAL(nodes[0].addr(), address_v4::from_string("4.4.4.4")); + TEST_EQUAL(nodes[0].port(), 4); + TEST_EQUAL(nodes[0].timeout_count, 0); + } + + // set timeout_count to 1 + table.node_failed(tmp, udp::endpoint(address_v4::from_string("4.4.4.4"), 4)); + + nodes.clear(); + table.for_each_node(node_push_back, nop, &nodes); + TEST_EQUAL(nodes.size(), 1); + if (!nodes.empty()) + { + TEST_EQUAL(nodes[0].id, tmp); + TEST_EQUAL(nodes[0].addr(), address_v4::from_string("4.4.4.4")); + TEST_EQUAL(nodes[0].port(), 4); + TEST_EQUAL(nodes[0].timeout_count, 1); + } + + // add the exact same node again, it should set the timeout_count to 0 + table.node_seen(tmp, udp::endpoint(address::from_string("4.4.4.4"), 4), 10); + nodes.clear(); + table.for_each_node(node_push_back, nop, &nodes); + TEST_EQUAL(nodes.size(), 1); + if (!nodes.empty()) + { + TEST_EQUAL(nodes[0].id, tmp); + TEST_EQUAL(nodes[0].addr(), address_v4::from_string("4.4.4.4")); + TEST_EQUAL(nodes[0].port(), 4); + TEST_EQUAL(nodes[0].timeout_count, 0); + } + + // test adding the same IP:port again with a new node ID (should replace the old one) + add_and_replace(tmp, diff); + table.node_seen(tmp, udp::endpoint(address::from_string("4.4.4.4"), 4), 10); + table.find_node(id, nodes, 0, 10); + TEST_EQUAL(table.bucket_size(0), 1); + TEST_EQUAL(nodes.size(), 1); + if (!nodes.empty()) + { + TEST_EQUAL(nodes[0].id, tmp); + TEST_EQUAL(nodes[0].addr(), address_v4::from_string("4.4.4.4")); + TEST_EQUAL(nodes[0].port(), 4); + } + + // test adding the same node ID again with a different IP (should be ignored) + table.node_seen(tmp, udp::endpoint(address::from_string("4.4.4.4"), 5), 10); + table.find_node(id, nodes, 0, 10); + TEST_EQUAL(table.bucket_size(0), 1); + if (!nodes.empty()) + { + TEST_EQUAL(nodes[0].id, tmp); + TEST_EQUAL(nodes[0].addr(), address_v4::from_string("4.4.4.4")); + TEST_EQUAL(nodes[0].port(), 4); + } + + // test adding a node that ends up in the same bucket with an IP + // very close to the current one (should be ignored) + // if restrict_routing_ips == true + table.node_seen(tmp, udp::endpoint(address::from_string("4.4.4.5"), 5), 10); + table.find_node(id, nodes, 0, 10); + TEST_EQUAL(table.bucket_size(0), 1); + if (!nodes.empty()) + { + TEST_EQUAL(nodes[0].id, tmp); + TEST_EQUAL(nodes[0].addr(), address_v4::from_string("4.4.4.4")); + TEST_EQUAL(nodes[0].port(), 4); + } + + s.restrict_routing_ips = false; + + add_and_replace(tmp, diff); + table.node_seen(id, udp::endpoint(rand_v4(), rand()), 10); + + nodes.clear(); + for (int i = 0; i < 7000; ++i) + { + table.node_seen(tmp, udp::endpoint(rand_v4(), rand()), 10); + add_and_replace(tmp, diff); + } + TEST_EQUAL(table.num_active_buckets(), 11); + TEST_CHECK(table.size().get<0>() > 10 * 10); + //#error test num_global_nodes + //#error test need_refresh + +#if defined TORRENT_DHT_VERBOSE_LOGGING || defined TORRENT_DEBUG + table.print_state(std::cerr); +#endif + + table.for_each_node(node_push_back, nop, &nodes); + + std::cout << "nodes: " << nodes.size() << std::endl; + + std::vector temp; + + std::generate(tmp.begin(), tmp.end(), &std::rand); + table.find_node(tmp, temp, 0, nodes.size() * 2); + std::cout << "returned: " << temp.size() << std::endl; + TEST_EQUAL(temp.size(), nodes.size()); + + std::generate(tmp.begin(), tmp.end(), &std::rand); + table.find_node(tmp, temp, 0, 7); + std::cout << "returned: " << temp.size() << std::endl; + TEST_EQUAL(temp.size(), 7); + + std::sort(nodes.begin(), nodes.end(), boost::bind(&compare_ref + , boost::bind(&node_entry::id, _1) + , boost::bind(&node_entry::id, _2), tmp)); + + int hits = 0; + // This makes sure enough of the nodes returned are actually + // part of the closest nodes + for (std::vector::iterator i = temp.begin() + , end(temp.end()); i != end; ++i) + { + int hit = std::find_if(nodes.begin(), nodes.end() + , boost::bind(&node_entry::id, _1) == i->id) - nodes.begin(); + // std::cerr << hit << std::endl; + if (hit < int(temp.size())) ++hits; + } + std::cout << "hits: " << hits << std::endl; + TEST_CHECK(hits == int(temp.size())); + + std::generate(tmp.begin(), tmp.end(), &std::rand); + table.find_node(tmp, temp, 0, 15); + std::cout << "returned: " << temp.size() << std::endl; + TEST_EQUAL(int(temp.size()), (std::min)(15, int(nodes.size()))); + + std::sort(nodes.begin(), nodes.end(), boost::bind(&compare_ref + , boost::bind(&node_entry::id, _1) + , boost::bind(&node_entry::id, _2), tmp)); + + hits = 0; + // This makes sure enough of the nodes returned are actually + // part of the closest nodes + for (std::vector::iterator i = temp.begin() + , end(temp.end()); i != end; ++i) + { + int hit = std::find_if(nodes.begin(), nodes.end() + , boost::bind(&node_entry::id, _1) == i->id) - nodes.begin(); + // std::cerr << hit << std::endl; + if (hit < int(temp.size())) ++hits; + } + std::cout << "hits: " << hits << std::endl; + TEST_CHECK(hits == int(temp.size())); + + using namespace libtorrent::dht; + + char const* ips[] = { + "124.31.75.21", + "21.75.31.124", + "65.23.51.170", + "84.124.73.14", + "43.213.53.83", + }; + + int rs[] = { 1,86,22,65,90 }; + + boost::uint8_t prefixes[][4] = + { + { 0x17, 0x12, 0xf6, 0xc7 }, + { 0x94, 0x64, 0x06, 0xc1 }, + { 0xfe, 0xfd, 0x92, 0x20 }, + { 0xaf, 0x15, 0x46, 0xdd }, + { 0xa9, 0xe9, 0x20, 0xbf } + }; + + for (int i = 0; i < 5; ++i) + { + address a = address_v4::from_string(ips[i]); + node_id id = generate_id_impl(a, rs[i]); + for (int j = 0; j < 4; ++j) + TEST_CHECK(id[j] == prefixes[i][j]); + TEST_CHECK(id[19] == rs[i]); + fprintf(stderr, "IP address: %s r: %d node ID: %s\n", ips[i] + , rs[i], to_hex(id.to_string()).c_str()); + } + } return 0; } diff --git a/test/test_file.cpp b/test/test_file.cpp index c9f14272d..fc36d1ce3 100644 --- a/test/test_file.cpp +++ b/test/test_file.cpp @@ -102,6 +102,132 @@ int test_main() remove_all("file_test_dir2", ec); if (ec) fprintf(stderr, "remove_all: %s\n", ec.message().c_str()); + // test path functions + TEST_EQUAL(combine_path("test1/", "test2"), "test1/test2"); +#ifdef TORRENT_WINDOWS + TEST_EQUAL(combine_path("test1\\", "test2"), "test1\\test2"); + TEST_EQUAL(combine_path("test1", "test2"), "test1\\test2"); +#else + TEST_EQUAL(combine_path("test1", "test2"), "test1/test2"); +#endif + +#if TORRENT_USE_UNC_PATHS + TEST_EQUAL(canonicalize_path("c:\\a\\..\\b"), "c:\\b"); + TEST_EQUAL(canonicalize_path("a\\..\\b"), "b"); + TEST_EQUAL(canonicalize_path("a\\..\\.\\b"), "b"); + TEST_EQUAL(canonicalize_path("\\.\\a"), "\\a"); + TEST_EQUAL(canonicalize_path("\\\\bla\\.\\a"), "\\\\bla\\a"); + TEST_EQUAL(canonicalize_path("c:\\bla\\a"), "c:\\bla\\a"); +#endif + + TEST_EQUAL(extension("blah"), ""); + TEST_EQUAL(extension("blah.exe"), ".exe"); + TEST_EQUAL(extension("blah.foo.bar"), ".bar"); + TEST_EQUAL(extension("blah.foo."), "."); + + TEST_EQUAL(filename("blah"), "blah"); + TEST_EQUAL(filename("/blah/foo/bar"), "bar"); + TEST_EQUAL(filename("/blah/foo/bar/"), "bar"); + TEST_EQUAL(filename("blah/"), "blah"); + +#ifdef TORRENT_WINDOWS + TEST_EQUAL(is_root_path("c:\\blah"), false); + TEST_EQUAL(is_root_path("c:\\"), true); + TEST_EQUAL(is_root_path("\\\\"), true); + TEST_EQUAL(is_root_path("\\\\foobar"), true); + TEST_EQUAL(is_root_path("\\\\foobar\\"), true); + TEST_EQUAL(is_root_path("\\\\foobar/"), true); + TEST_EQUAL(is_root_path("\\\\foo/bar"), false); + TEST_EQUAL(is_root_path("\\\\foo\\bar\\"), false); +#else + TEST_EQUAL(is_root_path("/blah"), false); + TEST_EQUAL(is_root_path("/"), true); +#endif + + // if has_parent_path() returns false + // parent_path() should return the empty string + TEST_EQUAL(parent_path("blah"), ""); + TEST_EQUAL(has_parent_path("blah"), false); + TEST_EQUAL(parent_path("/blah/foo/bar"), "/blah/foo/"); + TEST_EQUAL(has_parent_path("/blah/foo/bar"), true); + TEST_EQUAL(parent_path("/blah/foo/bar/"), "/blah/foo/"); + TEST_EQUAL(has_parent_path("/blah/foo/bar/"), true); + TEST_EQUAL(parent_path("/a"), "/"); + TEST_EQUAL(has_parent_path("/a"), true); + TEST_EQUAL(parent_path("/"), ""); + TEST_EQUAL(has_parent_path("/"), false); + TEST_EQUAL(parent_path(""), ""); + TEST_EQUAL(has_parent_path(""), false); +#ifdef TORRENT_WINDOWS + TEST_EQUAL(parent_path("\\\\"), ""); + TEST_EQUAL(has_parent_path("\\\\"), false); + TEST_EQUAL(parent_path("c:\\"), ""); + TEST_EQUAL(has_parent_path("c:\\"), false); + TEST_EQUAL(parent_path("c:\\a"), "c:\\"); + TEST_EQUAL(has_parent_path("c:\\a"), true); + TEST_EQUAL(has_parent_path("\\\\a"), false); + TEST_EQUAL(has_parent_path("\\\\foobar/"), false); + TEST_EQUAL(has_parent_path("\\\\foobar\\"), false); + TEST_EQUAL(has_parent_path("\\\\foo/bar\\"), true); +#endif + +#ifdef TORRENT_WINDOWS + TEST_EQUAL(is_complete("c:\\"), true); + TEST_EQUAL(is_complete("c:\\foo\\bar"), true); + TEST_EQUAL(is_complete("\\\\foo\\bar"), true); + TEST_EQUAL(is_complete("foo/bar"), false); + TEST_EQUAL(is_complete("\\\\"), true); +#else + TEST_EQUAL(is_complete("/foo/bar"), true); + TEST_EQUAL(is_complete("foo/bar"), false); + TEST_EQUAL(is_complete("/"), true); + TEST_EQUAL(is_complete(""), false); +#endif + + // test split_string + + char const* tags[10]; + char tags_str[] = " this is\ta test\t string\x01to be split and it cannot " + "extend over the limit of elements \t"; + int ret = split_string(tags, 10, tags_str); + + TEST_CHECK(ret == 10); + TEST_CHECK(strcmp(tags[0], "this") == 0); + TEST_CHECK(strcmp(tags[1], "is") == 0); + TEST_CHECK(strcmp(tags[2], "a") == 0); + TEST_CHECK(strcmp(tags[3], "test") == 0); + TEST_CHECK(strcmp(tags[4], "string") == 0); + TEST_CHECK(strcmp(tags[5], "to") == 0); + TEST_CHECK(strcmp(tags[6], "be") == 0); + TEST_CHECK(strcmp(tags[7], "split") == 0); + TEST_CHECK(strcmp(tags[8], "and") == 0); + TEST_CHECK(strcmp(tags[9], "it") == 0); + + // replace_extension + std::string test = "foo.bar"; + replace_extension(test, "txt"); + TEST_EQUAL(test, "foo.txt"); + + // file class + file f; +#if TORRENT_USE_UNC_PATHS || !defined WIN32 + TEST_CHECK(f.open("con", file::read_write, ec)); +#else + TEST_CHECK(f.open("test_file", file::read_write, ec)); +#endif + TEST_CHECK(!ec); + if (ec) fprintf(stderr, "%s\n", ec.message().c_str()); + file::iovec_t b = {(void*)"test", 4}; + TEST_CHECK(f.writev(0, &b, 1, ec) == 4); + TEST_CHECK(!ec); + char test_buf[5] = {0}; + b.iov_base = test_buf; + b.iov_len = 4; + TEST_CHECK(f.readv(0, &b, 1, ec) == 4); + TEST_CHECK(!ec); + TEST_CHECK(strcmp(test_buf, "test") == 0); + f.close(); + return 0; } diff --git a/test/test_http_parser.cpp b/test/test_http_parser.cpp new file mode 100644 index 000000000..6c06ca997 --- /dev/null +++ b/test/test_http_parser.cpp @@ -0,0 +1,306 @@ +/* + +Copyright (c) 2012, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "test.hpp" +#include "libtorrent/http_parser.hpp" +#include "libtorrent/parse_url.hpp" +#include "libtorrent/size_type.hpp" + +#include +#include + +using namespace libtorrent; +using boost::tuple; +using boost::make_tuple; +using boost::tie; + +tuple feed_bytes(http_parser& parser, char const* str) +{ + tuple ret(0, 0, false); + tuple prev(0, 0, false); + for (int chunks = 1; chunks < 70; ++chunks) + { + ret = make_tuple(0, 0, false); + parser.reset(); + buffer::const_interval recv_buf(str, str); + for (; *str;) + { + int chunk_size = (std::min)(chunks, int(strlen(recv_buf.end))); + if (chunk_size == 0) break; + recv_buf.end += chunk_size; + int payload, protocol; + bool error = false; + tie(payload, protocol) = parser.incoming(recv_buf, error); + ret.get<0>() += payload; + ret.get<1>() += protocol; + ret.get<2>() |= error; +// std::cerr << payload << ", " << protocol << ", " << chunk_size << std::endl; + TORRENT_ASSERT(payload + protocol == chunk_size); + } + TEST_CHECK(prev == make_tuple(0, 0, false) || ret == prev); + TEST_EQUAL(ret.get<0>() + ret.get<1>(), strlen(str)); + prev = ret; + } + return ret; +} + +int test_main() +{ + // HTTP request parser + http_parser parser; + boost::tuple received; + + received = feed_bytes(parser + , "HTTP/1.1 200 OK\r\n" + "Content-Length: 4\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "test"); + + TEST_CHECK(received == make_tuple(4, 64, false)); + 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(atoi(parser.header("content-length").c_str()) == 4); + + parser.reset(); + + TEST_CHECK(!parser.finished()); + + char const* upnp_response = + "HTTP/1.1 200 OK\r\n" + "ST:upnp:rootdevice\r\n" + "USN:uuid:000f-66d6-7296000099dc::upnp:rootdevice\r\n" + "Location: http://192.168.1.1:5431/dyndev/uuid:000f-66d6-7296000099dc\r\n" + "Server: Custom/1.0 UPnP/1.0 Proc/Ver\r\n" + "EXT:\r\n" + "Cache-Control:max-age=180\r\n" + "DATE: Fri, 02 Jan 1970 08:10:38 GMT\r\n\r\n"; + + received = feed_bytes(parser, upnp_response); + + TEST_CHECK(received == make_tuple(0, int(strlen(upnp_response)), false)); + TEST_CHECK(parser.get_body().left() == 0); + 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"); + + parser.reset(); + TEST_CHECK(!parser.finished()); + + char const* upnp_notify = + "NOTIFY * HTTP/1.1\r\n" + "Host:239.255.255.250:1900\r\n" + "NT:urn:schemas-upnp-org:device:MediaServer:1\r\n" + "NTS:ssdp:alive\r\n" + "Location:http://10.0.1.15:2353/upnphost/udhisapi.dll?content=uuid:c17f2c31-d19b-4912-af94-651945c8a84e\r\n" + "USN:uuid:c17f0c32-d1db-4be8-ae94-25f94583026e::urn:schemas-upnp-org:device:MediaServer:1\r\n" + "Cache-Control:max-age=900\r\n" + "Server:Microsoft-Windows-NT/5.1 UPnP/1.0 UPnP-Device-Host/1.0\r\n"; + + received = feed_bytes(parser, upnp_notify); + + TEST_CHECK(received == make_tuple(0, int(strlen(upnp_notify)), false)); + 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"; + + received = feed_bytes(parser, bt_lsd); + + TEST_CHECK(received == make_tuple(0, int(strlen(bt_lsd)), false)); + 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()); + + // test chunked encoding + char const* chunked_test = "HTTP/1.1 200 OK\r\n" + "Content-Length: 20\r\n" + "Content-Type: text/plain\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "4\r\n" + "test\r\n" + "10\r\n" + "0123456789abcdef\r\n" + "0\r\n" + "Test-header: foobar\r\n" + "\r\n"; + + received = feed_bytes(parser, chunked_test); + + printf("payload: %d protocol: %d\n", received.get<0>(), received.get<1>()); + TEST_CHECK(received == make_tuple(20, strlen(chunked_test) - 20, false)); + TEST_CHECK(parser.finished()); + TEST_CHECK(std::equal(parser.get_body().begin, parser.get_body().end + , "4\r\ntest\r\n10\r\n0123456789abcdef")); + TEST_CHECK(parser.header("test-header") == "foobar"); + TEST_CHECK(parser.header("content-type") == "text/plain"); + TEST_CHECK(atoi(parser.header("content-length").c_str()) == 20); + TEST_CHECK(parser.chunked_encoding()); + typedef std::pair chunk_range; + std::vector cmp; + cmp.push_back(chunk_range(96, 100)); + cmp.push_back(chunk_range(106, 122)); + TEST_CHECK(cmp == parser.chunks()); + + // 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), false)); + TEST_CHECK(parser.get_body().left() == 5); + + parser.reset(); + + // make sure we support content-range responses + // and that we're case insensitive + char const* web_seed_response = + "HTTP/1.1 206 OK\n" + "contEnt-rAngE: bYTes 0-4\n" + "conTent-TyPe: test/plain\n" + "\n" + "\ntest"; + + received = feed_bytes(parser, web_seed_response); + + TEST_CHECK(received == make_tuple(5, int(strlen(web_seed_response) - 5), false)); + TEST_CHECK(parser.content_range() == (std::pair(0, 4))); + TEST_CHECK(parser.content_length() == 5); + + parser.reset(); + + // make sure we support content-range responses + // and that we're case insensitive + char const* one_hundred_response = + "HTTP/1.1 100 Continue\n" + "\r\n" + "HTTP/1.1 200 OK\n" + "Content-Length: 4\r\n" + "Content-Type: test/plain\r\n" + "\r\n" + "test"; + + received = feed_bytes(parser, one_hundred_response); + + TEST_CHECK(received == make_tuple(4, int(strlen(one_hundred_response) - 4), false)); + TEST_EQUAL(parser.content_length(), 4); + + { + // test chunked encoding parser + char const chunk_header1[] = "f;this is a comment\r\n"; + size_type chunk_size; + int header_size; + bool ret = parser.parse_chunk_header(buffer::const_interval(chunk_header1, chunk_header1 + 10) + , &chunk_size, &header_size); + TEST_EQUAL(ret, false); + ret = parser.parse_chunk_header(buffer::const_interval(chunk_header1, chunk_header1 + sizeof(chunk_header1)) + , &chunk_size, &header_size); + TEST_EQUAL(ret, true); + TEST_EQUAL(chunk_size, 15); + TEST_EQUAL(header_size, sizeof(chunk_header1) - 1); + + char const chunk_header2[] = + "0;this is a comment\r\n" + "test1: foo\r\n" + "test2: bar\r\n" + "\r\n"; + + ret = parser.parse_chunk_header(buffer::const_interval(chunk_header2, chunk_header2 + sizeof(chunk_header2)) + , &chunk_size, &header_size); + TEST_EQUAL(ret, true); + TEST_EQUAL(chunk_size, 0); + TEST_EQUAL(header_size, sizeof(chunk_header2) - 1); + + TEST_EQUAL(parser.headers().find("test1")->second, "foo"); + TEST_EQUAL(parser.headers().find("test2")->second, "bar"); + } + + // test url parsing + + error_code ec; + TEST_CHECK(parse_url_components("http://foo:bar@host.com:80/path/to/file", ec) + == make_tuple("http", "foo:bar", "host.com", 80, "/path/to/file")); + + TEST_CHECK(parse_url_components("http://host.com/path/to/file", ec) + == make_tuple("http", "", "host.com", -1, "/path/to/file")); + + TEST_CHECK(parse_url_components("ftp://host.com:21/path/to/file", ec) + == make_tuple("ftp", "", "host.com", 21, "/path/to/file")); + + TEST_CHECK(parse_url_components("http://host.com/path?foo:bar@foo:", ec) + == make_tuple("http", "", "host.com", -1, "/path?foo:bar@foo:")); + + TEST_CHECK(parse_url_components("http://192.168.0.1/path/to/file", ec) + == make_tuple("http", "", "192.168.0.1", -1, "/path/to/file")); + + TEST_CHECK(parse_url_components("http://[2001:ff00::1]:42/path/to/file", ec) + == make_tuple("http", "", "[2001:ff00::1]", 42, "/path/to/file")); + + // leading spaces are supposed to be stripped + TEST_CHECK(parse_url_components(" \thttp://[2001:ff00::1]:42/path/to/file", ec) + == make_tuple("http", "", "[2001:ff00::1]", 42, "/path/to/file")); + + parse_url_components("http://[2001:ff00::1:42/path/to/file", ec); + TEST_CHECK(ec == error_code(errors::expected_close_bracket_in_address)); + + parse_url_components("http:/", ec); + TEST_CHECK(ec == error_code(errors::unsupported_url_protocol)); + ec.clear(); + + parse_url_components("http:", ec); + TEST_CHECK(ec == error_code(errors::unsupported_url_protocol)); + ec.clear(); + return 0; +} + diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index 5354236ba..f05654d31 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -34,8 +34,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/parse_url.hpp" #include "libtorrent/http_tracker_connection.hpp" #include "libtorrent/buffer.hpp" -#include "libtorrent/xml_parse.hpp" -#include "libtorrent/upnp.hpp" #include "libtorrent/entry.hpp" #include "libtorrent/bitfield.hpp" #include "libtorrent/torrent_info.hpp" @@ -52,13 +50,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/rsa.hpp" #include "libtorrent/ip_voter.hpp" -#ifndef TORRENT_DISABLE_DHT -#include "libtorrent/kademlia/node_id.hpp" -#include "libtorrent/kademlia/routing_table.hpp" -#include "libtorrent/kademlia/node.hpp" -#endif -#include -#include #include #include #include @@ -67,7 +58,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "setup_transfer.hpp" using namespace libtorrent; -using namespace boost::tuples; namespace libtorrent { TORRENT_EXPORT std::string sanitize_path(std::string const& p); @@ -80,313 +70,12 @@ sha1_hash to_hash(char const* s) return ret; } -tuple feed_bytes(http_parser& parser, char const* str) -{ - tuple ret(0, 0, false); - tuple prev(0, 0, false); - for (int chunks = 1; chunks < 70; ++chunks) - { - ret = make_tuple(0, 0, false); - parser.reset(); - buffer::const_interval recv_buf(str, str); - for (; *str;) - { - int chunk_size = (std::min)(chunks, int(strlen(recv_buf.end))); - if (chunk_size == 0) break; - recv_buf.end += chunk_size; - int payload, protocol; - bool error = false; - tie(payload, protocol) = parser.incoming(recv_buf, error); - ret.get<0>() += payload; - ret.get<1>() += protocol; - ret.get<2>() |= error; -// std::cerr << payload << ", " << protocol << ", " << chunk_size << std::endl; - TORRENT_ASSERT(payload + protocol == chunk_size); - } - TEST_CHECK(prev == make_tuple(0, 0, false) || ret == prev); - TEST_EQUAL(ret.get<0>() + ret.get<1>(), strlen(str)); - prev = ret; - } - return ret; -} - -void parser_callback(std::string& out, int token, char const* s, char const* val) -{ - switch (token) - { - case xml_start_tag: out += "B"; break; - case xml_end_tag: out += "F"; break; - case xml_empty_tag: out += "E"; break; - case xml_declaration_tag: out += "D"; break; - case xml_comment: out += "C"; break; - case xml_string: out += "S"; break; - case xml_attribute: out += "A"; break; - case xml_parse_error: out += "P"; break; - case xml_tag_content: out += "T"; break; - default: TEST_CHECK(false); - } - out += s; - if (token == xml_attribute) - { - TEST_CHECK(val != 0); - out += "V"; - out += val; - } - else - { - TEST_CHECK(val == 0); - } -} - -#ifndef TORRENT_DISABLE_DHT -void add_and_replace(libtorrent::dht::node_id& dst, libtorrent::dht::node_id const& add) -{ - bool carry = false; - for (int k = 19; k >= 0; --k) - { - int sum = dst[k] + add[k] + (carry?1:0); - dst[k] = sum & 255; - carry = sum > 255; - } -} - -void node_push_back(void* userdata, libtorrent::dht::node_entry const& n) -{ - using namespace libtorrent::dht; - std::vector* nv = (std::vector*)userdata; - nv->push_back(n); -} - -void nop(void* userdata, libtorrent::dht::node_entry const& n) {} - -#endif - -char upnp_xml[] = -"" -"" -"1" -"0" -"" -"http://192.168.0.1:5678" -"" -"" -"urn:schemas-upnp-org:device:InternetGatewayDevice:1" -"" -"http://192.168.0.1:80" -"D-Link Router" -"D-Link" -"http://www.dlink.com" -"Internet Access Router" -"D-Link Router" -"uuid:upnp-InternetGatewayDevice-1_0-12345678900001" -"123456789001" -"" -"" -"urn:schemas-upnp-org:service:Layer3Forwarding:1" -"urn:upnp-org:serviceId:L3Forwarding1" -"/Layer3Forwarding" -"/Layer3Forwarding" -"/Layer3Forwarding.xml" -"" -"" -"" -"" -"urn:schemas-upnp-org:device:WANDevice:1" -"WANDevice" -"D-Link" -"http://www.dlink.com" -"Internet Access Router" -"D-Link Router" -"1" -"http://support.dlink.com" -"12345678900001" -"uuid:upnp-WANDevice-1_0-12345678900001" -"123456789001" -"" -"" -"" -"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" -"" -"urn:upnp-org:serviceId:WANCommonInterfaceConfig" -"/WANCommonInterfaceConfig" -"/WANCommonInterfaceConfig" -"/WANCommonInterfaceConfig.xml" -"" -"" -"" -"" -"urn:schemas-upnp-org:device:WANConnectionDevice:1" -"WAN Connection Device" -"D-Link" -"http://www.dlink.com" -"Internet Access Router" -"D-Link Router" -"1" -"http://support.dlink.com" -"12345678900001" -"uuid:upnp-WANConnectionDevice-1_0-12345678900001" -"123456789001" -"" -"" -"urn:schemas-upnp-org:service:WANIPConnection:1" -"urn:upnp-org:serviceId:WANIPConnection" -"/WANIPConnection" -"/WANIPConnection" -"/WANIPConnection.xml" -"" -"" -"" -"" -"" -"" -"" -""; - -char upnp_xml2[] = -"" -"" -"1" -"0" -"" -"http://192.168.1.1:49152" -"" -"" -"urn:schemas-upnp-org:device:InternetGatewayDevice:1" -"" -"LINKSYS WAG200G Gateway" -"LINKSYS" -"http://www.linksys.com" -"LINKSYS WAG200G Gateway" -"Wireless-G ADSL Home Gateway" -"WAG200G" -"http://www.linksys.com" -"123456789" -"uuid:8d401597-1dd2-11b2-a7d4-001ee5947cac" -"WAG200G" -"" -"" -"urn:schemas-upnp-org:service:Layer3Forwarding:1" -"urn:upnp-org:serviceId:L3Forwarding1" -"/upnp/control/L3Forwarding1" -"/upnp/event/L3Forwarding1" -"/l3frwd.xml" -"" -"" -"" -"" -"urn:schemas-upnp-org:device:WANDevice:1" -"WANDevice" -"LINKSYS" -"http://www.linksys.com/" -"Residential Gateway" -"Internet Connection Sharing" -"1" -"http://www.linksys.com/" -"0000001" -"uuid:8d401596-1dd2-11b2-a7d4-001ee5947cac" -"WAG200G" -"" -"" -"" -"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" -"" -"urn:upnp-org:serviceId:WANCommonIFC1" -"/upnp/control/WANCommonIFC1" -"/upnp/event/WANCommonIFC1" -"/cmnicfg.xml" -"" -"" -"" -"" -"urn:schemas-upnp-org:device:WANConnectionDevice:1" -"WANConnectionDevice" -"LINKSYS" -"http://www.linksys.com/" -"Residential Gateway" -"Internet Connection Sharing" -"1" -"http://www.linksys.com/" -"0000001" -"uuid:8d401597-1dd2-11b2-a7d3-001ee5947cac" -"WAG200G" -"" -"" -"" -"urn:schemas-upnp-org:service:WANEthernetLinkConfig:1" -"" -"urn:upnp-org:serviceId:WANEthLinkC1" -"/upnp/control/WANEthLinkC1" -"/upnp/event/WANEthLinkC1" -"/wanelcfg.xml" -"" -"" -"urn:schemas-upnp-org:service:WANPPPConnection:1" -"urn:upnp-org:serviceId:WANPPPConn1" -"/upnp/control/WANPPPConn1" -"/upnp/event/WANPPPConn1" -"/pppcfg.xml" -"" -"" -"" -"" -"" -"" -"urn:schemas-upnp-org:device:LANDevice:1" -"LANDevice" -"LINKSYS" -"http://www.linksys.com/" -"Residential Gateway" -"Residential Gateway" -"1" -"http://www.linksys.com/" -"0000001" -"uuid:8d401596-1dd2-11b2-a7d3-001ee5947cac" -"WAG200G" -"" -"" -"" -"urn:schemas-upnp-org:service:LANHostConfigManagement:1" -"" -"urn:upnp-org:serviceId:LANHostCfg1" -"/upnp/control/LANHostCfg1" -"/upnp/event/LANHostCfg1" -"/lanhostc.xml" -"" -"" -"" -"" -"http://192.168.1.1/index.htm" -"" -""; - -struct parse_state -{ - parse_state(): in_service(false) {} - void reset(char const* st) - { - in_service = false; - service_type = st; - tag_stack.clear(); - control_url.clear(); - model.clear(); - url_base.clear(); - } - bool in_service; - std::list tag_stack; - std::string control_url; - char const* service_type; - std::string model; - std::string url_base; -}; - namespace libtorrent { // defined in torrent_info.cpp TORRENT_EXPORT bool verify_encoding(std::string& target, bool path = true); } -TORRENT_EXPORT void find_control_url(int type, char const* string, parse_state& state); - address rand_v4() { return address_v4((rand() << 16 | rand()) & 0xffffffff); @@ -450,101 +139,6 @@ int test_main() TEST_CHECK(ret == 1); #endif - lazy_entry ent; - -#ifndef TORRENT_DISABLE_DHT - // test verify_message - const static key_desc_t msg_desc[] = { - {"A", lazy_entry::string_t, 4, 0}, - {"B", lazy_entry::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children}, - {"B1", lazy_entry::string_t, 0, 0}, - {"B2", lazy_entry::string_t, 0, key_desc_t::last_child}, - {"C", lazy_entry::dict_t, 0, key_desc_t::optional | key_desc_t::parse_children}, - {"C1", lazy_entry::string_t, 0, 0}, - {"C2", lazy_entry::string_t, 0, key_desc_t::last_child}, - }; - - lazy_entry const* msg_keys[7]; - - char const test_msg[] = "d1:A4:test1:Bd2:B15:test22:B25:test3ee"; - lazy_bdecode(test_msg, test_msg + sizeof(test_msg)-1, ent, ec); - fprintf(stderr, "%s\n", print_entry(ent).c_str()); - - char error_string[200]; - ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); - TEST_CHECK(ret); - TEST_CHECK(msg_keys[0]); - if (msg_keys[0]) TEST_EQUAL(msg_keys[0]->string_value(), "test"); - TEST_CHECK(msg_keys[1]); - TEST_CHECK(msg_keys[2]); - if (msg_keys[2]) TEST_EQUAL(msg_keys[2]->string_value(), "test2"); - TEST_CHECK(msg_keys[3]); - if (msg_keys[3]) TEST_EQUAL(msg_keys[3]->string_value(), "test3"); - TEST_CHECK(msg_keys[4] == 0); - TEST_CHECK(msg_keys[5] == 0); - TEST_CHECK(msg_keys[6] == 0); - - char const test_msg2[] = "d1:A4:test1:Cd2:C15:test22:C25:test3ee"; - lazy_bdecode(test_msg2, test_msg2 + sizeof(test_msg2)-1, ent, ec); - fprintf(stderr, "%s\n", print_entry(ent).c_str()); - - ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); - TEST_CHECK(ret); - TEST_CHECK(msg_keys[0]); - if (msg_keys[0]) TEST_EQUAL(msg_keys[0]->string_value(), "test"); - TEST_CHECK(msg_keys[1] == 0); - TEST_CHECK(msg_keys[2] == 0); - TEST_CHECK(msg_keys[3] == 0); - TEST_CHECK(msg_keys[4]); - TEST_CHECK(msg_keys[5]); - if (msg_keys[5]) TEST_EQUAL(msg_keys[5]->string_value(), "test2"); - TEST_CHECK(msg_keys[6]); - if (msg_keys[6]) TEST_EQUAL(msg_keys[6]->string_value(), "test3"); - - - char const test_msg3[] = "d1:Cd2:C15:test22:C25:test3ee"; - lazy_bdecode(test_msg3, test_msg3 + sizeof(test_msg3)-1, ent, ec); - fprintf(stderr, "%s\n", print_entry(ent).c_str()); - - ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); - TEST_CHECK(!ret); - fprintf(stderr, "%s\n", error_string); - TEST_EQUAL(error_string, std::string("missing 'A' key")); - - char const test_msg4[] = "d1:A6:foobare"; - lazy_bdecode(test_msg4, test_msg4 + sizeof(test_msg4)-1, ent, ec); - fprintf(stderr, "%s\n", print_entry(ent).c_str()); - - ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); - TEST_CHECK(!ret); - fprintf(stderr, "%s\n", error_string); - TEST_EQUAL(error_string, std::string("invalid value for 'A'")); - - char const test_msg5[] = "d1:A4:test1:Cd2:C15:test2ee"; - lazy_bdecode(test_msg5, test_msg5 + sizeof(test_msg5)-1, ent, ec); - fprintf(stderr, "%s\n", print_entry(ent).c_str()); - - ret = verify_message(&ent, msg_desc, msg_keys, 7, error_string, sizeof(error_string)); - TEST_CHECK(!ret); - fprintf(stderr, "%s\n", error_string); - TEST_EQUAL(error_string, std::string("missing 'C2' key")); - - // test empty strings [ { "":1 }, "" ] - char const test_msg6[] = "ld0:i1ee0:e"; - lazy_bdecode(test_msg6, test_msg6 + sizeof(test_msg6)-1, ent, ec); - fprintf(stderr, "%s\n", print_entry(ent).c_str()); - TEST_CHECK(ent.type() == lazy_entry::list_t); - if (ent.type() == lazy_entry::list_t) - { - TEST_CHECK(ent.list_size() == 2); - if (ent.list_size() == 2) - { - TEST_CHECK(ent.list_at(0)->dict_find_int_value("") == 1); - TEST_CHECK(ent.list_at(1)->string_value() == ""); - } - } -#endif // TORRENT_DISABLE_DHT - // test external ip voting external_ip ipv1; @@ -771,6 +365,8 @@ int test_main() TEST_CHECK(error_code(errors::unauthorized, get_http_category()).message() == "401 Unauthorized"); TEST_CHECK(error_code(errors::service_unavailable, get_http_category()).message() == "503 Service Unavailable"); + session_proxy p1; + session_proxy p2; { // test session state load/restore session* s = new session(fingerprint("LT",0,0,0,0), 0); @@ -873,6 +469,7 @@ int test_main() TEST_EQUAL(to_hex(t.info_hash().to_string()), "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"); + p1 = s->abort(); delete s; s = new session(fingerprint("LT",0,0,0,0), 0); @@ -933,124 +530,16 @@ int test_main() CMP_SET(prefer_udp_trackers); CMP_SET(strict_super_seeding); CMP_SET(seeding_piece_quota); + p2 = s->abort(); delete s; } - // test path functions - TEST_EQUAL(combine_path("test1/", "test2"), "test1/test2"); -#ifdef TORRENT_WINDOWS - TEST_EQUAL(combine_path("test1\\", "test2"), "test1\\test2"); - TEST_EQUAL(combine_path("test1", "test2"), "test1\\test2"); -#else - TEST_EQUAL(combine_path("test1", "test2"), "test1/test2"); -#endif - -#if TORRENT_USE_UNC_PATHS - TEST_EQUAL(canonicalize_path("c:\\a\\..\\b"), "c:\\b"); - TEST_EQUAL(canonicalize_path("a\\..\\b"), "b"); - TEST_EQUAL(canonicalize_path("a\\..\\.\\b"), "b"); - TEST_EQUAL(canonicalize_path("\\.\\a"), "\\a"); - TEST_EQUAL(canonicalize_path("\\\\bla\\.\\a"), "\\\\bla\\a"); - TEST_EQUAL(canonicalize_path("c:\\bla\\a"), "c:\\bla\\a"); -#endif - - TEST_EQUAL(extension("blah"), ""); - TEST_EQUAL(extension("blah.exe"), ".exe"); - TEST_EQUAL(extension("blah.foo.bar"), ".bar"); - TEST_EQUAL(extension("blah.foo."), "."); - - TEST_EQUAL(filename("blah"), "blah"); - TEST_EQUAL(filename("/blah/foo/bar"), "bar"); - TEST_EQUAL(filename("/blah/foo/bar/"), "bar"); - TEST_EQUAL(filename("blah/"), "blah"); - -#ifdef TORRENT_WINDOWS - TEST_EQUAL(is_root_path("c:\\blah"), false); - TEST_EQUAL(is_root_path("c:\\"), true); - TEST_EQUAL(is_root_path("\\\\"), true); - TEST_EQUAL(is_root_path("\\\\foobar"), true); - TEST_EQUAL(is_root_path("\\\\foobar\\"), true); - TEST_EQUAL(is_root_path("\\\\foobar/"), true); - TEST_EQUAL(is_root_path("\\\\foo/bar"), false); - TEST_EQUAL(is_root_path("\\\\foo\\bar\\"), false); -#else - TEST_EQUAL(is_root_path("/blah"), false); - TEST_EQUAL(is_root_path("/"), true); -#endif - - // if has_parent_path() returns false - // parent_path() should return the empty string - TEST_EQUAL(parent_path("blah"), ""); - TEST_EQUAL(has_parent_path("blah"), false); - TEST_EQUAL(parent_path("/blah/foo/bar"), "/blah/foo/"); - TEST_EQUAL(has_parent_path("/blah/foo/bar"), true); - TEST_EQUAL(parent_path("/blah/foo/bar/"), "/blah/foo/"); - TEST_EQUAL(has_parent_path("/blah/foo/bar/"), true); - TEST_EQUAL(parent_path("/a"), "/"); - TEST_EQUAL(has_parent_path("/a"), true); - TEST_EQUAL(parent_path("/"), ""); - TEST_EQUAL(has_parent_path("/"), false); - TEST_EQUAL(parent_path(""), ""); - TEST_EQUAL(has_parent_path(""), false); -#ifdef TORRENT_WINDOWS - TEST_EQUAL(parent_path("\\\\"), ""); - TEST_EQUAL(has_parent_path("\\\\"), false); - TEST_EQUAL(parent_path("c:\\"), ""); - TEST_EQUAL(has_parent_path("c:\\"), false); - TEST_EQUAL(parent_path("c:\\a"), "c:\\"); - TEST_EQUAL(has_parent_path("c:\\a"), true); - TEST_EQUAL(has_parent_path("\\\\a"), false); - TEST_EQUAL(has_parent_path("\\\\foobar/"), false); - TEST_EQUAL(has_parent_path("\\\\foobar\\"), false); - TEST_EQUAL(has_parent_path("\\\\foo/bar\\"), true); -#endif - -#ifdef TORRENT_WINDOWS - TEST_EQUAL(is_complete("c:\\"), true); - TEST_EQUAL(is_complete("c:\\foo\\bar"), true); - TEST_EQUAL(is_complete("\\\\foo\\bar"), true); - TEST_EQUAL(is_complete("foo/bar"), false); - TEST_EQUAL(is_complete("\\\\"), true); -#else - TEST_EQUAL(is_complete("/foo/bar"), true); - TEST_EQUAL(is_complete("foo/bar"), false); - TEST_EQUAL(is_complete("/"), true); - TEST_EQUAL(is_complete(""), false); -#endif - - // test split_string - - char const* tags[10]; - char tags_str[] = " this is\ta test\t string\x01to be split and it cannot " - "extend over the limit of elements \t"; - ret = split_string(tags, 10, tags_str); - - TEST_CHECK(ret == 10); - TEST_CHECK(strcmp(tags[0], "this") == 0); - TEST_CHECK(strcmp(tags[1], "is") == 0); - TEST_CHECK(strcmp(tags[2], "a") == 0); - TEST_CHECK(strcmp(tags[3], "test") == 0); - TEST_CHECK(strcmp(tags[4], "string") == 0); - TEST_CHECK(strcmp(tags[5], "to") == 0); - TEST_CHECK(strcmp(tags[6], "be") == 0); - TEST_CHECK(strcmp(tags[7], "split") == 0); - TEST_CHECK(strcmp(tags[8], "and") == 0); - TEST_CHECK(strcmp(tags[9], "it") == 0); - // test snprintf char msg[10]; snprintf(msg, sizeof(msg), "too %s format string", "long"); TEST_CHECK(strcmp(msg, "too long ") == 0); - // test maybe_url_encode - TEST_EQUAL(maybe_url_encode("http://test:test@abc.com/abc<>abc"), "http://test:test@abc.com/abc%3c%3eabc"); - TEST_EQUAL(maybe_url_encode("http://abc.com/foo bar"), "http://abc.com/foo%20bar"); - TEST_EQUAL(maybe_url_encode("http://abc.com:80/foo bar"), "http://abc.com:80/foo%20bar"); - TEST_EQUAL(maybe_url_encode("http://abc.com:8080/foo bar"), "http://abc.com:8080/foo%20bar"); - TEST_EQUAL(maybe_url_encode("abc"), "abc"); - TEST_EQUAL(maybe_url_encode("http://abc.com/abc"), "http://abc.com/abc"); - // test sanitize_path #ifdef TORRENT_WINDOWS @@ -1101,202 +590,8 @@ int test_main() TEST_CHECK(identify_client(peer_id("S123--..............")) == "Shadow 1.2.3"); TEST_CHECK(identify_client(peer_id("M1-2-3--............")) == "Mainline 1.2.3"); - // test to/from hex conversion - - char const* str = "0123456789012345678901234567890123456789"; - char bin[20]; - TEST_CHECK(from_hex(str, 40, bin)); - char hex[41]; - to_hex(bin, 20, hex); - TEST_CHECK(strcmp(hex, str) == 0); - - // test is_space - - TEST_CHECK(!is_space('C')); - TEST_CHECK(!is_space('\b')); - TEST_CHECK(!is_space('8')); - TEST_CHECK(!is_space('=')); - TEST_CHECK(is_space(' ')); - TEST_CHECK(is_space('\t')); - TEST_CHECK(is_space('\n')); - TEST_CHECK(is_space('\r')); - - // test to_lower - - TEST_CHECK(to_lower('C') == 'c'); - TEST_CHECK(to_lower('c') == 'c'); - TEST_CHECK(to_lower('-') == '-'); - TEST_CHECK(to_lower('&') == '&'); - - // test string_equal_no_case - - TEST_CHECK(string_equal_no_case("foobar", "FoobAR")); - TEST_CHECK(string_equal_no_case("foobar", "foobar")); - TEST_CHECK(!string_equal_no_case("foobar", "foobar ")); - TEST_CHECK(!string_equal_no_case("foobar", "F00")); - - // test string_begins_no_case - - TEST_CHECK(string_begins_no_case("foobar", "FoobAR --")); - TEST_CHECK(!string_begins_no_case("foobar", "F00")); - - // test itoa - - TEST_CHECK(to_string(345).elems == std::string("345")); - TEST_CHECK(to_string(-345).elems == std::string("-345")); - TEST_CHECK(to_string(0).elems == std::string("0")); - TEST_CHECK(to_string(1000000000).elems == std::string("1000000000")); - - // test url parsing - - TEST_CHECK(parse_url_components("http://foo:bar@host.com:80/path/to/file", ec) - == make_tuple("http", "foo:bar", "host.com", 80, "/path/to/file")); - - TEST_CHECK(parse_url_components("http://host.com/path/to/file", ec) - == make_tuple("http", "", "host.com", -1, "/path/to/file")); - - TEST_CHECK(parse_url_components("ftp://host.com:21/path/to/file", ec) - == make_tuple("ftp", "", "host.com", 21, "/path/to/file")); - - TEST_CHECK(parse_url_components("http://host.com/path?foo:bar@foo:", ec) - == make_tuple("http", "", "host.com", -1, "/path?foo:bar@foo:")); - - TEST_CHECK(parse_url_components("http://192.168.0.1/path/to/file", ec) - == make_tuple("http", "", "192.168.0.1", -1, "/path/to/file")); - - TEST_CHECK(parse_url_components("http://[2001:ff00::1]:42/path/to/file", ec) - == make_tuple("http", "", "[2001:ff00::1]", 42, "/path/to/file")); - - // leading spaces are supposed to be stripped - TEST_CHECK(parse_url_components(" \thttp://[2001:ff00::1]:42/path/to/file", ec) - == make_tuple("http", "", "[2001:ff00::1]", 42, "/path/to/file")); - - parse_url_components("http://[2001:ff00::1:42/path/to/file", ec); - TEST_CHECK(ec == error_code(errors::expected_close_bracket_in_address)); - - parse_url_components("http:/", ec); - TEST_CHECK(ec == error_code(errors::unsupported_url_protocol)); - ec.clear(); - - parse_url_components("http:", ec); - TEST_CHECK(ec == error_code(errors::unsupported_url_protocol)); - ec.clear(); - - // base64 test vectors from http://www.faqs.org/rfcs/rfc4648.html - - TEST_CHECK(base64encode("") == ""); - TEST_CHECK(base64encode("f") == "Zg=="); - TEST_CHECK(base64encode("fo") == "Zm8="); - TEST_CHECK(base64encode("foo") == "Zm9v"); - TEST_CHECK(base64encode("foob") == "Zm9vYg=="); - TEST_CHECK(base64encode("fooba") == "Zm9vYmE="); - TEST_CHECK(base64encode("foobar") == "Zm9vYmFy"); - - // base32 test vectors from http://www.faqs.org/rfcs/rfc4648.html - - TEST_CHECK(base32encode("") == ""); - TEST_CHECK(base32encode("f") == "MY======"); - TEST_CHECK(base32encode("fo") == "MZXQ===="); - TEST_CHECK(base32encode("foo") == "MZXW6==="); - TEST_CHECK(base32encode("foob") == "MZXW6YQ="); - TEST_CHECK(base32encode("fooba") == "MZXW6YTB"); - TEST_CHECK(base32encode("foobar") == "MZXW6YTBOI======"); - - TEST_CHECK(base32decode("") == ""); - TEST_CHECK(base32decode("MY======") == "f"); - TEST_CHECK(base32decode("MZXQ====") == "fo"); - TEST_CHECK(base32decode("MZXW6===") == "foo"); - TEST_CHECK(base32decode("MZXW6YQ=") == "foob"); - TEST_CHECK(base32decode("MZXW6YTB") == "fooba"); - TEST_CHECK(base32decode("MZXW6YTBOI======") == "foobar"); - - TEST_CHECK(base32decode("MY") == "f"); - TEST_CHECK(base32decode("MZXW6YQ") == "foob"); - TEST_CHECK(base32decode("MZXW6YTBOI") == "foobar"); - TEST_CHECK(base32decode("mZXw6yTBO1======") == "foobar"); - - std::string test; - for (int i = 0; i < 255; ++i) - test += char(i); - - TEST_CHECK(base32decode(base32encode(test)) == test); - - // url_has_argument - - TEST_CHECK(url_has_argument("http://127.0.0.1/test", "test") == ""); - TEST_CHECK(url_has_argument("http://127.0.0.1/test?foo=24", "bar") == ""); - TEST_CHECK(url_has_argument("http://127.0.0.1/test?foo=24", "foo") == "24"); - TEST_CHECK(url_has_argument("http://127.0.0.1/test?foo=24&bar=23", "foo") == "24"); - TEST_CHECK(url_has_argument("http://127.0.0.1/test?foo=24&bar=23", "bar") == "23"); - TEST_CHECK(url_has_argument("http://127.0.0.1/test?foo=24&bar=23&a=e", "bar") == "23"); - TEST_CHECK(url_has_argument("http://127.0.0.1/test?foo=24&bar=23&a=e", "a") == "e"); - TEST_CHECK(url_has_argument("http://127.0.0.1/test?foo=24&bar=23&a=e", "b") == ""); - - // escape_string - char const* test_string = "!@#$%^&*()-_=+/,. %?"; - TEST_EQUAL(escape_string(test_string, strlen(test_string)) - , "!%40%23%24%25%5e%26*()-_%3d%2b%2f%2c.%20%25%3f"); - - // escape_path - TEST_EQUAL(escape_path(test_string, strlen(test_string)) - , "!%40%23%24%25%5e%26*()-_%3d%2b/%2c.%20%25%3f"); - - TEST_CHECK(unescape_string(escape_path(test_string, strlen(test_string)), ec) == test_string); - TEST_CHECK(!ec); - if (ec) fprintf(stderr, "%s\n", ec.message().c_str()); - - // need_encoding - char const* test_string2 = "!@$&()-_/,.%?"; - TEST_CHECK(need_encoding(test_string, strlen(test_string)) == true); - TEST_CHECK(need_encoding(test_string2, strlen(test_string2)) == false); - TEST_CHECK(need_encoding("\n", 1) == true); - - // maybe_url_encode - TEST_EQUAL(maybe_url_encode("http://bla.com/\n"), "http://bla.com/%0a"); - TEST_EQUAL(maybe_url_encode("http://bla.com/foo%20bar"), "http://bla.com/foo%20bar"); - TEST_EQUAL(maybe_url_encode("http://bla.com/foo%20bar?k=v&k2=v2"), "http://bla.com/foo%20bar?k=v&k2=v2"); - TEST_EQUAL(maybe_url_encode("?&"), "?&"); - - // unescape_string - TEST_CHECK(unescape_string(escape_string(test_string, strlen(test_string)), ec) - == test_string); - std::cerr << unescape_string(escape_string(test_string, strlen(test_string)), ec) << std::endl; - // prematurely terminated string - unescape_string("%", ec); - TEST_CHECK(ec == error_code(errors::invalid_escaped_string)); - unescape_string("%0", ec); - TEST_CHECK(ec == error_code(errors::invalid_escaped_string)); - - // invalid hex character - unescape_string("%GE", ec); - TEST_CHECK(ec == error_code(errors::invalid_escaped_string)); - unescape_string("%eg", ec); - TEST_CHECK(ec == error_code(errors::invalid_escaped_string)); - ec.clear(); - - char hex_chars[] = "0123456789abcdefABCDEF"; - - for (int i = 1; i < 255; ++i) - { - bool hex = strchr(hex_chars, i) != NULL; - char c = i; - TEST_EQUAL(is_hex(&c, 1), hex); - } - - TEST_EQUAL(hex_to_int('0'), 0); - TEST_EQUAL(hex_to_int('7'), 7); - TEST_EQUAL(hex_to_int('a'), 10); - TEST_EQUAL(hex_to_int('f'), 15); - TEST_EQUAL(hex_to_int('b'), 11); - TEST_EQUAL(hex_to_int('t'), -1); - TEST_EQUAL(hex_to_int('g'), -1); - - std::string path = "a\\b\\c"; - convert_path_to_posix(path); - TEST_EQUAL(path, "a/b/c"); - // verify_encoding - test = "\b?filename=4"; + std::string test = "\b?filename=4"; TEST_CHECK(!verify_encoding(test)); #ifdef TORRENT_WINDOWS TEST_CHECK(test == "__filename=4"); @@ -1399,283 +694,6 @@ int test_main() comparison.resize(TORRENT_MAX_PATH); TEST_EQUAL(test, comparison); - - // replace_extension - test = "foo.bar"; - replace_extension(test, "txt"); - TEST_EQUAL(test, "foo.txt"); - - // file class - file f; -#if TORRENT_USE_UNC_PATHS || !defined WIN32 - TEST_CHECK(f.open("con", file::read_write, ec)); -#else - TEST_CHECK(f.open("test_file", file::read_write, ec)); -#endif - TEST_CHECK(!ec); - if (ec) fprintf(stderr, "%s\n", ec.message().c_str()); - file::iovec_t b = {(void*)"test", 4}; - TEST_CHECK(f.writev(0, &b, 1, ec) == 4); - TEST_CHECK(!ec); - char test_buf[5] = {0}; - b.iov_base = test_buf; - b.iov_len = 4; - TEST_CHECK(f.readv(0, &b, 1, ec) == 4); - TEST_CHECK(!ec); - TEST_CHECK(strcmp(test_buf, "test") == 0); - f.close(); - - // HTTP request parser - http_parser parser; - boost::tuple received; - - received = feed_bytes(parser - , "HTTP/1.1 200 OK\r\n" - "Content-Length: 4\r\n" - "Content-Type: text/plain\r\n" - "\r\n" - "test"); - - TEST_CHECK(received == make_tuple(4, 64, false)); - 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(atoi(parser.header("content-length").c_str()) == 4); - - parser.reset(); - - TEST_CHECK(!parser.finished()); - - char const* upnp_response = - "HTTP/1.1 200 OK\r\n" - "ST:upnp:rootdevice\r\n" - "USN:uuid:000f-66d6-7296000099dc::upnp:rootdevice\r\n" - "Location: http://192.168.1.1:5431/dyndev/uuid:000f-66d6-7296000099dc\r\n" - "Server: Custom/1.0 UPnP/1.0 Proc/Ver\r\n" - "EXT:\r\n" - "Cache-Control:max-age=180\r\n" - "DATE: Fri, 02 Jan 1970 08:10:38 GMT\r\n\r\n"; - - received = feed_bytes(parser, upnp_response); - - TEST_CHECK(received == make_tuple(0, int(strlen(upnp_response)), false)); - TEST_CHECK(parser.get_body().left() == 0); - 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"); - - parser.reset(); - TEST_CHECK(!parser.finished()); - - char const* upnp_notify = - "NOTIFY * HTTP/1.1\r\n" - "Host:239.255.255.250:1900\r\n" - "NT:urn:schemas-upnp-org:device:MediaServer:1\r\n" - "NTS:ssdp:alive\r\n" - "Location:http://10.0.1.15:2353/upnphost/udhisapi.dll?content=uuid:c17f2c31-d19b-4912-af94-651945c8a84e\r\n" - "USN:uuid:c17f0c32-d1db-4be8-ae94-25f94583026e::urn:schemas-upnp-org:device:MediaServer:1\r\n" - "Cache-Control:max-age=900\r\n" - "Server:Microsoft-Windows-NT/5.1 UPnP/1.0 UPnP-Device-Host/1.0\r\n"; - - received = feed_bytes(parser, upnp_notify); - - TEST_CHECK(received == make_tuple(0, int(strlen(upnp_notify)), false)); - 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"; - - received = feed_bytes(parser, bt_lsd); - - TEST_CHECK(received == make_tuple(0, int(strlen(bt_lsd)), false)); - 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()); - - // test chunked encoding - char const* chunked_test = "HTTP/1.1 200 OK\r\n" - "Content-Length: 20\r\n" - "Content-Type: text/plain\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "4\r\n" - "test\r\n" - "10\r\n" - "0123456789abcdef\r\n" - "0\r\n" - "Test-header: foobar\r\n" - "\r\n"; - - received = feed_bytes(parser, chunked_test); - - printf("payload: %d protocol: %d\n", received.get<0>(), received.get<1>()); - TEST_CHECK(received == make_tuple(20, strlen(chunked_test) - 20, false)); - TEST_CHECK(parser.finished()); - TEST_CHECK(std::equal(parser.get_body().begin, parser.get_body().end - , "4\r\ntest\r\n10\r\n0123456789abcdef")); - TEST_CHECK(parser.header("test-header") == "foobar"); - TEST_CHECK(parser.header("content-type") == "text/plain"); - TEST_CHECK(atoi(parser.header("content-length").c_str()) == 20); - TEST_CHECK(parser.chunked_encoding()); - typedef std::pair chunk_range; - std::vector cmp; - cmp.push_back(chunk_range(96, 100)); - cmp.push_back(chunk_range(106, 122)); - TEST_CHECK(cmp == parser.chunks()); - - // 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), false)); - TEST_CHECK(parser.get_body().left() == 5); - - parser.reset(); - - // make sure we support content-range responses - // and that we're case insensitive - char const* web_seed_response = - "HTTP/1.1 206 OK\n" - "contEnt-rAngE: bYTes 0-4\n" - "conTent-TyPe: test/plain\n" - "\n" - "\ntest"; - - received = feed_bytes(parser, web_seed_response); - - TEST_CHECK(received == make_tuple(5, int(strlen(web_seed_response) - 5), false)); - TEST_CHECK(parser.content_range() == (std::pair(0, 4))); - TEST_CHECK(parser.content_length() == 5); - - parser.reset(); - - // make sure we support content-range responses - // and that we're case insensitive - char const* one_hundred_response = - "HTTP/1.1 100 Continue\n" - "\r\n" - "HTTP/1.1 200 OK\n" - "Content-Length: 4\r\n" - "Content-Type: test/plain\r\n" - "\r\n" - "test"; - - received = feed_bytes(parser, one_hundred_response); - - TEST_CHECK(received == make_tuple(4, int(strlen(one_hundred_response) - 4), false)); - TEST_EQUAL(parser.content_length(), 4); - - { - // test chunked encoding parser - char const chunk_header1[] = "f;this is a comment\r\n"; - size_type chunk_size; - int header_size; - bool ret = parser.parse_chunk_header(buffer::const_interval(chunk_header1, chunk_header1 + 10) - , &chunk_size, &header_size); - TEST_EQUAL(ret, false); - ret = parser.parse_chunk_header(buffer::const_interval(chunk_header1, chunk_header1 + sizeof(chunk_header1)) - , &chunk_size, &header_size); - TEST_EQUAL(ret, true); - TEST_EQUAL(chunk_size, 15); - TEST_EQUAL(header_size, sizeof(chunk_header1) - 1); - - char const chunk_header2[] = - "0;this is a comment\r\n" - "test1: foo\r\n" - "test2: bar\r\n" - "\r\n"; - - ret = parser.parse_chunk_header(buffer::const_interval(chunk_header2, chunk_header2 + sizeof(chunk_header2)) - , &chunk_size, &header_size); - TEST_EQUAL(ret, true); - TEST_EQUAL(chunk_size, 0); - TEST_EQUAL(header_size, sizeof(chunk_header2) - 1); - - TEST_EQUAL(parser.headers().find("test1")->second, "foo"); - TEST_EQUAL(parser.headers().find("test2")->second, "bar"); - } - - // test xml parser - char xml1[] = "foobar"; - std::string out1; - - xml_parse(xml1, xml1 + sizeof(xml1) - 1, boost::bind(&parser_callback - , boost::ref(out1), _1, _2, _3)); - std::cerr << out1 << std::endl; - TEST_CHECK(out1 == "BaSfooEbSbarFa"); - - char xml2[] = ""; - std::string out2; - - xml_parse(xml2, xml2 + sizeof(xml2) - 1, boost::bind(&parser_callback - , boost::ref(out2), _1, _2, _3)); - std::cerr << out2 << std::endl; - TEST_CHECK(out2 == "DxmlAversionV1.0EcAxV1AyV3BdAfooVbarFdAbooVfooCcomment"); - - char xml3[] = "foo + +char upnp_xml[] = +"" +"" +"1" +"0" +"" +"http://192.168.0.1:5678" +"" +"" +"urn:schemas-upnp-org:device:InternetGatewayDevice:1" +"" +"http://192.168.0.1:80" +"D-Link Router" +"D-Link" +"http://www.dlink.com" +"Internet Access Router" +"D-Link Router" +"uuid:upnp-InternetGatewayDevice-1_0-12345678900001" +"123456789001" +"" +"" +"urn:schemas-upnp-org:service:Layer3Forwarding:1" +"urn:upnp-org:serviceId:L3Forwarding1" +"/Layer3Forwarding" +"/Layer3Forwarding" +"/Layer3Forwarding.xml" +"" +"" +"" +"" +"urn:schemas-upnp-org:device:WANDevice:1" +"WANDevice" +"D-Link" +"http://www.dlink.com" +"Internet Access Router" +"D-Link Router" +"1" +"http://support.dlink.com" +"12345678900001" +"uuid:upnp-WANDevice-1_0-12345678900001" +"123456789001" +"" +"" +"" +"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" +"" +"urn:upnp-org:serviceId:WANCommonInterfaceConfig" +"/WANCommonInterfaceConfig" +"/WANCommonInterfaceConfig" +"/WANCommonInterfaceConfig.xml" +"" +"" +"" +"" +"urn:schemas-upnp-org:device:WANConnectionDevice:1" +"WAN Connection Device" +"D-Link" +"http://www.dlink.com" +"Internet Access Router" +"D-Link Router" +"1" +"http://support.dlink.com" +"12345678900001" +"uuid:upnp-WANConnectionDevice-1_0-12345678900001" +"123456789001" +"" +"" +"urn:schemas-upnp-org:service:WANIPConnection:1" +"urn:upnp-org:serviceId:WANIPConnection" +"/WANIPConnection" +"/WANIPConnection" +"/WANIPConnection.xml" +"" +"" +"" +"" +"" +"" +"" +""; + +char upnp_xml2[] = +"" +"" +"1" +"0" +"" +"http://192.168.1.1:49152" +"" +"" +"urn:schemas-upnp-org:device:InternetGatewayDevice:1" +"" +"LINKSYS WAG200G Gateway" +"LINKSYS" +"http://www.linksys.com" +"LINKSYS WAG200G Gateway" +"Wireless-G ADSL Home Gateway" +"WAG200G" +"http://www.linksys.com" +"123456789" +"uuid:8d401597-1dd2-11b2-a7d4-001ee5947cac" +"WAG200G" +"" +"" +"urn:schemas-upnp-org:service:Layer3Forwarding:1" +"urn:upnp-org:serviceId:L3Forwarding1" +"/upnp/control/L3Forwarding1" +"/upnp/event/L3Forwarding1" +"/l3frwd.xml" +"" +"" +"" +"" +"urn:schemas-upnp-org:device:WANDevice:1" +"WANDevice" +"LINKSYS" +"http://www.linksys.com/" +"Residential Gateway" +"Internet Connection Sharing" +"1" +"http://www.linksys.com/" +"0000001" +"uuid:8d401596-1dd2-11b2-a7d4-001ee5947cac" +"WAG200G" +"" +"" +"" +"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" +"" +"urn:upnp-org:serviceId:WANCommonIFC1" +"/upnp/control/WANCommonIFC1" +"/upnp/event/WANCommonIFC1" +"/cmnicfg.xml" +"" +"" +"" +"" +"urn:schemas-upnp-org:device:WANConnectionDevice:1" +"WANConnectionDevice" +"LINKSYS" +"http://www.linksys.com/" +"Residential Gateway" +"Internet Connection Sharing" +"1" +"http://www.linksys.com/" +"0000001" +"uuid:8d401597-1dd2-11b2-a7d3-001ee5947cac" +"WAG200G" +"" +"" +"" +"urn:schemas-upnp-org:service:WANEthernetLinkConfig:1" +"" +"urn:upnp-org:serviceId:WANEthLinkC1" +"/upnp/control/WANEthLinkC1" +"/upnp/event/WANEthLinkC1" +"/wanelcfg.xml" +"" +"" +"urn:schemas-upnp-org:service:WANPPPConnection:1" +"urn:upnp-org:serviceId:WANPPPConn1" +"/upnp/control/WANPPPConn1" +"/upnp/event/WANPPPConn1" +"/pppcfg.xml" +"" +"" +"" +"" +"" +"" +"urn:schemas-upnp-org:device:LANDevice:1" +"LANDevice" +"LINKSYS" +"http://www.linksys.com/" +"Residential Gateway" +"Residential Gateway" +"1" +"http://www.linksys.com/" +"0000001" +"uuid:8d401596-1dd2-11b2-a7d3-001ee5947cac" +"WAG200G" +"" +"" +"" +"urn:schemas-upnp-org:service:LANHostConfigManagement:1" +"" +"urn:upnp-org:serviceId:LANHostCfg1" +"/upnp/control/LANHostCfg1" +"/upnp/event/LANHostCfg1" +"/lanhostc.xml" +"" +"" +"" +"" +"http://192.168.1.1/index.htm" +"" +""; + +using namespace libtorrent; + +struct parse_state +{ + parse_state(): in_service(false) {} + void reset(char const* st) + { + in_service = false; + service_type = st; + tag_stack.clear(); + control_url.clear(); + model.clear(); + url_base.clear(); + } + bool in_service; + std::list tag_stack; + std::string control_url; + char const* service_type; + std::string model; + std::string url_base; +}; + +TORRENT_EXPORT void find_control_url(int type, char const* string, parse_state& state); + +void parser_callback(std::string& out, int token, char const* s, char const* val) +{ + switch (token) + { + case xml_start_tag: out += "B"; break; + case xml_end_tag: out += "F"; break; + case xml_empty_tag: out += "E"; break; + case xml_declaration_tag: out += "D"; break; + case xml_comment: out += "C"; break; + case xml_string: out += "S"; break; + case xml_attribute: out += "A"; break; + case xml_parse_error: out += "P"; break; + case xml_tag_content: out += "T"; break; + default: TEST_CHECK(false); + } + out += s; + if (token == xml_attribute) + { + TEST_CHECK(val != 0); + out += "V"; + out += val; + } + else + { + TEST_CHECK(val == 0); + } +} + +int test_main() +{ + // test upnp xml parser + + parse_state xml_s; + xml_s.reset("urn:schemas-upnp-org:service:WANIPConnection:1"); + xml_parse(upnp_xml, upnp_xml + sizeof(upnp_xml) + , boost::bind(&find_control_url, _1, _2, boost::ref(xml_s))); + + std::cerr << "namespace " << xml_s.service_type << std::endl; + std::cerr << "url_base: " << xml_s.url_base << std::endl; + std::cerr << "control_url: " << xml_s.control_url << std::endl; + std::cerr << "model: " << xml_s.model << std::endl; + TEST_CHECK(xml_s.url_base == "http://192.168.0.1:5678"); + TEST_CHECK(xml_s.control_url == "/WANIPConnection"); + TEST_CHECK(xml_s.model == "D-Link Router"); + + xml_s.reset("urn:schemas-upnp-org:service:WANPPPConnection:1"); + xml_parse(upnp_xml2, upnp_xml2 + sizeof(upnp_xml2) + , boost::bind(&find_control_url, _1, _2, boost::ref(xml_s))); + + std::cerr << "namespace " << xml_s.service_type << std::endl; + std::cerr << "url_base: " << xml_s.url_base << std::endl; + std::cerr << "control_url: " << xml_s.control_url << std::endl; + std::cerr << "model: " << xml_s.model << std::endl; + TEST_CHECK(xml_s.url_base == "http://192.168.1.1:49152"); + TEST_CHECK(xml_s.control_url == "/upnp/control/WANPPPConn1"); + TEST_CHECK(xml_s.model == "Wireless-G ADSL Home Gateway"); + + // test xml parser + char xml1[] = "foobar"; + std::string out1; + + xml_parse(xml1, xml1 + sizeof(xml1) - 1, boost::bind(&parser_callback + , boost::ref(out1), _1, _2, _3)); + std::cerr << out1 << std::endl; + TEST_CHECK(out1 == "BaSfooEbSbarFa"); + + char xml2[] = ""; + std::string out2; + + xml_parse(xml2, xml2 + sizeof(xml2) - 1, boost::bind(&parser_callback + , boost::ref(out2), _1, _2, _3)); + std::cerr << out2 << std::endl; + TEST_CHECK(out2 == "DxmlAversionV1.0EcAxV1AyV3BdAfooVbarFdAbooVfooCcomment"); + + char xml3[] = "foo