diff --git a/ChangeLog b/ChangeLog index ab68f0d1e..7b1f599a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -26,6 +26,9 @@ * fix uTP edge case where udp socket buffer fills up * fix nagle implementation in uTP + * deduplicate web seed entries from torrent files + * improve error reporting from lazy_decode() + 0.16.13 release * fix auto-manage issue when pausing session diff --git a/examples/dump_torrent.cpp b/examples/dump_torrent.cpp index af60264c8..a70c3891f 100644 --- a/examples/dump_torrent.cpp +++ b/examples/dump_torrent.cpp @@ -267,7 +267,7 @@ int main(int argc, char* argv[]) return 1; } lazy_entry e; - int pos; + int pos = -1; printf("decoding. recursion limit: %d total item count limit: %d\n" , depth_limit, item_limit); ret = lazy_bdecode(&buf[0], &buf[0] + buf.size(), e, ec, &pos diff --git a/src/lazy_bdecode.cpp b/src/lazy_bdecode.cpp index b0a40c0d9..6a843fbd0 100644 --- a/src/lazy_bdecode.cpp +++ b/src/lazy_bdecode.cpp @@ -61,15 +61,22 @@ namespace libtorrent // first occurance of the delimiter is interpreted as an int. // return the pointer to the delimiter, or 0 if there is a // parse error. val should be initialized to zero - char const* parse_int(char const* start, char const* end, char delimiter, boost::int64_t& val) + char const* parse_int(char const* start, char const* end, char delimiter + , boost::int64_t& val, bdecode_errors::error_code_enum& ec) { while (start < end && *start != delimiter) { - if (!numeric(*start)) { return 0; } + if (!numeric(*start)) + { + ec = bdecode_errors::expected_string; + return start; + } val *= 10; val += *start - '0'; ++start; } + if (*start != delimiter) + ec = bdecode_errors::expected_colon; return start; } @@ -124,9 +131,14 @@ namespace libtorrent } if (!numeric(t)) TORRENT_FAIL_BDECODE(bdecode_errors::expected_string); boost::int64_t len = t - '0'; - start = parse_int(start, end, ':', len); - if (start == 0 || start + len + 3 > end || *start != ':') - TORRENT_FAIL_BDECODE(bdecode_errors::expected_colon); + bdecode_errors::error_code_enum e = bdecode_errors::no_error; + start = parse_int(start, end, ':', len, e); + if (e) + TORRENT_FAIL_BDECODE(e); + + if (start + len + 1 > end) + TORRENT_FAIL_BDECODE(errors::unexpected_eof); + ++start; if (start == end) TORRENT_FAIL_BDECODE(bdecode_errors::unexpected_eof); lazy_entry* ent = top->dict_append(start); @@ -183,9 +195,12 @@ namespace libtorrent TORRENT_FAIL_BDECODE(bdecode_errors::expected_value); boost::int64_t len = t - '0'; - start = parse_int(start, end, ':', len); - if (start == 0 || start + len + 1 > end || *start != ':') - TORRENT_FAIL_BDECODE(bdecode_errors::expected_colon); + bdecode_errors::error_code_enum e = bdecode_errors::no_error; + start = parse_int(start, end, ':', len, e); + if (e) + TORRENT_FAIL_BDECODE(e); + if (start + len + 1 > end) + TORRENT_FAIL_BDECODE(errors::unexpected_eof); ++start; top->construct_string(start, int(len)); stack.pop_back(); @@ -204,7 +219,10 @@ namespace libtorrent boost::int64_t val = 0; bool negative = false; if (*m_data.start == '-') negative = true; - parse_int(negative?m_data.start+1:m_data.start, m_data.start + m_size, 'e', val); + bdecode_errors::error_code_enum ec = bdecode_errors::no_error; + parse_int(negative?m_data.start+1:m_data.start + , m_data.start + m_size, 'e', val, ec); + TORRENT_ASSERT(!ec); if (negative) val = -val; return val; } diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 5bd1a135a..89f4c71f7 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -1280,6 +1280,8 @@ namespace libtorrent } else if (url_seeds && url_seeds->type() == lazy_entry::list_t) { + // only add a URL once + std::set unique; for (int i = 0, end(url_seeds->list_size()); i < end; ++i) { lazy_entry const* url = url_seeds->list_at(i); @@ -1288,6 +1290,8 @@ namespace libtorrent web_seed_entry ent(maybe_url_encode(url->string_value()) , web_seed_entry::url_seed); if (m_multifile && ent.url[ent.url.size()-1] != '/') ent.url += '/'; + if (unique.count(ent.url)) continue; + unique.insert(ent.url); m_web_seeds.push_back(ent); } } @@ -1301,12 +1305,16 @@ namespace libtorrent } else if (http_seeds && http_seeds->type() == lazy_entry::list_t) { + // only add a URL once + std::set unique; for (int i = 0, end(http_seeds->list_size()); i < end; ++i) { lazy_entry const* url = http_seeds->list_at(i); if (url->type() != lazy_entry::string_t || url->string_length() == 0) continue; - m_web_seeds.push_back(web_seed_entry(maybe_url_encode(url->string_value()) - , web_seed_entry::http_seed)); + std::string u = maybe_url_encode(url->string_value()); + if (unique.count(u)) continue; + unique.insert(u); + m_web_seeds.push_back(web_seed_entry(u, web_seed_entry::http_seed)); } } diff --git a/test/Makefile.am b/test/Makefile.am index 9fd33941e..bc2cdac9e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -52,7 +52,6 @@ TESTS = $(check_PROGRAMS) EXTRA_DIST = Jamfile \ test_torrents/base.torrent \ - test_torrents/empty_path.torrent \ test_torrents/parent_path.torrent \ test_torrents/hidden_parent_path.torrent \ test_torrents/single_multi_file.torrent \ @@ -91,6 +90,8 @@ EXTRA_DIST = Jamfile \ test_torrents/invalid_root_hash2.torrent \ test_torrents/root_hash.torrent \ test_torrents/invalid_file_size.torrent \ + test_torrents/empty_path_multi.torrent \ + test_torrents/duplicate_web_seeds.torrent \ eztv.xml \ kat.xml \ cb.xml \ diff --git a/test/test_torrent_parse.cpp b/test/test_torrent_parse.cpp index 5ab9bae3c..09bfacf7e 100644 --- a/test/test_torrent_parse.cpp +++ b/test/test_torrent_parse.cpp @@ -72,6 +72,7 @@ test_torrent_t test_torrents[] = { "url_seed_multi_space_nolist.torrent" }, { "root_hash.torrent" }, { "empty_path_multi.torrent" }, + { "duplicate_web_seeds.torrent" }, { "invalid_name3.torrent" }, }; @@ -382,12 +383,16 @@ int test_main() else if (std::string(test_torrents[i].file) == "pad_file.torrent") { TEST_EQUAL(ti->num_files(), 2); - TEST_CHECK(ti->file_at(0).pad_file == false); - TEST_CHECK(ti->file_at(1).pad_file == true); + TEST_EQUAL(ti->file_at(0).pad_file, false); + TEST_EQUAL(ti->file_at(1).pad_file, true); } else if (std::string(test_torrents[i].file) == "creation_date.torrent") { - TEST_CHECK(*ti->creation_date() == 1234567); + TEST_EQUAL(*ti->creation_date(), 1234567); + } + else if (std::string(test_torrents[i].file) == "duplicate_web_seeds.torrent") + { + TEST_EQUAL(ti->web_seeds().size(), 3); } else if (std::string(test_torrents[i].file) == "no_creation_date.torrent") { diff --git a/test/test_torrents/duplicate_web_seeds.torrent b/test/test_torrents/duplicate_web_seeds.torrent new file mode 100644 index 000000000..8a5d8a6f1 --- /dev/null +++ b/test/test_torrents/duplicate_web_seeds.torrent @@ -0,0 +1 @@ +d8:announce23:udp://test.com/announce10:created by10:libtorrent13:creation datei1359599503e4:infod6:lengthi425e4:name4:temp12:piece lengthi16384e6:pieces20:‚ž¼Œ&¾ÇJW›}ÜA4u,·¼‘‡e8:url-listl21:http://foobar.com/foo21:http://foobar.com/foo21:http://foobar.com/foo24:http://foobar.com/foobar21:http://foobar.com/foo21:http://foobar.com/foo21:http://foobar.com/foo21:http://foobar.com/baree