From f5fc2d52b85df87a7024607e12527d59f02a590b Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Tue, 20 Feb 2018 01:02:57 +0800 Subject: [PATCH] Fix loading very large torrents. Closes #8449. `torrent_info` constructor has default limits that can't be changed via parameters, so we handle the loading process manually and explicitly specifiy the limits to `bdecode()`. The token_limit is also changed to 10000000. --- src/base/bittorrent/torrentinfo.cpp | 48 ++++++++++++++++++++++++++--- src/base/bittorrent/torrentinfo.h | 3 ++ 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/base/bittorrent/torrentinfo.cpp b/src/base/bittorrent/torrentinfo.cpp index 950d772c3..825c8c078 100644 --- a/src/base/bittorrent/torrentinfo.cpp +++ b/src/base/bittorrent/torrentinfo.cpp @@ -76,13 +76,51 @@ TorrentInfo TorrentInfo::load(const QByteArray &data, QString *error) noexcept TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString *error) noexcept { + if (error) + error->clear(); + + QFile file {path}; + if (!file.open(QIODevice::ReadOnly)) { + if (error) + *error = file.errorString(); + return TorrentInfo(); + } + + const qint64 fileSizeLimit = 100 * 1024 * 1024; // 100 MB + if (file.size() > fileSizeLimit) { + if (error) + *error = tr("File size exceeds max limit %1").arg(fileSizeLimit); + return TorrentInfo(); + } + + const QByteArray data = file.read(fileSizeLimit); + if (data.size() != file.size()) { + if (error) + *error = tr("Torrent file read error"); + return TorrentInfo(); + } + + file.close(); + + // 2-step construction to overcome default limits of `depth_limit` & `token_limit` which are + // used in `torrent_info()` constructor + const int depthLimit = 100; + const int tokenLimit = 10000000; + libt::bdecode_node node; libt::error_code ec; - TorrentInfo info(NativePtr(new libt::torrent_info(Utils::Fs::toNativePath(path).toStdString(), ec))); - if (error) { - if (ec) + bdecode(data.constData(), (data.constData() + data.size()), node, ec + , nullptr, depthLimit, tokenLimit); + if (ec) { + if (error) *error = QString::fromStdString(ec.message()); - else - error->clear(); + return TorrentInfo(); + } + + TorrentInfo info {NativePtr(new libt::torrent_info(node, ec))}; + if (ec) { + if (error) + *error = QString::fromStdString(ec.message()); + return TorrentInfo(); } return info; diff --git a/src/base/bittorrent/torrentinfo.h b/src/base/bittorrent/torrentinfo.h index cb40c3927..85c8158d5 100644 --- a/src/base/bittorrent/torrentinfo.h +++ b/src/base/bittorrent/torrentinfo.h @@ -29,6 +29,7 @@ #ifndef BITTORRENT_TORRENTINFO_H #define BITTORRENT_TORRENTINFO_H +#include #include #include @@ -51,6 +52,8 @@ namespace BitTorrent class TorrentInfo { + Q_DECLARE_TR_FUNCTIONS("TorrentInfo") + public: #if LIBTORRENT_VERSION_NUM < 10100 typedef boost::intrusive_ptr NativeConstPtr;