make parse_interface_list more robust and improve string tests (#806)

make parse_interface_list more robust and improve string tests
This commit is contained in:
Arvid Norberg 2016-06-12 02:00:10 -04:00 committed by GitHub
parent 0440c57f68
commit 590f68cd3d
4 changed files with 216 additions and 111 deletions

View File

@ -54,6 +54,18 @@ namespace lt = libtorrent;
const int connect_socks = 2;
std::string make_ep_string(char const* address, bool const is_v6
, char const* port)
{
std::string ret;
if (is_v6) ret += '[';
ret += address;
if (is_v6) ret += ']';
ret += ':';
ret += port;
return ret;
}
template <typename Setup, typename HandleAlerts, typename Test>
void run_test(
Setup const& setup
@ -98,13 +110,13 @@ void run_test(
pack.set_int(settings_pack::out_enc_policy, settings_pack::pe_disabled);
pack.set_int(settings_pack::allowed_enc_level, settings_pack::pe_plaintext);
pack.set_str(settings_pack::listen_interfaces, peer0_ip[use_ipv6] + std::string(":6881"));
pack.set_str(settings_pack::listen_interfaces, make_ep_string(peer0_ip[use_ipv6], use_ipv6, "6881"));
// create session
std::shared_ptr<lt::session> ses[2];
ses[0] = std::make_shared<lt::session>(pack, ios0);
pack.set_str(settings_pack::listen_interfaces, peer1_ip[use_ipv6] + std::string(":6881"));
pack.set_str(settings_pack::listen_interfaces, make_ep_string(peer1_ip[use_ipv6], use_ipv6, "6881"));
ses[1] = std::make_shared<lt::session>(pack, ios1);
setup(*ses[0], *ses[1]);

View File

@ -214,44 +214,89 @@ namespace libtorrent
out.clear();
std::string::size_type start = 0;
std::string::size_type end = 0;
while (start < in.size())
{
// skip leading spaces
while (start < in.size()
&& is_space(in[start]))
while (start < in.size() && is_space(in[start]))
++start;
end = in.find_first_of(',', start);
if (end == std::string::npos) end = in.size();
if (start == in.size()) return;
std::string::size_type colon = in.find_last_of(':', end);
listen_interface_t iface;
iface.ssl = false;
if (colon != std::string::npos && colon > start)
#if !TORRENT_USE_IPV6
bool ipv6 = false;
#endif
if (in[start] == '[')
{
listen_interface_t iface;
#if !TORRENT_USE_IPV6
ipv6 = true;
#endif
++start;
// IPv6 address
while (start < in.size() && in[start] != ']')
iface.device += in[start++];
std::string port_string = in.substr(colon + 1, end - colon - 1);
iface.ssl = !port_string.empty() && port_string[port_string.size()-1] == 's';
iface.port = atoi(port_string.c_str());
// skip to the colon
while (start < in.size() && in[start] != ':')
++start;
}
else
{
// consume device name
while (start < in.size() && !is_space(in[start]) && in[start] != ':')
iface.device += in[start++];
}
// skip trailing spaces
std::string::size_type soft_end = colon;
while (soft_end > start
&& is_space(in[soft_end-1]))
--soft_end;
// skip spaces
while (start < in.size() && is_space(in[start]))
++start;
// in case this is an IPv6 address, strip off the square brackets
// to make it more easily parseable into an ip::address
if (in[start] == '[') ++start;
if (soft_end > start && in[soft_end-1] == ']') --soft_end;
if (start == in.size() || in[start] != ':') return;
++start; // skip colon
iface.device = in.substr(start, soft_end - start);
// skip spaces
while (start < in.size() && is_space(in[start]))
++start;
// consume port
std::string port;
while (start < in.size() && is_digit(in[start]) && in[start] != ',')
port += in[start++];
if (port.empty()) iface.port = -1;
else iface.port = std::atoi(port.c_str());
// skip spaces
while (start < in.size() && is_space(in[start]))
++start;
// consume potential SSL 's'
if (start < in.size() && in[start] == 's')
{
iface.ssl = true;
++start;
}
// skip until end or comma
while (start < in.size() && in[start] != ',')
++start;
if (iface.port >= 0
#if !TORRENT_USE_IPV6
&& ipv6 == false
#endif
)
{
out.push_back(iface);
}
start = end + 1;
// skip the comma
if (start < in.size() && in[start] == ',')
++start;
}
}

View File

@ -125,7 +125,6 @@ test-suite libtorrent :
test_sliding_average.cpp
test_socket_io.cpp
# test_random.cpp
test_utf8.cpp
test_gzip.cpp
test_bitfield.cpp
test_part_file.cpp
@ -142,7 +141,6 @@ test-suite libtorrent :
test_bencoding.cpp
test_bdecode.cpp
test_http_parser.cpp
test_string.cpp
test_xml.cpp
test_ip_filter.cpp
test_hasher.cpp
@ -158,6 +156,10 @@ test-suite libtorrent :
test_linked_list.cpp
test_file_progress.cpp ]
[ run test_string.cpp
test_utf8.cpp
]
[ run test_receive_buffer.cpp ]
[ run test_alert_manager.cpp ]
[ run test_direct_dht.cpp ]

View File

@ -39,7 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
using namespace libtorrent;
TORRENT_TEST(string)
TORRENT_TEST(maybe_url_encode)
{
// test maybe_url_encode
TEST_EQUAL(maybe_url_encode("http://test:test@abc.com/abc<>abc"), "http://test:test@abc.com/abc%3c%3eabc");
@ -48,10 +48,11 @@ TORRENT_TEST(string)
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";
TORRENT_TEST(hex)
{
static char const str[] = "0123456789012345678901234567890123456789";
char bin[20];
TEST_CHECK(aux::from_hex(str, 40, bin));
char hex[41];
@ -61,8 +62,26 @@ TORRENT_TEST(string)
TEST_CHECK(aux::to_hex("\x55\x73") == "5573");
TEST_CHECK(aux::to_hex("\xaB\xd0") == "abd0");
// test is_space
static char const hex_chars[] = "0123456789abcdefABCDEF";
for (int i = 1; i < 255; ++i)
{
bool hex = strchr(hex_chars, i) != NULL;
char c = i;
TEST_EQUAL(aux::is_hex(&c, 1), hex);
}
TEST_EQUAL(aux::hex_to_int('0'), 0);
TEST_EQUAL(aux::hex_to_int('7'), 7);
TEST_EQUAL(aux::hex_to_int('a'), 10);
TEST_EQUAL(aux::hex_to_int('f'), 15);
TEST_EQUAL(aux::hex_to_int('b'), 11);
TEST_EQUAL(aux::hex_to_int('t'), -1);
TEST_EQUAL(aux::hex_to_int('g'), -1);
}
TORRENT_TEST(is_space)
{
TEST_CHECK(!is_space('C'));
TEST_CHECK(!is_space('\b'));
TEST_CHECK(!is_space('8'));
@ -71,35 +90,38 @@ TORRENT_TEST(string)
TEST_CHECK(is_space('\t'));
TEST_CHECK(is_space('\n'));
TEST_CHECK(is_space('\r'));
}
// test to_lower
TORRENT_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
TORRENT_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
TORRENT_TEST(to_string)
{
TEST_CHECK(to_string(345).data() == std::string("345"));
TEST_CHECK(to_string(-345).data() == std::string("-345"));
TEST_CHECK(to_string(0).data() == std::string("0"));
TEST_CHECK(to_string(1000000000).data() == std::string("1000000000"));
}
TORRENT_TEST(base64)
{
// base64 test vectors from http://www.faqs.org/rfcs/rfc4648.html
TEST_CHECK(base64encode("") == "");
TEST_CHECK(base64encode("f") == "Zg==");
TEST_CHECK(base64encode("fo") == "Zm8=");
@ -107,44 +129,50 @@ TORRENT_TEST(string)
TEST_CHECK(base64encode("foob") == "Zm9vYg==");
TEST_CHECK(base64encode("fooba") == "Zm9vYmE=");
TEST_CHECK(base64encode("foobar") == "Zm9vYmFy");
}
TORRENT_TEST(base32)
{
// 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(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======");
// base32 for i2p
TEST_CHECK(base32encode("fo", string::no_padding) == "MZXQ");
TEST_CHECK(base32encode("foob", string::i2p) == "mzxw6yq");
TEST_CHECK(base32encode("foobar", string::lowercase) == "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("") == "");
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");
TEST_CHECK(base32decode("MY") == "f");
TEST_CHECK(base32decode("MZXW6YQ") == "foob");
TEST_CHECK(base32decode("MZXW6YTBOI") == "foobar");
TEST_CHECK(base32decode("mZXw6yTBO1======") == "foobar");
// make sure invalid encoding returns the empty string
TEST_CHECK(base32decode("mZXw6yTBO1{#&*()=") == "");
TEST_CHECK(base32decode("mZXw6yTBO1{#&*()=") == "");
std::string test;
for (int i = 0; i < 255; ++i)
test += char(i);
TEST_CHECK(base32decode(base32encode(test)) == test);
}
TORRENT_TEST(escape_string)
{
// escape_string
char const* test_string = "!@#$%^&*()-_=+/,. %?";
TEST_EQUAL(escape_string(test_string, int(strlen(test_string)))
@ -189,40 +217,20 @@ TORRENT_TEST(string)
ec.clear();
TEST_CHECK(unescape_string("123+abc", ec) == "123 abc");
}
// read_until
TORRENT_TEST(read_until)
{
char const* test_string1 = "abcdesdf sdgf";
char const* tmp1 = test_string1;
TEST_CHECK(read_until(tmp1, 'd', test_string1 + strlen(test_string1)) == "abc");
tmp1 = test_string1;
TEST_CHECK(read_until(tmp1, '[', test_string1 + strlen(test_string1)) == "abcdesdf sdgf");
}
char hex_chars[] = "0123456789abcdefABCDEF";
for (int i = 1; i < 255; ++i)
{
bool hex = strchr(hex_chars, i) != NULL;
char c = i;
TEST_EQUAL(aux::is_hex(&c, 1), hex);
}
TEST_EQUAL(aux::hex_to_int('0'), 0);
TEST_EQUAL(aux::hex_to_int('7'), 7);
TEST_EQUAL(aux::hex_to_int('a'), 10);
TEST_EQUAL(aux::hex_to_int('f'), 15);
TEST_EQUAL(aux::hex_to_int('b'), 11);
TEST_EQUAL(aux::hex_to_int('t'), -1);
TEST_EQUAL(aux::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
TORRENT_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");
@ -231,6 +239,13 @@ TORRENT_TEST(string)
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") == "");
}
TORRENT_TEST(path)
{
std::string path = "a\\b\\c";
convert_path_to_posix(path);
TEST_EQUAL(path, "a/b/c");
// resolve_file_url
@ -245,7 +260,27 @@ TORRENT_TEST(string)
TEST_EQUAL(resolve_file_url("file:///c/blah/foo/bar"), "/c/blah/foo/bar");
TEST_EQUAL(resolve_file_url("file:///c/b%3fah/foo/bar"), "/c/b?ah/foo/bar");
#endif
}
void test_parse_interface(char const* input
, std::vector<listen_interface_t> expected
, std::string output)
{
std::fprintf(stderr, "parse interface: %s\n", input);
std::vector<listen_interface_t> list;
parse_listen_interfaces(input, list);
TEST_EQUAL(list.size(), expected.size());
if (list.size() == expected.size())
{
TEST_CHECK(std::equal(list.begin(), list.end(), expected.begin()
, [&](listen_interface_t const& lhs, listen_interface_t const& rhs)
{ return lhs.device == rhs.device && lhs.port == rhs.port && lhs.ssl == rhs.ssl; }));
}
TEST_EQUAL(print_listen_interfaces(list), output);
}
TORRENT_TEST(parse_list)
{
std::vector<std::string> list;
parse_comma_separated_string(" a,b, c, d ,e \t,foobar\n\r,[::1]", list);
TEST_EQUAL(list.size(), 7);
@ -257,37 +292,48 @@ TORRENT_TEST(string)
TEST_EQUAL(list[5], "foobar");
TEST_EQUAL(list[6], "[::1]");
std::vector<listen_interface_t> list2;
parse_listen_interfaces(" a:4,b:35, c : 1000s, d: 351 ,e \t:42,foobar:1337s\n\r,[2001::1]:6881", list2);
TEST_EQUAL(list2.size(), 7);
TEST_EQUAL(list2[0].device, "a");
TEST_EQUAL(list2[1].device, "b");
TEST_EQUAL(list2[2].device, "c");
TEST_EQUAL(list2[3].device, "d");
TEST_EQUAL(list2[4].device, "e");
TEST_EQUAL(list2[5].device, "foobar");
TEST_EQUAL(list2[6].device, "2001::1");
#if TORRENT_USE_IPV6
test_parse_interface(" a:4,b:35, c : 1000s, d: 351 ,e \t:42,foobar:1337s\n\r,[2001::1]:6881"
, {{"a", 4, false}, {"b", 35, false}, {"c", 1000, true}, {"d", 351, false}
, {"e", 42, false}, {"foobar", 1337, true}, {"2001::1", 6881, false}}
, "a:4,b:35,c:1000s,d:351,e:42,foobar:1337s,[2001::1]:6881");
#else
test_parse_interface(" a:4,b:35, c : 1000s, d: 351 ,e \t:42,foobar:1337s\n\r,[2001::1]:6881"
, {{"a", 4, false}, {"b", 35, false}, {"c", 1000, true}, {"d", 351, false}
, {"e", 42, false}, {"foobar", 1337, true}}
, "a:4,b:35,c:1000s,d:351,e:42,foobar:1337s");
#endif
TEST_EQUAL(list2[0].port, 4);
TEST_EQUAL(list2[1].port, 35);
TEST_EQUAL(list2[2].port, 1000);
TEST_EQUAL(list2[3].port, 351);
TEST_EQUAL(list2[4].port, 42);
TEST_EQUAL(list2[5].port, 1337);
TEST_EQUAL(list2[6].port, 6881);
// IPv6 address
#if TORRENT_USE_IPV6
test_parse_interface("[2001:ffff::1]:6882s"
, {{"2001:ffff::1", 6882, true}}
, "[2001:ffff::1]:6882s");
#else
test_parse_interface("[2001:ffff::1]:6882s", {}, "");
#endif
TEST_EQUAL(list2[0].ssl, false);
TEST_EQUAL(list2[1].ssl, false);
TEST_EQUAL(list2[2].ssl, true);
TEST_EQUAL(list2[3].ssl, false);
TEST_EQUAL(list2[4].ssl, false);
TEST_EQUAL(list2[5].ssl, true);
TEST_EQUAL(list2[6].ssl, false);
// IPv4 address
test_parse_interface("127.0.0.1:6882"
, {{"127.0.0.1", 6882, false}}
, "127.0.0.1:6882");
TEST_EQUAL(print_listen_interfaces(list2), "a:4,b:35,c:1000s,d:351,e:42,foobar:1337s,[2001::1]:6881");
// maximum padding
test_parse_interface(" nic\r\n:\t 12\r s "
, {{"nic", 12, true}}
, "nic:12s");
// test string_tokenize
// negative tests
test_parse_interface("nic:99999999999999999999999", {}, "");
test_parse_interface("nic: -3", {}, "");
test_parse_interface("nic: ", {}, "");
test_parse_interface("nic :", {}, "");
test_parse_interface("nic ", {}, "");
test_parse_interface("nic s", {}, "");
}
TORRENT_TEST(tokenize)
{
char test_tokenize[] = "a b c \"foo bar\" d\ne f";
char* next = test_tokenize;
char* ptr = string_tokenize(next, ' ', &next);