|
|
|
@ -51,6 +51,9 @@
@@ -51,6 +51,9 @@
|
|
|
|
|
|
|
|
|
|
using namespace libtorrent; |
|
|
|
|
|
|
|
|
|
static const int API_VERSION = 2; |
|
|
|
|
static const int API_VERSION_MIN = 2; |
|
|
|
|
|
|
|
|
|
const QString WWW_FOLDER = ":/www/public/"; |
|
|
|
|
const QString PRIVATE_FOLDER = ":/www/private/"; |
|
|
|
|
const QString DEFAULT_SCOPE = "public"; |
|
|
|
@ -58,6 +61,7 @@ const QString SCOPE_IMAGES = "images";
@@ -58,6 +61,7 @@ const QString SCOPE_IMAGES = "images";
|
|
|
|
|
const QString SCOPE_THEME = "theme"; |
|
|
|
|
const QString DEFAULT_ACTION = "index"; |
|
|
|
|
const QString WEBUI_ACTION = "webui"; |
|
|
|
|
const QString VERSION_INFO = "version"; |
|
|
|
|
|
|
|
|
|
#define ADD_ACTION(scope, action) actions[#scope][#action] = &RequestHandler::action_##scope##_##action |
|
|
|
|
|
|
|
|
@ -102,6 +106,9 @@ QMap<QString, QMap<QString, RequestHandler::Action> > RequestHandler::initialize
@@ -102,6 +106,9 @@ QMap<QString, QMap<QString, RequestHandler::Action> > RequestHandler::initialize
|
|
|
|
|
ADD_ACTION(command, topPrio); |
|
|
|
|
ADD_ACTION(command, bottomPrio); |
|
|
|
|
ADD_ACTION(command, recheck); |
|
|
|
|
ADD_ACTION(version, api); |
|
|
|
|
ADD_ACTION(version, api_min); |
|
|
|
|
ADD_ACTION(version, qbittorrent); |
|
|
|
|
|
|
|
|
|
return actions; |
|
|
|
|
} |
|
|
|
@ -109,8 +116,8 @@ QMap<QString, QMap<QString, RequestHandler::Action> > RequestHandler::initialize
@@ -109,8 +116,8 @@ QMap<QString, QMap<QString, RequestHandler::Action> > RequestHandler::initialize
|
|
|
|
|
void RequestHandler::action_public_index() |
|
|
|
|
{ |
|
|
|
|
QString path; |
|
|
|
|
if (!args_.isEmpty()) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
if (!args_.isEmpty()) { |
|
|
|
|
if (args_.back() == "favicon.ico") |
|
|
|
|
path = ":/Icons/skin/qbittorrent16.png"; |
|
|
|
|
else |
|
|
|
@ -139,13 +146,11 @@ void RequestHandler::action_public_login()
@@ -139,13 +146,11 @@ void RequestHandler::action_public_login()
|
|
|
|
|
bool equalUser = misc::slowEquals(request().posts["username"].toUtf8(), pref->getWebUiUsername().toUtf8()); |
|
|
|
|
bool equalPass = misc::slowEquals(pass.toUtf8(), pref->getWebUiPassword().toUtf8()); |
|
|
|
|
|
|
|
|
|
if (equalUser && equalPass) |
|
|
|
|
{ |
|
|
|
|
if (equalUser && equalPass) { |
|
|
|
|
sessionStart(); |
|
|
|
|
print(QByteArray("Ok."), CONTENT_TYPE_TXT); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
else { |
|
|
|
|
QString addr = env().clientAddress.toString(); |
|
|
|
|
increaseFailedAttempts(); |
|
|
|
|
qDebug("client IP: %s (%d failed attempts)", qPrintable(addr), failedAttempts()); |
|
|
|
@ -160,8 +165,7 @@ void RequestHandler::action_public_logout()
@@ -160,8 +165,7 @@ void RequestHandler::action_public_logout()
|
|
|
|
|
|
|
|
|
|
void RequestHandler::action_public_theme() |
|
|
|
|
{ |
|
|
|
|
if (args_.size() != 1) |
|
|
|
|
{ |
|
|
|
|
if (args_.size() != 1) { |
|
|
|
|
status(404, "Not Found"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
@ -212,6 +216,21 @@ void RequestHandler::action_json_propertiesFiles()
@@ -212,6 +216,21 @@ void RequestHandler::action_json_propertiesFiles()
|
|
|
|
|
print(btjson::getFilesForTorrent(args_.front()), CONTENT_TYPE_JS); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_version_api() |
|
|
|
|
{ |
|
|
|
|
print(QString::number(API_VERSION), CONTENT_TYPE_TXT); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_version_api_min() |
|
|
|
|
{ |
|
|
|
|
print(QString::number(API_VERSION_MIN), CONTENT_TYPE_TXT); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_version_qbittorrent() |
|
|
|
|
{ |
|
|
|
|
print(QString(VERSION), CONTENT_TYPE_TXT); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_command_shutdown() |
|
|
|
|
{ |
|
|
|
|
qDebug() << "Shutdown request from Web UI"; |
|
|
|
@ -227,22 +246,17 @@ void RequestHandler::action_command_download()
@@ -227,22 +246,17 @@ void RequestHandler::action_command_download()
|
|
|
|
|
QString urls = request().posts["urls"]; |
|
|
|
|
QStringList list = urls.split('\n'); |
|
|
|
|
|
|
|
|
|
foreach (QString url, list) |
|
|
|
|
{ |
|
|
|
|
foreach (QString url, list) { |
|
|
|
|
url = url.trimmed(); |
|
|
|
|
if (!url.isEmpty()) |
|
|
|
|
{ |
|
|
|
|
if (url.startsWith("bc://bt/", Qt::CaseInsensitive)) |
|
|
|
|
{ |
|
|
|
|
if (!url.isEmpty()) { |
|
|
|
|
if (url.startsWith("bc://bt/", Qt::CaseInsensitive)) { |
|
|
|
|
qDebug("Converting bc link to magnet link"); |
|
|
|
|
url = misc::bcLinkToMagnet(url); |
|
|
|
|
} |
|
|
|
|
else if (url.startsWith("magnet:", Qt::CaseInsensitive)) |
|
|
|
|
{ |
|
|
|
|
else if (url.startsWith("magnet:", Qt::CaseInsensitive)) { |
|
|
|
|
QBtSession::instance()->addMagnetSkipAddDlg(url); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
else { |
|
|
|
|
qDebug("Downloading url: %s", qPrintable(url)); |
|
|
|
|
QBtSession::instance()->downloadUrlAndSkipDialog(url); |
|
|
|
|
} |
|
|
|
@ -254,12 +268,10 @@ void RequestHandler::action_command_upload()
@@ -254,12 +268,10 @@ void RequestHandler::action_command_upload()
|
|
|
|
|
{ |
|
|
|
|
qDebug() << Q_FUNC_INFO; |
|
|
|
|
|
|
|
|
|
foreach(const UploadedFile& torrent, request().files) |
|
|
|
|
{ |
|
|
|
|
foreach(const UploadedFile& torrent, request().files) { |
|
|
|
|
QString filePath = saveTmpFile(torrent.data); |
|
|
|
|
|
|
|
|
|
if (!filePath.isEmpty()) |
|
|
|
|
{ |
|
|
|
|
if (!filePath.isEmpty()) { |
|
|
|
|
QTorrentHandle h = QBtSession::instance()->addTorrent(filePath); |
|
|
|
|
if (!h.is_valid()) { |
|
|
|
|
status(415, "Internal Server Error"); |
|
|
|
@ -268,8 +280,7 @@ void RequestHandler::action_command_upload()
@@ -268,8 +280,7 @@ void RequestHandler::action_command_upload()
|
|
|
|
|
// Clean up
|
|
|
|
|
fsutils::forceRemove(filePath); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
else { |
|
|
|
|
qWarning() << "I/O Error: Could not create temporary file"; |
|
|
|
|
status(500, "Internal Server Error"); |
|
|
|
|
print(QObject::tr("I/O Error: Could not create temporary file."), CONTENT_TYPE_TXT); |
|
|
|
@ -281,17 +292,14 @@ void RequestHandler::action_command_addTrackers()
@@ -281,17 +292,14 @@ void RequestHandler::action_command_addTrackers()
|
|
|
|
|
{ |
|
|
|
|
QString hash = request().posts["hash"]; |
|
|
|
|
|
|
|
|
|
if (!hash.isEmpty()) |
|
|
|
|
{ |
|
|
|
|
if (!hash.isEmpty()) { |
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
|
|
|
|
|
if (h.is_valid() && h.has_metadata()) |
|
|
|
|
{ |
|
|
|
|
if (h.is_valid() && h.has_metadata()) { |
|
|
|
|
QString urls = request().posts["urls"]; |
|
|
|
|
QStringList list = urls.split('\n'); |
|
|
|
|
|
|
|
|
|
foreach (const QString& url, list) |
|
|
|
|
{ |
|
|
|
|
foreach (const QString& url, list) { |
|
|
|
|
announce_entry e(url.toStdString()); |
|
|
|
|
h.add_tracker(e); |
|
|
|
|
} |
|
|
|
@ -332,9 +340,7 @@ void RequestHandler::action_command_setFilePrio()
@@ -332,9 +340,7 @@ void RequestHandler::action_command_setFilePrio()
|
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
|
|
|
|
|
if (h.is_valid() && h.has_metadata()) |
|
|
|
|
{ |
|
|
|
|
h.file_priority(file_id, priority); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_command_getGlobalUpLimit() |
|
|
|
@ -353,7 +359,7 @@ void RequestHandler::action_command_setGlobalUpLimit()
@@ -353,7 +359,7 @@ void RequestHandler::action_command_setGlobalUpLimit()
|
|
|
|
|
if (limit == 0) limit = -1; |
|
|
|
|
|
|
|
|
|
QBtSession::instance()->setUploadRateLimit(limit); |
|
|
|
|
Preferences::instance()->setGlobalUploadLimit(limit/1024.); |
|
|
|
|
Preferences::instance()->setGlobalUploadLimit(limit / 1024.); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_command_setGlobalDlLimit() |
|
|
|
@ -362,7 +368,7 @@ void RequestHandler::action_command_setGlobalDlLimit()
@@ -362,7 +368,7 @@ void RequestHandler::action_command_setGlobalDlLimit()
|
|
|
|
|
if (limit == 0) limit = -1; |
|
|
|
|
|
|
|
|
|
QBtSession::instance()->setDownloadRateLimit(limit); |
|
|
|
|
Preferences::instance()->setGlobalDownloadLimit(limit/1024.); |
|
|
|
|
Preferences::instance()->setGlobalDownloadLimit(limit / 1024.); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_command_getTorrentUpLimit() |
|
|
|
@ -371,9 +377,7 @@ void RequestHandler::action_command_getTorrentUpLimit()
@@ -371,9 +377,7 @@ void RequestHandler::action_command_getTorrentUpLimit()
|
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
|
|
|
|
|
if (h.is_valid()) |
|
|
|
|
{ |
|
|
|
|
print(QByteArray::number(h.upload_limit())); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_command_getTorrentDlLimit() |
|
|
|
@ -382,9 +386,7 @@ void RequestHandler::action_command_getTorrentDlLimit()
@@ -382,9 +386,7 @@ void RequestHandler::action_command_getTorrentDlLimit()
|
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
|
|
|
|
|
if (h.is_valid()) |
|
|
|
|
{ |
|
|
|
|
print(QByteArray::number(h.download_limit())); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_command_setTorrentUpLimit() |
|
|
|
@ -395,9 +397,7 @@ void RequestHandler::action_command_setTorrentUpLimit()
@@ -395,9 +397,7 @@ void RequestHandler::action_command_setTorrentUpLimit()
|
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
|
|
|
|
|
if (h.is_valid()) |
|
|
|
|
{ |
|
|
|
|
h.set_upload_limit(limit); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_command_setTorrentDlLimit() |
|
|
|
@ -408,59 +408,46 @@ void RequestHandler::action_command_setTorrentDlLimit()
@@ -408,59 +408,46 @@ void RequestHandler::action_command_setTorrentDlLimit()
|
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
|
|
|
|
|
if (h.is_valid()) |
|
|
|
|
{ |
|
|
|
|
h.set_download_limit(limit); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_command_delete() |
|
|
|
|
{ |
|
|
|
|
QStringList hashes = request().posts["hashes"].split("|"); |
|
|
|
|
|
|
|
|
|
foreach (const QString &hash, hashes) |
|
|
|
|
{ |
|
|
|
|
QBtSession::instance()->deleteTorrent(hash, false); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_command_deletePerm() |
|
|
|
|
{ |
|
|
|
|
QStringList hashes = request().posts["hashes"].split("|"); |
|
|
|
|
|
|
|
|
|
foreach (const QString &hash, hashes) |
|
|
|
|
{ |
|
|
|
|
QBtSession::instance()->deleteTorrent(hash, true); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::action_command_increasePrio() |
|
|
|
|
{ |
|
|
|
|
QStringList hashes = request().posts["hashes"].split("|"); |
|
|
|
|
|
|
|
|
|
std::priority_queue<QPair<int, QTorrentHandle>, |
|
|
|
|
std::vector<QPair<int, QTorrentHandle> >, |
|
|
|
|
std::greater<QPair<int, QTorrentHandle> > > torrent_queue; |
|
|
|
|
|
|
|
|
|
// Sort torrents by priority
|
|
|
|
|
foreach (const QString &hash, hashes) |
|
|
|
|
{ |
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
foreach (const QString &hash, hashes) { |
|
|
|
|
try { |
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
if (!h.is_seed()) |
|
|
|
|
{ |
|
|
|
|
torrent_queue.push(qMakePair(h.queue_position(), h)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
catch(invalid_handle&) {} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Increase torrents priority (starting with the ones with highest priority)
|
|
|
|
|
while(!torrent_queue.empty()) |
|
|
|
|
{ |
|
|
|
|
while(!torrent_queue.empty()) { |
|
|
|
|
QTorrentHandle h = torrent_queue.top().second; |
|
|
|
|
|
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
try { |
|
|
|
|
h.queue_position_up(); |
|
|
|
|
} |
|
|
|
|
catch(invalid_handle&) {} |
|
|
|
@ -472,32 +459,27 @@ void RequestHandler::action_command_increasePrio()
@@ -472,32 +459,27 @@ void RequestHandler::action_command_increasePrio()
|
|
|
|
|
void RequestHandler::action_command_decreasePrio() |
|
|
|
|
{ |
|
|
|
|
QStringList hashes = request().posts["hashes"].split("|"); |
|
|
|
|
|
|
|
|
|
std::priority_queue<QPair<int, QTorrentHandle>, |
|
|
|
|
std::vector<QPair<int, QTorrentHandle> >, |
|
|
|
|
std::less<QPair<int, QTorrentHandle> > > torrent_queue; |
|
|
|
|
|
|
|
|
|
// Sort torrents by priority
|
|
|
|
|
foreach (const QString &hash, hashes) |
|
|
|
|
{ |
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
foreach (const QString &hash, hashes) { |
|
|
|
|
try { |
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
|
|
|
|
|
if (!h.is_seed()) |
|
|
|
|
{ |
|
|
|
|
torrent_queue.push(qMakePair(h.queue_position(), h)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
catch(invalid_handle&) {} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Decrease torrents priority (starting with the ones with lowest priority)
|
|
|
|
|
while(!torrent_queue.empty()) |
|
|
|
|
{ |
|
|
|
|
while(!torrent_queue.empty()) { |
|
|
|
|
QTorrentHandle h = torrent_queue.top().second; |
|
|
|
|
|
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
try { |
|
|
|
|
h.queue_position_down(); |
|
|
|
|
} |
|
|
|
|
catch(invalid_handle&) {} |
|
|
|
@ -508,8 +490,7 @@ void RequestHandler::action_command_decreasePrio()
@@ -508,8 +490,7 @@ void RequestHandler::action_command_decreasePrio()
|
|
|
|
|
|
|
|
|
|
void RequestHandler::action_command_topPrio() |
|
|
|
|
{ |
|
|
|
|
foreach (const QString &hash, request().posts["hashes"].split("|")) |
|
|
|
|
{ |
|
|
|
|
foreach (const QString &hash, request().posts["hashes"].split("|")) { |
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
if (h.is_valid()) h.queue_position_top(); |
|
|
|
|
} |
|
|
|
@ -517,8 +498,7 @@ void RequestHandler::action_command_topPrio()
@@ -517,8 +498,7 @@ void RequestHandler::action_command_topPrio()
|
|
|
|
|
|
|
|
|
|
void RequestHandler::action_command_bottomPrio() |
|
|
|
|
{ |
|
|
|
|
foreach (const QString &hash, request().posts["hashes"].split("|")) |
|
|
|
|
{ |
|
|
|
|
foreach (const QString &hash, request().posts["hashes"].split("|")) { |
|
|
|
|
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
|
|
|
if (h.is_valid()) h.queue_position_bottom(); |
|
|
|
|
} |
|
|
|
@ -531,30 +511,26 @@ void RequestHandler::action_command_recheck()
@@ -531,30 +511,26 @@ void RequestHandler::action_command_recheck()
|
|
|
|
|
|
|
|
|
|
bool RequestHandler::isPublicScope() |
|
|
|
|
{ |
|
|
|
|
return (scope_ == DEFAULT_SCOPE); |
|
|
|
|
return (scope_ == DEFAULT_SCOPE || scope_ == VERSION_INFO); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void RequestHandler::processRequest() |
|
|
|
|
{ |
|
|
|
|
if (args_.contains(".") || args_.contains("..")) |
|
|
|
|
{ |
|
|
|
|
if (args_.contains(".") || args_.contains("..")) { |
|
|
|
|
qDebug() << Q_FUNC_INFO << "Invalid path:" << request().path; |
|
|
|
|
status(404, "Not Found"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!isPublicScope() && !sessionActive()) |
|
|
|
|
{ |
|
|
|
|
if (!isPublicScope() && !sessionActive()) { |
|
|
|
|
status(403, "Forbidden"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (actions_.value(scope_).value(action_) != 0) |
|
|
|
|
{ |
|
|
|
|
if (actions_.value(scope_).value(action_) != 0) { |
|
|
|
|
(this->*(actions_[scope_][action_]))(); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
else { |
|
|
|
|
status(404, "Not Found"); |
|
|
|
|
qDebug() << Q_FUNC_INFO << "Resource not found:" << request().path; |
|
|
|
|
} |
|
|
|
@ -566,19 +542,15 @@ void RequestHandler::parsePath()
@@ -566,19 +542,15 @@ void RequestHandler::parsePath()
|
|
|
|
|
|
|
|
|
|
// check action for requested path
|
|
|
|
|
QStringList pathItems = request().path.split('/', QString::SkipEmptyParts); |
|
|
|
|
if (!pathItems.empty()) |
|
|
|
|
{ |
|
|
|
|
if (actions_.contains(pathItems.front())) |
|
|
|
|
{ |
|
|
|
|
if (!pathItems.empty()) { |
|
|
|
|
if (actions_.contains(pathItems.front())) { |
|
|
|
|
scope_ = pathItems.front(); |
|
|
|
|
pathItems.pop_front(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!pathItems.empty()) |
|
|
|
|
{ |
|
|
|
|
if (actions_[scope_].contains(pathItems.front())) |
|
|
|
|
{ |
|
|
|
|
if (!pathItems.empty()) { |
|
|
|
|
if (actions_[scope_].contains(pathItems.front())) { |
|
|
|
|
action_ = pathItems.front(); |
|
|
|
|
pathItems.pop_front(); |
|
|
|
|
} |
|
|
|
|