2022-01-20 18:27:56 +00:00
|
|
|
|
// This file Copyright (C) 2013-2022 Mnemosyne LLC.
|
2022-08-08 18:05:39 +00:00
|
|
|
|
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
2022-01-20 18:27:56 +00:00
|
|
|
|
// or any future license endorsed by Mnemosyne LLC.
|
|
|
|
|
// License text can be found in the licenses/ folder.
|
2021-12-25 21:21:13 +00:00
|
|
|
|
|
|
|
|
|
#include <array>
|
2023-07-08 15:24:03 +00:00
|
|
|
|
#include <cerrno>
|
|
|
|
|
#include <cstddef> // size_t
|
2021-12-25 21:21:13 +00:00
|
|
|
|
#include <string_view>
|
2023-07-08 15:24:03 +00:00
|
|
|
|
#include <vector>
|
2021-12-25 21:21:13 +00:00
|
|
|
|
|
2023-01-02 16:23:51 +00:00
|
|
|
|
#include <libtransmission/transmission.h>
|
|
|
|
|
|
|
|
|
|
#include <libtransmission/crypto-utils.h>
|
|
|
|
|
#include <libtransmission/error.h>
|
2023-07-08 15:24:03 +00:00
|
|
|
|
#include <libtransmission/file.h>
|
|
|
|
|
#include <libtransmission/log.h>
|
2023-01-02 16:23:51 +00:00
|
|
|
|
#include <libtransmission/torrent-metainfo.h>
|
|
|
|
|
#include <libtransmission/torrent.h>
|
|
|
|
|
#include <libtransmission/tr-strbuf.h>
|
|
|
|
|
#include <libtransmission/utils.h>
|
2021-12-25 21:21:13 +00:00
|
|
|
|
|
2023-07-08 15:24:03 +00:00
|
|
|
|
#include "gtest/gtest.h"
|
2021-12-26 16:25:07 +00:00
|
|
|
|
#include "test-fixtures.h"
|
2021-12-25 21:21:13 +00:00
|
|
|
|
|
|
|
|
|
using namespace std::literals;
|
|
|
|
|
|
2022-11-14 20:16:29 +00:00
|
|
|
|
namespace libtransmission::test
|
2021-12-26 16:25:07 +00:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
using TorrentMetainfoTest = SessionTest;
|
|
|
|
|
|
|
|
|
|
TEST_F(TorrentMetainfoTest, magnetLink)
|
2021-12-25 21:21:13 +00:00
|
|
|
|
{
|
|
|
|
|
// background info @ http://wiki.theory.org/BitTorrent_Magnet-URI_Webseeding
|
2022-08-21 13:43:09 +00:00
|
|
|
|
auto constexpr MagnetLink =
|
2021-12-25 21:21:13 +00:00
|
|
|
|
"magnet:?"
|
|
|
|
|
"xt=urn:btih:14ffe5dd23188fd5cb53a1d47f1289db70abf31e"
|
|
|
|
|
"&dn=ubuntu_12_04_1_desktop_32_bit"
|
|
|
|
|
"&tr=http%3A%2F%2Ftracker.publicbt.com%2Fannounce"
|
|
|
|
|
"&tr=udp%3A%2F%2Ftracker.publicbt.com%3A80"
|
2022-08-21 13:43:09 +00:00
|
|
|
|
"&ws=http%3A%2F%2Ftransmissionbt.com"sv;
|
2021-12-25 21:21:13 +00:00
|
|
|
|
|
|
|
|
|
auto metainfo = tr_torrent_metainfo{};
|
|
|
|
|
EXPECT_TRUE(metainfo.parseMagnet(MagnetLink));
|
2023-04-23 01:25:55 +00:00
|
|
|
|
EXPECT_EQ(0U, metainfo.file_count()); // because it's a magnet link
|
|
|
|
|
EXPECT_EQ(2U, std::size(metainfo.announce_list()));
|
2023-08-30 02:58:31 +00:00
|
|
|
|
EXPECT_EQ(MagnetLink, metainfo.magnet());
|
2021-12-25 21:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define BEFORE_PATH \
|
|
|
|
|
"d10:created by25:Transmission/2.82 (14160)13:creation datei1402280218e8:encoding5:UTF-84:infod5:filesld6:lengthi2e4:pathl"
|
|
|
|
|
#define AFTER_PATH \
|
|
|
|
|
"eed6:lengthi2e4:pathl5:b.txteee4:name3:foo12:piece lengthi32768e6:pieces20:ÞÉ`âMs¡Å;˺¬.åÂà7:privatei0eee"
|
|
|
|
|
|
|
|
|
|
// FIXME: split these into parameterized tests?
|
2021-12-26 16:25:07 +00:00
|
|
|
|
TEST_F(TorrentMetainfoTest, bucket)
|
2021-12-25 21:21:13 +00:00
|
|
|
|
{
|
|
|
|
|
struct LocalTest
|
|
|
|
|
{
|
|
|
|
|
std::string_view benc;
|
|
|
|
|
bool expected_parse_result;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto const tests = std::array<LocalTest, 9>{ {
|
|
|
|
|
{ BEFORE_PATH "5:a.txt" AFTER_PATH, true },
|
|
|
|
|
// allow empty components, but not =all= empty components, see bug #5517
|
|
|
|
|
{ BEFORE_PATH "0:5:a.txt" AFTER_PATH, true },
|
|
|
|
|
{ BEFORE_PATH "0:0:" AFTER_PATH, false },
|
|
|
|
|
// allow path separators in a filename (replaced with '_')
|
|
|
|
|
{ BEFORE_PATH "7:a/a.txt" AFTER_PATH, true },
|
|
|
|
|
// allow "." components (skipped)
|
|
|
|
|
{ BEFORE_PATH "1:.5:a.txt" AFTER_PATH, true },
|
|
|
|
|
{ BEFORE_PATH "5:a.txt1:." AFTER_PATH, true },
|
|
|
|
|
// allow ".." components (replaced with "__")
|
|
|
|
|
{ BEFORE_PATH "2:..5:a.txt" AFTER_PATH, true },
|
|
|
|
|
{ BEFORE_PATH "5:a.txt2:.." AFTER_PATH, true },
|
|
|
|
|
// fail on empty string
|
|
|
|
|
{ "", false },
|
|
|
|
|
} };
|
|
|
|
|
|
2022-03-10 05:51:14 +00:00
|
|
|
|
tr_logSetLevel(TR_LOG_OFF);
|
2021-12-25 21:21:13 +00:00
|
|
|
|
|
|
|
|
|
for (auto const& test : tests)
|
|
|
|
|
{
|
|
|
|
|
auto metainfo = tr_torrent_metainfo{};
|
2023-04-23 01:25:55 +00:00
|
|
|
|
EXPECT_EQ(test.expected_parse_result, metainfo.parse_benc(test.benc));
|
2021-12-25 21:21:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-06 20:26:13 +00:00
|
|
|
|
TEST_F(TorrentMetainfoTest, parseBencFuzzRegressions)
|
|
|
|
|
{
|
|
|
|
|
static auto constexpr Tests = std::array<std::string_view, 1>{
|
|
|
|
|
"ZC/veNSVW0Ss+KGfMqH4DQqtYXzgmVi5oBi0XlxviLytlwwjf7MLanOcnS73eSB/iye83hVyvSWg27tPl5oqWdNEZ0euMbo7E8FH/xgTvUEOnBVgvPno50CyI7c5F2QTw16avUB7dvGzx5xIjzJ2qkD2BsNtOoiZI3skC6XwSifsDfJUN8NxHFiwvWxmZRLq2eQlE2wGxAW5aLj6U1MHDzPZ83+2o81pRyMr11bHmWFcNorTGLeOpHBd9veduHpNOKNwOatoXeb57jZCy1Zmu9y/wCuUx6DP3I5FGQ/t3AYh7w028Z/zgIlvWat6QjqSPp7j1nEbl6SNZNl1doGmusl9hvRsbaCq9b1XHpTDtQSJ8Owj07fph0p0ZVu5kJpQBfOGsHLh6ALVrTepptIvcnNW9+nauE+NJa2z+9Yla7780sCdBsGYZZA6HUr0J9GXES7+uRPPBwAl2YB1qWhCsOCClixTiAlwrsBl1bJ/a4FV04aU5jXDEYrpJMzdSAEoypDWMsn3Fc5umLqJ1jtqPqykKY0HjPrCkVAMmvmacauBzIj5Eg/uw0xtZp+wXdLQv8qyuXgsJs7dExZbgTgfPY4niTBpftM6YFQrCx/IxiMshYp7tMolykoed/8gZMm6yyWizzml4BlvnvY3+J2eVKRvS7QToRKxN5eFP9l/pflrK+8cHbwVnjQ1pE3hTQACmNIQHRTY2QoOGwG+HTwo48akfbJnjJ3F0iN6miy7lvv5u0p1rpbM2On5FJ3G98OYnzGIxf8BomHvVp/3eX6QJZUMZKsUTpgbRqg0AJH9FjiERQ9v6B25Va+Q0yV8z5DmiA5AgyIwkIzlSBAl0PYsNaw+rH06a93yBhAfK6EPSArYLjMI6o/1kF4UxNyfE+F79xbdCAKRAX3iJ7DH1GncFoIQ1fZd/uZaF9tXjViQ7P/sHuKdZvfLpvJq88JV5Pcdsfdlle86QAF4weB+k/k8f/xgvxRNbbcAfjLvEHhDBzfEvHkgFrW19WvLHyAqjjUovpecIu3KeCqwyOr1dHViUVelxqc5BklyGQ+Asd6GnWPSzO5Hamj4rYrapgogEup5PKm1j2CgL2HH2tySWwjgtOWbooGhsdBnCeQOsapCxwc6ALtudG4Q9RBu6A6pLUfFE3rm1RuvNGoJNHiEQ4BAFiqLpYJd4lR7V2fI6EIKug0dB3SpHpUeNCQbG67IM+kVe0I+vP3cECGOGXo="sv,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (auto const& test : Tests)
|
|
|
|
|
{
|
|
|
|
|
auto tm = tr_torrent_metainfo{};
|
2023-04-23 01:25:55 +00:00
|
|
|
|
tm.parse_benc(tr_base64_decode(test));
|
2022-04-06 20:26:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(TorrentMetainfoTest, parseBencFuzz)
|
|
|
|
|
{
|
|
|
|
|
auto buf = std::vector<char>{};
|
|
|
|
|
|
2022-12-21 15:58:32 +00:00
|
|
|
|
for (size_t i = 0; i < 100000U; ++i)
|
2022-04-06 20:26:13 +00:00
|
|
|
|
{
|
2022-12-21 15:58:32 +00:00
|
|
|
|
buf.resize(tr_rand_int(1024U));
|
2022-04-06 20:26:13 +00:00
|
|
|
|
tr_rand_buffer(std::data(buf), std::size(buf));
|
|
|
|
|
// std::cerr << '[' << tr_base64_encode({ std::data(buf), std::size(buf) }) << ']' << std::endl;
|
|
|
|
|
|
|
|
|
|
auto tm = tr_torrent_metainfo{};
|
2023-04-23 01:25:55 +00:00
|
|
|
|
tm.parse_benc({ std::data(buf), std::size(buf) });
|
2022-04-06 20:26:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-26 16:25:07 +00:00
|
|
|
|
TEST_F(TorrentMetainfoTest, AndroidTorrent)
|
2021-12-25 21:21:13 +00:00
|
|
|
|
{
|
2022-04-07 22:26:59 +00:00
|
|
|
|
auto const filename = tr_pathbuf{ LIBTRANSMISSION_TEST_ASSETS_DIR, "/Android-x86 8.1 r6 iso.torrent"sv };
|
2021-12-25 21:21:13 +00:00
|
|
|
|
|
2021-12-26 16:25:07 +00:00
|
|
|
|
auto* ctor = tr_ctorNew(session_);
|
2023-11-04 16:39:41 +00:00
|
|
|
|
auto error = tr_error{};
|
2021-12-26 16:25:07 +00:00
|
|
|
|
EXPECT_TRUE(tr_ctorSetMetainfoFromFile(ctor, filename.c_str(), &error));
|
2023-11-04 16:39:41 +00:00
|
|
|
|
EXPECT_FALSE(error) << error;
|
2022-01-29 21:37:42 +00:00
|
|
|
|
auto const* const metainfo = tr_ctorGetMetainfo(ctor);
|
|
|
|
|
EXPECT_NE(nullptr, metainfo);
|
2023-04-23 01:25:55 +00:00
|
|
|
|
EXPECT_EQ(336, metainfo->info_dict_offset());
|
|
|
|
|
EXPECT_EQ(26583, metainfo->info_dict_size());
|
|
|
|
|
EXPECT_EQ(592, metainfo->pieces_offset());
|
2021-12-25 21:21:13 +00:00
|
|
|
|
tr_ctorFree(ctor);
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-26 16:25:07 +00:00
|
|
|
|
TEST_F(TorrentMetainfoTest, ctorSaveContents)
|
2021-12-25 21:21:13 +00:00
|
|
|
|
{
|
2024-03-17 20:13:56 +00:00
|
|
|
|
auto const sandbox = libtransmission::test::Sandbox::create_sandbox(::testing::TempDir(), "transmission-test-XXXXXX");
|
2022-03-26 00:31:27 +00:00
|
|
|
|
auto const src_filename = tr_pathbuf{ LIBTRANSMISSION_TEST_ASSETS_DIR, "/Android-x86 8.1 r6 iso.torrent"sv };
|
2024-03-17 20:13:56 +00:00
|
|
|
|
auto const tgt_filename = tr_pathbuf{ sandbox, "save-contents-test.torrent" };
|
2021-12-25 21:21:13 +00:00
|
|
|
|
|
|
|
|
|
// try saving without passing any metainfo.
|
2021-12-26 16:25:07 +00:00
|
|
|
|
auto* ctor = tr_ctorNew(session_);
|
2023-11-04 16:39:41 +00:00
|
|
|
|
auto error = tr_error{};
|
2023-11-26 21:43:37 +00:00
|
|
|
|
EXPECT_FALSE(ctor->save(tgt_filename, &error));
|
2023-11-04 16:39:41 +00:00
|
|
|
|
EXPECT_TRUE(error);
|
|
|
|
|
EXPECT_EQ(EINVAL, error.code());
|
|
|
|
|
error = {};
|
2021-12-25 21:21:13 +00:00
|
|
|
|
|
|
|
|
|
// now try saving _with_ metainfo
|
2021-12-26 16:25:07 +00:00
|
|
|
|
EXPECT_TRUE(tr_ctorSetMetainfoFromFile(ctor, src_filename.c_str(), &error));
|
2023-11-04 16:39:41 +00:00
|
|
|
|
EXPECT_FALSE(error) << error;
|
2023-11-26 21:43:37 +00:00
|
|
|
|
EXPECT_TRUE(ctor->save(tgt_filename, &error));
|
2023-11-04 16:39:41 +00:00
|
|
|
|
EXPECT_FALSE(error) << error;
|
2021-12-25 21:21:13 +00:00
|
|
|
|
|
|
|
|
|
// the saved contents should match the source file's contents
|
|
|
|
|
auto src_contents = std::vector<char>{};
|
2023-06-30 14:49:58 +00:00
|
|
|
|
EXPECT_TRUE(tr_file_read(src_filename.sv(), src_contents, &error));
|
2021-12-25 21:21:13 +00:00
|
|
|
|
auto tgt_contents = std::vector<char>{};
|
2023-06-30 14:49:58 +00:00
|
|
|
|
EXPECT_TRUE(tr_file_read(tgt_filename.sv(), tgt_contents, &error));
|
2021-12-25 21:21:13 +00:00
|
|
|
|
EXPECT_EQ(src_contents, tgt_contents);
|
|
|
|
|
|
|
|
|
|
// cleanup
|
2022-05-22 01:17:00 +00:00
|
|
|
|
EXPECT_TRUE(tr_sys_path_remove(tgt_filename, &error));
|
2023-11-04 16:39:41 +00:00
|
|
|
|
EXPECT_FALSE(error) << error;
|
2021-12-25 21:21:13 +00:00
|
|
|
|
tr_ctorFree(ctor);
|
|
|
|
|
}
|
2021-12-26 16:25:07 +00:00
|
|
|
|
|
2023-02-13 00:10:54 +00:00
|
|
|
|
TEST_F(TorrentMetainfoTest, magnetInfoHash)
|
|
|
|
|
{
|
|
|
|
|
// compatibility with magnet torrents created by Transmission <= 3.0
|
|
|
|
|
auto const src_filename = tr_pathbuf{ LIBTRANSMISSION_TEST_ASSETS_DIR, "/gimp-2.10.32-1-arm64.dmg.torrent"sv };
|
|
|
|
|
auto tm = tr_torrent_metainfo{};
|
2023-04-23 01:25:55 +00:00
|
|
|
|
EXPECT_TRUE(tm.parse_torrent_file(src_filename));
|
2023-02-13 00:10:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-24 04:05:16 +00:00
|
|
|
|
TEST_F(TorrentMetainfoTest, HoffmanStyleWebseeds)
|
|
|
|
|
{
|
|
|
|
|
auto const src_filename = tr_pathbuf{ LIBTRANSMISSION_TEST_ASSETS_DIR, "/debian-11.2.0-amd64-DVD-1.iso.torrent"sv };
|
|
|
|
|
auto tm = tr_torrent_metainfo{};
|
2023-04-23 01:25:55 +00:00
|
|
|
|
EXPECT_TRUE(tm.parse_torrent_file(src_filename));
|
|
|
|
|
EXPECT_EQ(size_t{ 2 }, tm.webseed_count());
|
2022-05-24 04:05:16 +00:00
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
"https://cdimage.debian.org/cdimage/release/11.2.0//srv/cdbuilder.debian.org/dst/deb-cd/weekly-builds/amd64/iso-dvd/debian-11.2.0-amd64-DVD-1.iso"sv,
|
|
|
|
|
tm.webseed(0));
|
|
|
|
|
EXPECT_EQ(
|
|
|
|
|
"https://cdimage.debian.org/cdimage/archive/11.2.0//srv/cdbuilder.debian.org/dst/deb-cd/weekly-builds/amd64/iso-dvd/debian-11.2.0-amd64-DVD-1.iso"sv,
|
|
|
|
|
tm.webseed(1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(TorrentMetainfoTest, GetRightStyleWebseedList)
|
|
|
|
|
{
|
|
|
|
|
auto const src_filename = tr_pathbuf{ LIBTRANSMISSION_TEST_ASSETS_DIR, "/webseed-getright-list.torrent"sv };
|
|
|
|
|
auto tm = tr_torrent_metainfo{};
|
2023-04-23 01:25:55 +00:00
|
|
|
|
EXPECT_TRUE(tm.parse_torrent_file(src_filename));
|
|
|
|
|
EXPECT_EQ(size_t{ 2 }, tm.webseed_count());
|
2022-05-24 04:05:16 +00:00
|
|
|
|
EXPECT_EQ("http://www.webseed-one.com/"sv, tm.webseed(0));
|
|
|
|
|
EXPECT_EQ("http://webseed-two.com/"sv, tm.webseed(1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(TorrentMetainfoTest, GetRightStyleWebseedString)
|
|
|
|
|
{
|
|
|
|
|
auto const src_filename = tr_pathbuf{ LIBTRANSMISSION_TEST_ASSETS_DIR, "/webseed-getright-string.torrent"sv };
|
|
|
|
|
auto tm = tr_torrent_metainfo{};
|
2023-04-23 01:25:55 +00:00
|
|
|
|
EXPECT_TRUE(tm.parse_torrent_file(src_filename));
|
|
|
|
|
EXPECT_EQ(size_t{ 1 }, tm.webseed_count());
|
2022-05-24 04:05:16 +00:00
|
|
|
|
EXPECT_EQ("http://www.webseed-one.com/"sv, tm.webseed(0));
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-09 22:04:56 +00:00
|
|
|
|
// Test for https://github.com/transmission/transmission/issues/3591
|
|
|
|
|
TEST_F(TorrentMetainfoTest, parseBencOOBWrite)
|
|
|
|
|
{
|
|
|
|
|
auto tm = tr_torrent_metainfo{};
|
2023-04-23 01:25:55 +00:00
|
|
|
|
EXPECT_FALSE(tm.parse_benc(tr_base64_decode("ZGg0OmluZm9kNjpwaWVjZXMzOkFpzQ==")));
|
2022-08-09 22:04:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-14 20:16:29 +00:00
|
|
|
|
} // namespace libtransmission::test
|