split up test_primitives into more tests (in an attempt to get the link-time down within the regression test time limit)
This commit is contained in:
@@ -323,7 +323,10 @@ if(build_tests)
|
|||||||
test_peer_priority
|
test_peer_priority
|
||||||
test_bencoding
|
test_bencoding
|
||||||
test_bdecode_performance
|
test_bdecode_performance
|
||||||
|
test_xml
|
||||||
|
test_string
|
||||||
test_primitives
|
test_primitives
|
||||||
|
test_http_parser
|
||||||
test_ip_filter
|
test_ip_filter
|
||||||
test_hasher
|
test_hasher
|
||||||
test_metadata_extension
|
test_metadata_extension
|
||||||
|
@@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "libtorrent/assert.hpp"
|
||||||
#include "libtorrent/escape_string.hpp"
|
#include "libtorrent/escape_string.hpp"
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
|
@@ -70,6 +70,9 @@ test-suite libtorrent :
|
|||||||
[ run test_bencoding.cpp ]
|
[ run test_bencoding.cpp ]
|
||||||
[ run test_fast_extension.cpp ]
|
[ run test_fast_extension.cpp ]
|
||||||
[ run test_primitives.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_ip_filter.cpp ]
|
||||||
[ run test_hasher.cpp ]
|
[ run test_hasher.cpp ]
|
||||||
[ run test_dht.cpp ]
|
[ run test_dht.cpp ]
|
||||||
|
@@ -19,7 +19,10 @@ test_programs = \
|
|||||||
test_peer_priority \
|
test_peer_priority \
|
||||||
test_pex \
|
test_pex \
|
||||||
test_piece_picker \
|
test_piece_picker \
|
||||||
|
test_xml \
|
||||||
|
test_string \
|
||||||
test_primitives \
|
test_primitives \
|
||||||
|
test_http_parser \
|
||||||
test_rss \
|
test_rss \
|
||||||
test_storage \
|
test_storage \
|
||||||
test_swarm \
|
test_swarm \
|
||||||
|
@@ -38,6 +38,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
#include "libtorrent/socket_io.hpp" // for hash_address
|
#include "libtorrent/socket_io.hpp" // for hash_address
|
||||||
#include "libtorrent/broadcast_socket.hpp" // for supports_ipv6
|
#include "libtorrent/broadcast_socket.hpp" // for supports_ipv6
|
||||||
#include "libtorrent/alert_dispatcher.hpp"
|
#include "libtorrent/alert_dispatcher.hpp"
|
||||||
|
|
||||||
|
#include "libtorrent/kademlia/node_id.hpp"
|
||||||
|
#include "libtorrent/kademlia/routing_table.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
@@ -46,6 +49,33 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
using namespace libtorrent::dht;
|
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<node_entry>* nv = (std::vector<node_entry>*)userdata;
|
||||||
|
nv->push_back(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nop(void* userdata, libtorrent::dht::node_entry const& n) {}
|
||||||
|
|
||||||
std::list<std::pair<udp::endpoint, entry> > g_responses;
|
std::list<std::pair<udp::endpoint, entry> > g_responses;
|
||||||
|
|
||||||
struct mock_socket : udp_socket_interface
|
struct mock_socket : udp_socket_interface
|
||||||
@@ -651,6 +681,327 @@ int test_main()
|
|||||||
#endif
|
#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<node_entry> 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<node_entry> 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<node_entry>::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<node_entry>::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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -102,6 +102,132 @@ int test_main()
|
|||||||
remove_all("file_test_dir2", ec);
|
remove_all("file_test_dir2", ec);
|
||||||
if (ec) fprintf(stderr, "remove_all: %s\n", ec.message().c_str());
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
306
test/test_http_parser.cpp
Normal file
306
test/test_http_parser.cpp
Normal file
@@ -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 <boost/tuple/tuple.hpp>
|
||||||
|
#include <boost/tuple/tuple_comparison.hpp>
|
||||||
|
|
||||||
|
using namespace libtorrent;
|
||||||
|
using boost::tuple;
|
||||||
|
using boost::make_tuple;
|
||||||
|
using boost::tie;
|
||||||
|
|
||||||
|
tuple<int, int, bool> feed_bytes(http_parser& parser, char const* str)
|
||||||
|
{
|
||||||
|
tuple<int, int, bool> ret(0, 0, false);
|
||||||
|
tuple<int, int, bool> 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<int, int, bool> 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<size_type, size_type> chunk_range;
|
||||||
|
std::vector<chunk_range> 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<size_type, size_type>(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;
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
212
test/test_string.cpp
Normal file
212
test/test_string.cpp
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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/escape_string.hpp"
|
||||||
|
#include "libtorrent/string_util.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
int test_main()
|
||||||
|
{
|
||||||
|
// 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 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"));
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
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");
|
||||||
|
|
||||||
|
// 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") == "");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
351
test/test_xml.cpp
Normal file
351
test/test_xml.cpp
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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 "libtorrent/xml_parse.hpp"
|
||||||
|
#include "libtorrent/upnp.hpp"
|
||||||
|
#include "test.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
char upnp_xml[] =
|
||||||
|
"<root>"
|
||||||
|
"<specVersion>"
|
||||||
|
"<major>1</major>"
|
||||||
|
"<minor>0</minor>"
|
||||||
|
"</specVersion>"
|
||||||
|
"<URLBase>http://192.168.0.1:5678</URLBase>"
|
||||||
|
"<device>"
|
||||||
|
"<deviceType>"
|
||||||
|
"urn:schemas-upnp-org:device:InternetGatewayDevice:1"
|
||||||
|
"</deviceType>"
|
||||||
|
"<presentationURL>http://192.168.0.1:80</presentationURL>"
|
||||||
|
"<friendlyName>D-Link Router</friendlyName>"
|
||||||
|
"<manufacturer>D-Link</manufacturer>"
|
||||||
|
"<manufacturerURL>http://www.dlink.com</manufacturerURL>"
|
||||||
|
"<modelDescription>Internet Access Router</modelDescription>"
|
||||||
|
"<modelName>D-Link Router</modelName>"
|
||||||
|
"<UDN>uuid:upnp-InternetGatewayDevice-1_0-12345678900001</UDN>"
|
||||||
|
"<UPC>123456789001</UPC>"
|
||||||
|
"<serviceList>"
|
||||||
|
"<service>"
|
||||||
|
"<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>"
|
||||||
|
"<serviceId>urn:upnp-org:serviceId:L3Forwarding1</serviceId>"
|
||||||
|
"<controlURL>/Layer3Forwarding</controlURL>"
|
||||||
|
"<eventSubURL>/Layer3Forwarding</eventSubURL>"
|
||||||
|
"<SCPDURL>/Layer3Forwarding.xml</SCPDURL>"
|
||||||
|
"</service>"
|
||||||
|
"</serviceList>"
|
||||||
|
"<deviceList>"
|
||||||
|
"<device>"
|
||||||
|
"<deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType>"
|
||||||
|
"<friendlyName>WANDevice</friendlyName>"
|
||||||
|
"<manufacturer>D-Link</manufacturer>"
|
||||||
|
"<manufacturerURL>http://www.dlink.com</manufacturerURL>"
|
||||||
|
"<modelDescription>Internet Access Router</modelDescription>"
|
||||||
|
"<modelName>D-Link Router</modelName>"
|
||||||
|
"<modelNumber>1</modelNumber>"
|
||||||
|
"<modelURL>http://support.dlink.com</modelURL>"
|
||||||
|
"<serialNumber>12345678900001</serialNumber>"
|
||||||
|
"<UDN>uuid:upnp-WANDevice-1_0-12345678900001</UDN>"
|
||||||
|
"<UPC>123456789001</UPC>"
|
||||||
|
"<serviceList>"
|
||||||
|
"<service>"
|
||||||
|
"<serviceType>"
|
||||||
|
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"
|
||||||
|
"</serviceType>"
|
||||||
|
"<serviceId>urn:upnp-org:serviceId:WANCommonInterfaceConfig</serviceId>"
|
||||||
|
"<controlURL>/WANCommonInterfaceConfig</controlURL>"
|
||||||
|
"<eventSubURL>/WANCommonInterfaceConfig</eventSubURL>"
|
||||||
|
"<SCPDURL>/WANCommonInterfaceConfig.xml</SCPDURL>"
|
||||||
|
"</service>"
|
||||||
|
"</serviceList>"
|
||||||
|
"<deviceList>"
|
||||||
|
"<device>"
|
||||||
|
"<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType>"
|
||||||
|
"<friendlyName>WAN Connection Device</friendlyName>"
|
||||||
|
"<manufacturer>D-Link</manufacturer>"
|
||||||
|
"<manufacturerURL>http://www.dlink.com</manufacturerURL>"
|
||||||
|
"<modelDescription>Internet Access Router</modelDescription>"
|
||||||
|
"<modelName>D-Link Router</modelName>"
|
||||||
|
"<modelNumber>1</modelNumber>"
|
||||||
|
"<modelURL>http://support.dlink.com</modelURL>"
|
||||||
|
"<serialNumber>12345678900001</serialNumber>"
|
||||||
|
"<UDN>uuid:upnp-WANConnectionDevice-1_0-12345678900001</UDN>"
|
||||||
|
"<UPC>123456789001</UPC>"
|
||||||
|
"<serviceList>"
|
||||||
|
"<service>"
|
||||||
|
"<serviceType>urn:schemas-upnp-org:service:WANIPConnection:1</serviceType>"
|
||||||
|
"<serviceId>urn:upnp-org:serviceId:WANIPConnection</serviceId>"
|
||||||
|
"<controlURL>/WANIPConnection</controlURL>"
|
||||||
|
"<eventSubURL>/WANIPConnection</eventSubURL>"
|
||||||
|
"<SCPDURL>/WANIPConnection.xml</SCPDURL>"
|
||||||
|
"</service>"
|
||||||
|
"</serviceList>"
|
||||||
|
"</device>"
|
||||||
|
"</deviceList>"
|
||||||
|
"</device>"
|
||||||
|
"</deviceList>"
|
||||||
|
"</device>"
|
||||||
|
"</root>";
|
||||||
|
|
||||||
|
char upnp_xml2[] =
|
||||||
|
"<root>"
|
||||||
|
"<specVersion>"
|
||||||
|
"<major>1</major>"
|
||||||
|
"<minor>0</minor>"
|
||||||
|
"</specVersion>"
|
||||||
|
"<URLBase>http://192.168.1.1:49152</URLBase>"
|
||||||
|
"<device>"
|
||||||
|
"<deviceType>"
|
||||||
|
"urn:schemas-upnp-org:device:InternetGatewayDevice:1"
|
||||||
|
"</deviceType>"
|
||||||
|
"<friendlyName>LINKSYS WAG200G Gateway</friendlyName>"
|
||||||
|
"<manufacturer>LINKSYS</manufacturer>"
|
||||||
|
"<manufacturerURL>http://www.linksys.com</manufacturerURL>"
|
||||||
|
"<modelDescription>LINKSYS WAG200G Gateway</modelDescription>"
|
||||||
|
"<modelName>Wireless-G ADSL Home Gateway</modelName>"
|
||||||
|
"<modelNumber>WAG200G</modelNumber>"
|
||||||
|
"<modelURL>http://www.linksys.com</modelURL>"
|
||||||
|
"<serialNumber>123456789</serialNumber>"
|
||||||
|
"<UDN>uuid:8d401597-1dd2-11b2-a7d4-001ee5947cac</UDN>"
|
||||||
|
"<UPC>WAG200G</UPC>"
|
||||||
|
"<serviceList>"
|
||||||
|
"<service>"
|
||||||
|
"<serviceType>urn:schemas-upnp-org:service:Layer3Forwarding:1</serviceType>"
|
||||||
|
"<serviceId>urn:upnp-org:serviceId:L3Forwarding1</serviceId>"
|
||||||
|
"<controlURL>/upnp/control/L3Forwarding1</controlURL>"
|
||||||
|
"<eventSubURL>/upnp/event/L3Forwarding1</eventSubURL>"
|
||||||
|
"<SCPDURL>/l3frwd.xml</SCPDURL>"
|
||||||
|
"</service>"
|
||||||
|
"</serviceList>"
|
||||||
|
"<deviceList>"
|
||||||
|
"<device>"
|
||||||
|
"<deviceType>urn:schemas-upnp-org:device:WANDevice:1</deviceType>"
|
||||||
|
"<friendlyName>WANDevice</friendlyName>"
|
||||||
|
"<manufacturer>LINKSYS</manufacturer>"
|
||||||
|
"<manufacturerURL>http://www.linksys.com/</manufacturerURL>"
|
||||||
|
"<modelDescription>Residential Gateway</modelDescription>"
|
||||||
|
"<modelName>Internet Connection Sharing</modelName>"
|
||||||
|
"<modelNumber>1</modelNumber>"
|
||||||
|
"<modelURL>http://www.linksys.com/</modelURL>"
|
||||||
|
"<serialNumber>0000001</serialNumber>"
|
||||||
|
"<UDN>uuid:8d401596-1dd2-11b2-a7d4-001ee5947cac</UDN>"
|
||||||
|
"<UPC>WAG200G</UPC>"
|
||||||
|
"<serviceList>"
|
||||||
|
"<service>"
|
||||||
|
"<serviceType>"
|
||||||
|
"urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1"
|
||||||
|
"</serviceType>"
|
||||||
|
"<serviceId>urn:upnp-org:serviceId:WANCommonIFC1</serviceId>"
|
||||||
|
"<controlURL>/upnp/control/WANCommonIFC1</controlURL>"
|
||||||
|
"<eventSubURL>/upnp/event/WANCommonIFC1</eventSubURL>"
|
||||||
|
"<SCPDURL>/cmnicfg.xml</SCPDURL>"
|
||||||
|
"</service>"
|
||||||
|
"</serviceList>"
|
||||||
|
"<deviceList>"
|
||||||
|
"<device>"
|
||||||
|
"<deviceType>urn:schemas-upnp-org:device:WANConnectionDevice:1</deviceType>"
|
||||||
|
"<friendlyName>WANConnectionDevice</friendlyName>"
|
||||||
|
"<manufacturer>LINKSYS</manufacturer>"
|
||||||
|
"<manufacturerURL>http://www.linksys.com/</manufacturerURL>"
|
||||||
|
"<modelDescription>Residential Gateway</modelDescription>"
|
||||||
|
"<modelName>Internet Connection Sharing</modelName>"
|
||||||
|
"<modelNumber>1</modelNumber>"
|
||||||
|
"<modelURL>http://www.linksys.com/</modelURL>"
|
||||||
|
"<serialNumber>0000001</serialNumber>"
|
||||||
|
"<UDN>uuid:8d401597-1dd2-11b2-a7d3-001ee5947cac</UDN>"
|
||||||
|
"<UPC>WAG200G</UPC>"
|
||||||
|
"<serviceList>"
|
||||||
|
"<service>"
|
||||||
|
"<serviceType>"
|
||||||
|
"urn:schemas-upnp-org:service:WANEthernetLinkConfig:1"
|
||||||
|
"</serviceType>"
|
||||||
|
"<serviceId>urn:upnp-org:serviceId:WANEthLinkC1</serviceId>"
|
||||||
|
"<controlURL>/upnp/control/WANEthLinkC1</controlURL>"
|
||||||
|
"<eventSubURL>/upnp/event/WANEthLinkC1</eventSubURL>"
|
||||||
|
"<SCPDURL>/wanelcfg.xml</SCPDURL>"
|
||||||
|
"</service>"
|
||||||
|
"<service>"
|
||||||
|
"<serviceType>urn:schemas-upnp-org:service:WANPPPConnection:1</serviceType>"
|
||||||
|
"<serviceId>urn:upnp-org:serviceId:WANPPPConn1</serviceId>"
|
||||||
|
"<controlURL>/upnp/control/WANPPPConn1</controlURL>"
|
||||||
|
"<eventSubURL>/upnp/event/WANPPPConn1</eventSubURL>"
|
||||||
|
"<SCPDURL>/pppcfg.xml</SCPDURL>"
|
||||||
|
"</service>"
|
||||||
|
"</serviceList>"
|
||||||
|
"</device>"
|
||||||
|
"</deviceList>"
|
||||||
|
"</device>"
|
||||||
|
"<device>"
|
||||||
|
"<deviceType>urn:schemas-upnp-org:device:LANDevice:1</deviceType>"
|
||||||
|
"<friendlyName>LANDevice</friendlyName>"
|
||||||
|
"<manufacturer>LINKSYS</manufacturer>"
|
||||||
|
"<manufacturerURL>http://www.linksys.com/</manufacturerURL>"
|
||||||
|
"<modelDescription>Residential Gateway</modelDescription>"
|
||||||
|
"<modelName>Residential Gateway</modelName>"
|
||||||
|
"<modelNumber>1</modelNumber>"
|
||||||
|
"<modelURL>http://www.linksys.com/</modelURL>"
|
||||||
|
"<serialNumber>0000001</serialNumber>"
|
||||||
|
"<UDN>uuid:8d401596-1dd2-11b2-a7d3-001ee5947cac</UDN>"
|
||||||
|
"<UPC>WAG200G</UPC>"
|
||||||
|
"<serviceList>"
|
||||||
|
"<service>"
|
||||||
|
"<serviceType>"
|
||||||
|
"urn:schemas-upnp-org:service:LANHostConfigManagement:1"
|
||||||
|
"</serviceType>"
|
||||||
|
"<serviceId>urn:upnp-org:serviceId:LANHostCfg1</serviceId>"
|
||||||
|
"<controlURL>/upnp/control/LANHostCfg1</controlURL>"
|
||||||
|
"<eventSubURL>/upnp/event/LANHostCfg1</eventSubURL>"
|
||||||
|
"<SCPDURL>/lanhostc.xml</SCPDURL>"
|
||||||
|
"</service>"
|
||||||
|
"</serviceList>"
|
||||||
|
"</device>"
|
||||||
|
"</deviceList>"
|
||||||
|
"<presentationURL>http://192.168.1.1/index.htm</presentationURL>"
|
||||||
|
"</device>"
|
||||||
|
"</root>";
|
||||||
|
|
||||||
|
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<std::string> 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[] = "<a>foo<b/>bar</a>";
|
||||||
|
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[] = "<?xml version = \"1.0\"?><c x=\"1\" \t y=\"3\"/><d foo='bar'></d boo='foo'><!--comment-->";
|
||||||
|
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[] = "<a f=1>foo</a f='b>";
|
||||||
|
std::string out3;
|
||||||
|
|
||||||
|
xml_parse(xml3, xml3 + sizeof(xml3) - 1, boost::bind(&parser_callback
|
||||||
|
, boost::ref(out3), _1, _2, _3));
|
||||||
|
std::cerr << out3 << std::endl;
|
||||||
|
TEST_CHECK(out3 == "BaPunquoted attribute valueSfooFaPmissing end quote on attribute");
|
||||||
|
|
||||||
|
char xml4[] = "<a f>foo</a v >";
|
||||||
|
std::string out4;
|
||||||
|
|
||||||
|
xml_parse(xml4, xml4 + sizeof(xml4) - 1, boost::bind(&parser_callback
|
||||||
|
, boost::ref(out4), _1, _2, _3));
|
||||||
|
std::cerr << out4 << std::endl;
|
||||||
|
TEST_CHECK(out4 == "BaTfSfooFaTv ");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user