Browse Source

Expose 'bdecode limits' settings

This includes:
* Bdecode depth limit
* Bdecode token limit
adaptive-webui-19844
Chocobo1 1 year ago
parent
commit
5a660fc8a9
No known key found for this signature in database
GPG Key ID: 210D9C873253A68C
  1. 8
      src/base/bittorrent/bencoderesumedatastorage.cpp
  2. 3
      src/base/bittorrent/common.h
  3. 9
      src/base/bittorrent/dbresumedatastorage.cpp
  4. 4
      src/base/bittorrent/sessionimpl.cpp
  5. 5
      src/base/bittorrent/torrentinfo.cpp
  6. 26
      src/base/preferences.cpp
  7. 4
      src/base/preferences.h
  8. 18
      src/gui/advancedsettings.cpp
  9. 2
      src/gui/advancedsettings.h
  10. 10
      src/webui/api/appcontroller.cpp
  11. 2
      src/webui/webapplication.h
  12. 20
      src/webui/www/private/views/preferences.html

8
src/base/bittorrent/bencoderesumedatastorage.cpp

@ -50,7 +50,6 @@
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "base/utils/io.h" #include "base/utils/io.h"
#include "base/utils/string.h" #include "base/utils/string.h"
#include "common.h"
#include "infohash.h" #include "infohash.h"
#include "loadtorrentparams.h" #include "loadtorrentparams.h"
@ -203,9 +202,11 @@ void BitTorrent::BencodeResumeDataStorage::loadQueue(const Path &queueFilename)
BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorrentResumeData(const QByteArray &data, const QByteArray &metadata) const BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorrentResumeData(const QByteArray &data, const QByteArray &metadata) const
{ {
const auto *pref = Preferences::instance();
lt::error_code ec; lt::error_code ec;
const lt::bdecode_node resumeDataRoot = lt::bdecode(data, ec const lt::bdecode_node resumeDataRoot = lt::bdecode(data, ec
, nullptr, BENCODE_DEPTH_LIMIT, BENCODE_TOKEN_LIMIT); , nullptr, pref->getBdecodeDepthLimit(), pref->getBdecodeTokenLimit());
if (ec) if (ec)
return nonstd::make_unexpected(tr("Cannot parse resume data: %1").arg(QString::fromStdString(ec.message()))); return nonstd::make_unexpected(tr("Cannot parse resume data: %1").arg(QString::fromStdString(ec.message())));
@ -272,8 +273,9 @@ BitTorrent::LoadResumeDataResult BitTorrent::BencodeResumeDataStorage::loadTorre
if (!metadata.isEmpty()) if (!metadata.isEmpty())
{ {
const auto *pref = Preferences::instance();
const lt::bdecode_node torentInfoRoot = lt::bdecode(metadata, ec const lt::bdecode_node torentInfoRoot = lt::bdecode(metadata, ec
, nullptr, BENCODE_DEPTH_LIMIT, BENCODE_TOKEN_LIMIT); , nullptr, pref->getBdecodeDepthLimit(), pref->getBdecodeTokenLimit());
if (ec) if (ec)
return nonstd::make_unexpected(tr("Cannot parse torrent info: %1").arg(QString::fromStdString(ec.message()))); return nonstd::make_unexpected(tr("Cannot parse torrent info: %1").arg(QString::fromStdString(ec.message())));

3
src/base/bittorrent/common.h

@ -33,6 +33,3 @@
#include "base/global.h" #include "base/global.h"
inline const QString QB_EXT = u".!qB"_s; inline const QString QB_EXT = u".!qB"_s;
inline const int BENCODE_DEPTH_LIMIT = 100;
inline const int BENCODE_TOKEN_LIMIT = 10'000'000;

9
src/base/bittorrent/dbresumedatastorage.cpp

@ -55,10 +55,10 @@
#include "base/global.h" #include "base/global.h"
#include "base/logger.h" #include "base/logger.h"
#include "base/path.h" #include "base/path.h"
#include "base/preferences.h"
#include "base/profile.h" #include "base/profile.h"
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "base/utils/string.h" #include "base/utils/string.h"
#include "common.h"
#include "infohash.h" #include "infohash.h"
#include "loadtorrentparams.h" #include "loadtorrentparams.h"
@ -246,10 +246,13 @@ namespace
} }
const QByteArray bencodedResumeData = query.value(DB_COLUMN_RESUMEDATA.name).toByteArray(); const QByteArray bencodedResumeData = query.value(DB_COLUMN_RESUMEDATA.name).toByteArray();
const auto *pref = Preferences::instance();
const int bdecodeDepthLimit = pref->getBdecodeDepthLimit();
const int bdecodeTokenLimit = pref->getBdecodeTokenLimit();
lt::error_code ec; lt::error_code ec;
const lt::bdecode_node resumeDataRoot = lt::bdecode(bencodedResumeData, ec const lt::bdecode_node resumeDataRoot = lt::bdecode(bencodedResumeData, ec
, nullptr, BENCODE_DEPTH_LIMIT, BENCODE_TOKEN_LIMIT); , nullptr, bdecodeDepthLimit, bdecodeTokenLimit);
lt::add_torrent_params &p = resumeData.ltAddTorrentParams; lt::add_torrent_params &p = resumeData.ltAddTorrentParams;
@ -259,7 +262,7 @@ namespace
; !bencodedMetadata.isEmpty()) ; !bencodedMetadata.isEmpty())
{ {
const lt::bdecode_node torentInfoRoot = lt::bdecode(bencodedMetadata, ec const lt::bdecode_node torentInfoRoot = lt::bdecode(bencodedMetadata, ec
, nullptr, BENCODE_DEPTH_LIMIT, BENCODE_TOKEN_LIMIT); , nullptr, bdecodeDepthLimit, bdecodeTokenLimit);
p.ti = std::make_shared<lt::torrent_info>(torentInfoRoot, ec); p.ti = std::make_shared<lt::torrent_info>(torentInfoRoot, ec);
} }

4
src/base/bittorrent/sessionimpl.cpp

@ -1740,6 +1740,10 @@ lt::settings_pack SessionImpl::loadLTSettings() const
settingsPack.set_int(lt::settings_pack::max_out_request_queue, requestQueueSize()); settingsPack.set_int(lt::settings_pack::max_out_request_queue, requestQueueSize());
#ifdef QBT_USES_LIBTORRENT2
settingsPack.set_int(lt::settings_pack::metadata_token_limit, Preferences::instance()->getBdecodeTokenLimit());
#endif
settingsPack.set_int(lt::settings_pack::aio_threads, asyncIOThreads()); settingsPack.set_int(lt::settings_pack::aio_threads, asyncIOThreads());
#ifdef QBT_USES_LIBTORRENT2 #ifdef QBT_USES_LIBTORRENT2
settingsPack.set_int(lt::settings_pack::hashing_threads, hashingThreads()); settingsPack.set_int(lt::settings_pack::hashing_threads, hashingThreads());

5
src/base/bittorrent/torrentinfo.cpp

@ -46,7 +46,6 @@
#include "base/utils/fs.h" #include "base/utils/fs.h"
#include "base/utils/io.h" #include "base/utils/io.h"
#include "base/utils/misc.h" #include "base/utils/misc.h"
#include "common.h"
#include "infohash.h" #include "infohash.h"
#include "trackerentry.h" #include "trackerentry.h"
@ -87,9 +86,11 @@ nonstd::expected<TorrentInfo, QString> TorrentInfo::load(const QByteArray &data)
{ {
// 2-step construction to overcome default limits of `depth_limit` & `token_limit` which are // 2-step construction to overcome default limits of `depth_limit` & `token_limit` which are
// used in `torrent_info()` constructor // used in `torrent_info()` constructor
const auto *pref = Preferences::instance();
lt::error_code ec; lt::error_code ec;
const lt::bdecode_node node = lt::bdecode(data, ec const lt::bdecode_node node = lt::bdecode(data, ec
, nullptr, BENCODE_DEPTH_LIMIT, BENCODE_TOKEN_LIMIT); , nullptr, pref->getBdecodeDepthLimit(), pref->getBdecodeTokenLimit());
if (ec) if (ec)
return nonstd::make_unexpected(QString::fromStdString(ec.message())); return nonstd::make_unexpected(QString::fromStdString(ec.message()));

26
src/base/preferences.cpp

@ -317,6 +317,32 @@ void Preferences::setTorrentFileSizeLimit(const qint64 value)
setValue(u"BitTorrent/TorrentFileSizeLimit"_s, value); setValue(u"BitTorrent/TorrentFileSizeLimit"_s, value);
} }
int Preferences::getBdecodeDepthLimit() const
{
return value(u"BitTorrent/BdecodeDepthLimit"_s, 100);
}
void Preferences::setBdecodeDepthLimit(const int value)
{
if (value == getBdecodeDepthLimit())
return;
setValue(u"BitTorrent/BdecodeDepthLimit"_s, value);
}
int Preferences::getBdecodeTokenLimit() const
{
return value(u"BitTorrent/BdecodeTokenLimit"_s, 10'000'000);
}
void Preferences::setBdecodeTokenLimit(const int value)
{
if (value == getBdecodeTokenLimit())
return;
setValue(u"BitTorrent/BdecodeTokenLimit"_s, value);
}
bool Preferences::isToolbarDisplayed() const bool Preferences::isToolbarDisplayed() const
{ {
return value(u"Preferences/General/ToolbarDisplayed"_s, true); return value(u"Preferences/General/ToolbarDisplayed"_s, true);

4
src/base/preferences.h

@ -335,6 +335,10 @@ public:
#endif // Q_OS_MACOS #endif // Q_OS_MACOS
qint64 getTorrentFileSizeLimit() const; qint64 getTorrentFileSizeLimit() const;
void setTorrentFileSizeLimit(qint64 value); void setTorrentFileSizeLimit(qint64 value);
int getBdecodeDepthLimit() const;
void setBdecodeDepthLimit(int value);
int getBdecodeTokenLimit() const;
void setBdecodeTokenLimit(int value);
// Stuff that don't appear in the Options GUI but are saved // Stuff that don't appear in the Options GUI but are saved
// in the same file. // in the same file.

18
src/gui/advancedsettings.cpp

@ -101,6 +101,8 @@ namespace
TRACKER_PORT_FORWARDING, TRACKER_PORT_FORWARDING,
// libtorrent section // libtorrent section
LIBTORRENT_HEADER, LIBTORRENT_HEADER,
BDECODE_DEPTH_LIMIT,
BDECODE_TOKEN_LIMIT,
ASYNC_IO_THREADS, ASYNC_IO_THREADS,
#ifdef QBT_USES_LIBTORRENT2 #ifdef QBT_USES_LIBTORRENT2
HASHING_THREADS, HASHING_THREADS,
@ -199,6 +201,10 @@ void AdvancedSettings::saveAdvancedSettings() const
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
app()->setProcessMemoryPriority(m_comboBoxOSMemoryPriority.currentData().value<MemoryPriority>()); app()->setProcessMemoryPriority(m_comboBoxOSMemoryPriority.currentData().value<MemoryPriority>());
#endif #endif
// Bdecode depth limit
pref->setBdecodeDepthLimit(m_spinBoxBdecodeDepthLimit.value());
// Bdecode token limit
pref->setBdecodeTokenLimit(m_spinBoxBdecodeTokenLimit.value());
// Async IO threads // Async IO threads
session->setAsyncIOThreads(m_spinBoxAsyncIOThreads.value()); session->setAsyncIOThreads(m_spinBoxAsyncIOThreads.value());
#ifdef QBT_USES_LIBTORRENT2 #ifdef QBT_USES_LIBTORRENT2
@ -464,6 +470,18 @@ void AdvancedSettings::loadAdvancedSettings()
+ u' ' + makeLink(u"https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-memory_priority_information", u"(?)")) + u' ' + makeLink(u"https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-memory_priority_information", u"(?)"))
, &m_comboBoxOSMemoryPriority); , &m_comboBoxOSMemoryPriority);
#endif #endif
// Bdecode depth limit
m_spinBoxBdecodeDepthLimit.setMinimum(0);
m_spinBoxBdecodeDepthLimit.setMaximum(std::numeric_limits<int>::max());
m_spinBoxBdecodeDepthLimit.setValue(pref->getBdecodeDepthLimit());
addRow(BDECODE_DEPTH_LIMIT, (tr("Bdecode depth limit") + u' ' + makeLink(u"https://www.libtorrent.org/reference-Bdecoding.html#bdecode()", u"(?)"))
, &m_spinBoxBdecodeDepthLimit);
// Bdecode token limit
m_spinBoxBdecodeTokenLimit.setMinimum(0);
m_spinBoxBdecodeTokenLimit.setMaximum(std::numeric_limits<int>::max());
m_spinBoxBdecodeTokenLimit.setValue(pref->getBdecodeTokenLimit());
addRow(BDECODE_TOKEN_LIMIT, (tr("Bdecode token limit") + u' ' + makeLink(u"https://www.libtorrent.org/reference-Bdecoding.html#bdecode()", u"(?)"))
, &m_spinBoxBdecodeTokenLimit);
// Async IO threads // Async IO threads
m_spinBoxAsyncIOThreads.setMinimum(1); m_spinBoxAsyncIOThreads.setMinimum(1);
m_spinBoxAsyncIOThreads.setMaximum(1024); m_spinBoxAsyncIOThreads.setMaximum(1024);

2
src/gui/advancedsettings.h

@ -67,7 +67,7 @@ private:
void loadAdvancedSettings(); void loadAdvancedSettings();
template <typename T> void addRow(int row, const QString &text, T *widget); template <typename T> void addRow(int row, const QString &text, T *widget);
QSpinBox m_spinBoxSaveResumeDataInterval, m_spinBoxTorrentFileSizeLimit, QSpinBox m_spinBoxSaveResumeDataInterval, m_spinBoxTorrentFileSizeLimit, m_spinBoxBdecodeDepthLimit, m_spinBoxBdecodeTokenLimit,
m_spinBoxAsyncIOThreads, m_spinBoxFilePoolSize, m_spinBoxCheckingMemUsage, m_spinBoxDiskQueueSize, m_spinBoxAsyncIOThreads, m_spinBoxFilePoolSize, m_spinBoxCheckingMemUsage, m_spinBoxDiskQueueSize,
m_spinBoxOutgoingPortsMin, m_spinBoxOutgoingPortsMax, m_spinBoxUPnPLeaseDuration, m_spinBoxPeerToS, m_spinBoxOutgoingPortsMin, m_spinBoxOutgoingPortsMax, m_spinBoxUPnPLeaseDuration, m_spinBoxPeerToS,
m_spinBoxListRefresh, m_spinBoxTrackerPort, m_spinBoxSendBufferWatermark, m_spinBoxSendBufferLowWatermark, m_spinBoxListRefresh, m_spinBoxTrackerPort, m_spinBoxSendBufferWatermark, m_spinBoxSendBufferLowWatermark,

10
src/webui/api/appcontroller.cpp

@ -335,6 +335,10 @@ void AppController::preferencesAction()
data[u"reannounce_when_address_changed"_s] = session->isReannounceWhenAddressChangedEnabled(); data[u"reannounce_when_address_changed"_s] = session->isReannounceWhenAddressChangedEnabled();
// libtorrent preferences // libtorrent preferences
// Bdecode depth limit
data[u"bdecode_depth_limit"_s] = pref->getBdecodeDepthLimit();
// Bdecode token limit
data[u"bdecode_token_limit"_s] = pref->getBdecodeTokenLimit();
// Async IO threads // Async IO threads
data[u"async_io_threads"_s] = session->asyncIOThreads(); data[u"async_io_threads"_s] = session->asyncIOThreads();
// Hashing threads // Hashing threads
@ -872,6 +876,12 @@ void AppController::setPreferencesAction()
session->setReannounceWhenAddressChangedEnabled(it.value().toBool()); session->setReannounceWhenAddressChangedEnabled(it.value().toBool());
// libtorrent preferences // libtorrent preferences
// Bdecode depth limit
if (hasKey(u"bdecode_depth_limit"_s))
pref->setBdecodeDepthLimit(it.value().toInt());
// Bdecode token limit
if (hasKey(u"bdecode_token_limit"_s))
pref->setBdecodeTokenLimit(it.value().toInt());
// Async IO threads // Async IO threads
if (hasKey(u"async_io_threads"_s)) if (hasKey(u"async_io_threads"_s))
session->setAsyncIOThreads(it.value().toInt()); session->setAsyncIOThreads(it.value().toInt());

2
src/webui/webapplication.h

@ -52,7 +52,7 @@
#include "base/utils/version.h" #include "base/utils/version.h"
#include "api/isessionmanager.h" #include "api/isessionmanager.h"
inline const Utils::Version<3, 2> API_VERSION {2, 9, 1}; inline const Utils::Version<3, 2> API_VERSION {2, 9, 2};
class APIController; class APIController;
class AuthController; class AuthController;

20
src/webui/www/private/views/preferences.html

@ -1046,6 +1046,22 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
<fieldset class="settings"> <fieldset class="settings">
<legend>QBT_TR(libtorrent Section)QBT_TR[CONTEXT=OptionsDialog]&nbsp;(<a href="https://www.libtorrent.org/reference-Settings.html" target="_blank">QBT_TR(Open documentation)QBT_TR[CONTEXT=HttpServer]</a>)</legend> <legend>QBT_TR(libtorrent Section)QBT_TR[CONTEXT=OptionsDialog]&nbsp;(<a href="https://www.libtorrent.org/reference-Settings.html" target="_blank">QBT_TR(Open documentation)QBT_TR[CONTEXT=HttpServer]</a>)</legend>
<table> <table>
<tr>
<td>
<label for="bdecodeDepthLimit">QBT_TR(Bdecode depth limit:)QBT_TR[CONTEXT=OptionsDialog]&nbsp;<a href="https://www.libtorrent.org/reference-Bdecoding.html#bdecode()" target="_blank">(?)</a></label>
</td>
<td>
<input type="text" id="bdecodeDepthLimit" style="width: 15em;" />
</td>
</tr>
<tr>
<td>
<label for="bdecodeTokenLimit">QBT_TR(Bdecode token limit:)QBT_TR[CONTEXT=OptionsDialog]&nbsp;<a href="https://www.libtorrent.org/reference-Bdecoding.html#bdecode()" target="_blank">(?)</a></label>
</td>
<td>
<input type="text" id="bdecodeTokenLimit" style="width: 15em;" />
</td>
</tr>
<tr> <tr>
<td> <td>
<label for="asyncIOThreads">QBT_TR(Asynchronous I/O threads:)QBT_TR[CONTEXT=OptionsDialog]&nbsp;<a href="https://www.libtorrent.org/reference-Settings.html#aio_threads" target="_blank">(?)</a></label> <label for="asyncIOThreads">QBT_TR(Asynchronous I/O threads:)QBT_TR[CONTEXT=OptionsDialog]&nbsp;<a href="https://www.libtorrent.org/reference-Settings.html#aio_threads" target="_blank">(?)</a></label>
@ -2161,6 +2177,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
$('resolvePeerCountries').setProperty('checked', pref.resolve_peer_countries); $('resolvePeerCountries').setProperty('checked', pref.resolve_peer_countries);
$('reannounceWhenAddressChanged').setProperty('checked', pref.reannounce_when_address_changed); $('reannounceWhenAddressChanged').setProperty('checked', pref.reannounce_when_address_changed);
// libtorrent section // libtorrent section
$('bdecodeDepthLimit').setProperty('value', pref.bdecode_depth_limit);
$('bdecodeTokenLimit').setProperty('value', pref.bdecode_token_limit);
$('asyncIOThreads').setProperty('value', pref.async_io_threads); $('asyncIOThreads').setProperty('value', pref.async_io_threads);
$('hashingThreads').setProperty('value', pref.hashing_threads); $('hashingThreads').setProperty('value', pref.hashing_threads);
$('filePoolSize').setProperty('value', pref.file_pool_size); $('filePoolSize').setProperty('value', pref.file_pool_size);
@ -2579,6 +2597,8 @@ Use ';' to split multiple entries. Can use wildcard '*'.)QBT_TR[CONTEXT=OptionsD
settings.set('reannounce_when_address_changed', $('reannounceWhenAddressChanged').getProperty('checked')); settings.set('reannounce_when_address_changed', $('reannounceWhenAddressChanged').getProperty('checked'));
// libtorrent section // libtorrent section
settings.set('bdecode_depth_limit', $('bdecodeDepthLimit').getProperty('value'));
settings.set('bdecode_token_limit', $('bdecodeTokenLimit').getProperty('value'));
settings.set('async_io_threads', $('asyncIOThreads').getProperty('value')); settings.set('async_io_threads', $('asyncIOThreads').getProperty('value'));
settings.set('hashing_threads', $('hashingThreads').getProperty('value')); settings.set('hashing_threads', $('hashingThreads').getProperty('value'));
settings.set('file_pool_size', $('filePoolSize').getProperty('value')); settings.set('file_pool_size', $('filePoolSize').getProperty('value'));

Loading…
Cancel
Save