diff --git a/include/libtorrent/escape_string.hpp b/include/libtorrent/escape_string.hpp index 6e65a827d..f818f3bc8 100644 --- a/include/libtorrent/escape_string.hpp +++ b/include/libtorrent/escape_string.hpp @@ -61,6 +61,8 @@ namespace libtorrent // it will be encoded std::string TORRENT_EXPORT maybe_url_encode(std::string const& url); + bool TORRENT_EXPORT need_encoding(char const* str, int len); + // encodes a string using the base64 scheme TORRENT_EXPORT std::string base64encode(std::string const& s); TORRENT_EXPORT std::string base64decode(std::string const& s); diff --git a/src/escape_string.cpp b/src/escape_string.cpp index f8c117ff3..34f192f67 100644 --- a/src/escape_string.cpp +++ b/src/escape_string.cpp @@ -179,10 +179,19 @@ namespace libtorrent // http://www.ietf.org/rfc/rfc2396.txt // section 2.3 - // some trackers seems to require that ' is escaped - static const char unreserved_chars[] = "%'/-_.!~*()" + static const char unreserved_chars[] = + // when determining if a url needs encoding + // % should be ok + "%+" + // reserved + ";?:@=&/" + // unreserved (special characters) ' excluded, + // since some buggy trackers fail with those + "$-_.!~*()," + // unreserved (alphanumerics) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789"; + static const char hex_chars[] = "0123456789abcdef"; // the offset is used to ignore the first characters in the unreserved_chars table. @@ -213,15 +222,15 @@ namespace libtorrent std::string escape_string(const char* str, int len) { - return escape_string_impl(str, len, 3); + return escape_string_impl(str, len, 9); } std::string escape_path(const char* str, int len) { - return escape_string_impl(str, len, 2); + return escape_string_impl(str, len, 8); } - static bool need_encoding(char const* str, int len) + bool need_encoding(char const* str, int len) { for (int i = 0; i < len; ++i) { diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index a2bbb0e6e..2a7739221 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -519,6 +519,31 @@ int test_main() 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_CHECK(escape_string(test_string, strlen(test_string)) + == "!%40%23$%25%5e%26*()-_%3d%2b%2f,.%20%25%3f"); + + // escape_path + TEST_CHECK(escape_path(test_string, strlen(test_string)) + == "!%40%23$%25%5e%26*()-_%3d%2b/,.%20%25%3f"); + + // 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_CHECK(maybe_url_encode("http://bla.com/\n") == "http://bla.com:80/%0a"); + std::cerr << maybe_url_encode("http://bla.com/\n") << std::endl; + TEST_CHECK(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; + // HTTP request parser http_parser parser;