mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-31 04:38:04 -06:00
WebUI core redesign.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Bittorrent Client using Qt4 and libtorrent.
|
||||
* Bittorrent Client using Qt and libtorrent.
|
||||
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
|
||||
* Copyright (C) 2006 Ishan Arora and Christophe Dumez
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -24,661 +25,84 @@
|
||||
* modify file(s), you may extend this exception to your version of the file(s),
|
||||
* but you are not obligated to do so. If you do not wish to do so, delete this
|
||||
* exception statement from your version.
|
||||
*
|
||||
* Contact : chris@qbittorrent.org
|
||||
*/
|
||||
|
||||
|
||||
#include "httpconnection.h"
|
||||
#include "httpserver.h"
|
||||
#include "httprequestheader.h"
|
||||
#include "httpresponseheader.h"
|
||||
#include "preferences.h"
|
||||
#include "btjson.h"
|
||||
#include "prefjson.h"
|
||||
#include "qbtsession.h"
|
||||
#include "misc.h"
|
||||
#include "fs_utils.h"
|
||||
#ifndef DISABLE_GUI
|
||||
#include "iconprovider.h"
|
||||
#endif
|
||||
#include <QTcpSocket>
|
||||
#include <QDateTime>
|
||||
#include <QStringList>
|
||||
#include <QFile>
|
||||
#include <QDebug>
|
||||
#include <QRegExp>
|
||||
#include <QTemporaryFile>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include "httptypes.h"
|
||||
#include "httpserver.h"
|
||||
#include "httprequestparser.h"
|
||||
#include "httpresponsegenerator.h"
|
||||
#include "webapplication.h"
|
||||
#include "requesthandler.h"
|
||||
#include "httpconnection.h"
|
||||
|
||||
#include <libtorrent/session.hpp>
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
HttpConnection::HttpConnection(QTcpSocket *socket, HttpServer *parent)
|
||||
: QObject(parent), m_socket(socket), m_httpserver(parent)
|
||||
HttpConnection::HttpConnection(QTcpSocket *socket, HttpServer *httpserver)
|
||||
: QObject(httpserver), m_socket(socket)
|
||||
{
|
||||
m_socket->setParent(this);
|
||||
connect(m_socket, SIGNAL(readyRead()), SLOT(read()));
|
||||
connect(m_socket, SIGNAL(disconnected()), SLOT(deleteLater()));
|
||||
}
|
||||
|
||||
HttpConnection::~HttpConnection() {
|
||||
HttpConnection::~HttpConnection()
|
||||
{
|
||||
delete m_socket;
|
||||
}
|
||||
|
||||
void HttpConnection::processDownloadedFile(const QString &url,
|
||||
const QString &file_path) {
|
||||
qDebug("URL %s successfully downloaded !", qPrintable(url));
|
||||
emit torrentReadyToBeDownloaded(file_path, false, url, false);
|
||||
}
|
||||
|
||||
void HttpConnection::handleDownloadFailure(const QString& url,
|
||||
const QString& reason) {
|
||||
std::cerr << "Could not download " << qPrintable(url) << ", reason: "
|
||||
<< qPrintable(reason) << std::endl;
|
||||
}
|
||||
|
||||
void HttpConnection::read()
|
||||
{
|
||||
m_receivedData.append(m_socket->readAll());
|
||||
|
||||
// Parse HTTP request header
|
||||
const int header_end = m_receivedData.indexOf("\r\n\r\n");
|
||||
if (header_end < 0) {
|
||||
qDebug() << "Partial request: \n" << m_receivedData;
|
||||
HttpRequest request;
|
||||
HttpRequestParser::ErrorCode err = HttpRequestParser::parse(m_receivedData, request);
|
||||
switch (err)
|
||||
{
|
||||
case HttpRequestParser::IncompleteRequest:
|
||||
// Partial request waiting for the rest
|
||||
return;
|
||||
}
|
||||
|
||||
const QByteArray header = m_receivedData.left(header_end);
|
||||
m_parser.writeHeader(header);
|
||||
if (m_parser.isError()) {
|
||||
qWarning() << Q_FUNC_INFO << "header parsing error";
|
||||
m_receivedData.clear();
|
||||
m_generator.setStatusLine(400, "Bad Request");
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse HTTP request message
|
||||
if (m_parser.header().hasContentLength()) {
|
||||
const int expected_length = m_parser.header().contentLength();
|
||||
QByteArray message = m_receivedData.mid(header_end + 4, expected_length);
|
||||
|
||||
if (expected_length > 10000000 /* ~10MB */) {
|
||||
qWarning() << "Bad request: message too long";
|
||||
m_generator.setStatusLine(400, "Bad Request");
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
m_receivedData.clear();
|
||||
write();
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.length() < expected_length) {
|
||||
// Message too short, waiting for the rest
|
||||
qDebug() << "Partial message:\n" << message;
|
||||
return;
|
||||
}
|
||||
|
||||
m_parser.writeMessage(message);
|
||||
m_receivedData = m_receivedData.mid(header_end + 4 + expected_length);
|
||||
} else {
|
||||
m_receivedData.clear();
|
||||
}
|
||||
|
||||
if (m_parser.isError()) {
|
||||
qWarning() << Q_FUNC_INFO << "message parsing error";
|
||||
m_generator.setStatusLine(400, "Bad Request");
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
} else {
|
||||
respond();
|
||||
break;
|
||||
case HttpRequestParser::BadRequest:
|
||||
write(HttpResponse(400, "Bad Request"));
|
||||
break;
|
||||
case HttpRequestParser::NoError:
|
||||
HttpEnvironment env;
|
||||
env.clientAddress = m_socket->peerAddress();
|
||||
HttpResponse response = RequestHandler(request, env, WebApplication::instance()).run();
|
||||
if (acceptsGzipEncoding(request.headers["accept-encoding"]))
|
||||
response.headers[HEADER_CONTENT_ENCODING] = "gzip";
|
||||
write(response);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void HttpConnection::write()
|
||||
void HttpConnection::write(const HttpResponse& response)
|
||||
{
|
||||
m_socket->write(m_generator.toByteArray());
|
||||
m_socket->write(HttpResponseGenerator::generate(response));
|
||||
m_socket->disconnectFromHost();
|
||||
}
|
||||
|
||||
void HttpConnection::translateDocument(QString& data) {
|
||||
static QRegExp regex(QString::fromUtf8("_\\(([\\w\\s?!:\\/\\(\\),%µ&\\-\\.]+)\\)"));
|
||||
static QRegExp mnemonic("\\(?&([a-zA-Z]?\\))?");
|
||||
const std::string contexts[] = {"TransferListFiltersWidget", "TransferListWidget",
|
||||
"PropertiesWidget", "MainWindow", "HttpServer",
|
||||
"confirmDeletionDlg", "TrackerList", "TorrentFilesModel",
|
||||
"options_imp", "Preferences", "TrackersAdditionDlg",
|
||||
"ScanFoldersModel", "PropTabBar", "TorrentModel",
|
||||
"downloadFromURL", "misc"};
|
||||
const size_t context_count = sizeof(contexts)/sizeof(contexts[0]);
|
||||
int i = 0;
|
||||
bool found = true;
|
||||
|
||||
const QString locale = Preferences::instance()->getLocale();
|
||||
bool isTranslationNeeded = !locale.startsWith("en") || locale.startsWith("en_AU") || locale.startsWith("en_GB");
|
||||
|
||||
while(i < data.size() && found) {
|
||||
i = regex.indexIn(data, i);
|
||||
if (i >= 0) {
|
||||
//qDebug("Found translatable string: %s", regex.cap(1).toUtf8().data());
|
||||
QByteArray word = regex.cap(1).toUtf8();
|
||||
|
||||
QString translation = word;
|
||||
if (isTranslationNeeded) {
|
||||
size_t context_index = 0;
|
||||
while(context_index < context_count && translation == word) {
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
|
||||
translation = qApp->translate(contexts[context_index].c_str(), word.constData(), 0, QCoreApplication::UnicodeUTF8, 1);
|
||||
#else
|
||||
translation = qApp->translate(contexts[context_index].c_str(), word.constData(), 0, 1);
|
||||
#endif
|
||||
++context_index;
|
||||
}
|
||||
}
|
||||
// Remove keyboard shortcuts
|
||||
translation.replace(mnemonic, "");
|
||||
|
||||
data.replace(i, regex.matchedLength(), translation);
|
||||
i += translation.length();
|
||||
} else {
|
||||
found = false; // no more translatable strings
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HttpConnection::respond() {
|
||||
if ((m_socket->peerAddress() != QHostAddress::LocalHost
|
||||
&& m_socket->peerAddress() != QHostAddress::LocalHostIPv6)
|
||||
|| m_httpserver->isLocalAuthEnabled()) {
|
||||
// Authentication
|
||||
const QString peer_ip = m_socket->peerAddress().toString();
|
||||
const int nb_fail = m_httpserver->NbFailedAttemptsForIp(peer_ip);
|
||||
if (nb_fail >= MAX_AUTH_FAILED_ATTEMPTS) {
|
||||
m_generator.setStatusLine(403, "Forbidden");
|
||||
m_generator.setMessage(tr("Your IP address has been banned after too many failed authentication attempts."));
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
return;
|
||||
}
|
||||
QString auth = m_parser.header().value("Authorization");
|
||||
if (auth.isEmpty()) {
|
||||
// Return unauthorized header
|
||||
qDebug("Auth is Empty...");
|
||||
m_generator.setStatusLine(401, "Unauthorized");
|
||||
m_generator.setValue("WWW-Authenticate", "Digest realm=\""+QString(QBT_REALM)+"\", nonce=\""+m_httpserver->generateNonce()+"\", opaque=\""+m_httpserver->generateNonce()+"\", stale=\"false\", algorithm=\"MD5\", qop=\"auth\"");
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
return;
|
||||
}
|
||||
//qDebug("Auth: %s", qPrintable(auth.split(" ").first()));
|
||||
if (QString::compare(auth.split(" ").first(), "Digest", Qt::CaseInsensitive) != 0
|
||||
|| !m_httpserver->isAuthorized(auth.toUtf8(), m_parser.header().method())) {
|
||||
// Update failed attempt counter
|
||||
m_httpserver->increaseNbFailedAttemptsForIp(peer_ip);
|
||||
qDebug("client IP: %s (%d failed attempts)", qPrintable(peer_ip), nb_fail);
|
||||
// Return unauthorized header
|
||||
m_generator.setStatusLine(401, "Unauthorized");
|
||||
m_generator.setValue("WWW-Authenticate", "Digest realm=\""+QString(QBT_REALM)+"\", nonce=\""+m_httpserver->generateNonce()+"\", opaque=\""+m_httpserver->generateNonce()+"\", stale=\"false\", algorithm=\"MD5\", qop=\"auth\"");
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
return;
|
||||
}
|
||||
// Client successfully authenticated, reset number of failed attempts
|
||||
m_httpserver->resetNbFailedAttemptsForIp(peer_ip);
|
||||
}
|
||||
QString url = m_parser.url();
|
||||
// Favicon
|
||||
if (url.endsWith("favicon.ico")) {
|
||||
qDebug("Returning favicon");
|
||||
QFile favicon(":/Icons/skin/qbittorrent16.png");
|
||||
if (favicon.open(QIODevice::ReadOnly)) {
|
||||
const QByteArray data = favicon.readAll();
|
||||
favicon.close();
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt("png");
|
||||
m_generator.setMessage(data);
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
} else {
|
||||
respondNotFound();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList list = url.split('/', QString::SkipEmptyParts);
|
||||
if (list.contains(".") || list.contains("..")) {
|
||||
respondNotFound();
|
||||
return;
|
||||
}
|
||||
|
||||
if (list.isEmpty())
|
||||
list.append("index.html");
|
||||
|
||||
if (list.size() >= 2) {
|
||||
if (list[0] == "json") {
|
||||
if (list[1] == "torrents") {
|
||||
respondTorrentsJson();
|
||||
return;
|
||||
}
|
||||
if (list.size() > 2) {
|
||||
if (list[1] == "propertiesGeneral") {
|
||||
const QString& hash = list[2];
|
||||
respondGenPropertiesJson(hash);
|
||||
return;
|
||||
}
|
||||
if (list[1] == "propertiesTrackers") {
|
||||
const QString& hash = list[2];
|
||||
respondTrackersPropertiesJson(hash);
|
||||
return;
|
||||
}
|
||||
if (list[1] == "propertiesFiles") {
|
||||
const QString& hash = list[2];
|
||||
respondFilesPropertiesJson(hash);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (list[1] == "preferences") {
|
||||
respondPreferencesJson();
|
||||
return;
|
||||
} else {
|
||||
if (list[1] == "transferInfo") {
|
||||
respondGlobalTransferInfoJson();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list[0] == "command") {
|
||||
const QString& command = list[1];
|
||||
if (command == "shutdown") {
|
||||
qDebug() << "Shutdown request from Web UI";
|
||||
// Special case handling for shutdown, we
|
||||
// need to reply to the Web UI before
|
||||
// actually shutting down.
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
qApp->processEvents();
|
||||
// Exit application
|
||||
qApp->exit();
|
||||
} else {
|
||||
respondCommand(command);
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Icons from theme
|
||||
//qDebug() << "list[0]" << list[0];
|
||||
if (list[0] == "theme" && list.size() == 2) {
|
||||
#ifdef DISABLE_GUI
|
||||
url = ":/Icons/oxygen/"+list[1]+".png";
|
||||
#else
|
||||
url = IconProvider::instance()->getIconPath(list[1]);
|
||||
#endif
|
||||
qDebug() << "There icon:" << url;
|
||||
} else {
|
||||
if (list[0] == "images") {
|
||||
list[0] = "Icons";
|
||||
} else {
|
||||
if (list.last().endsWith(".html"))
|
||||
list.prepend("html");
|
||||
list.prepend("webui");
|
||||
}
|
||||
url = ":/" + list.join("/");
|
||||
}
|
||||
QFile file(url);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qDebug("File %s was not found!", qPrintable(url));
|
||||
respondNotFound();
|
||||
return;
|
||||
}
|
||||
QString ext = list.last();
|
||||
int index = ext.lastIndexOf('.') + 1;
|
||||
if (index > 0)
|
||||
ext.remove(0, index);
|
||||
else
|
||||
ext.clear();
|
||||
QByteArray data = file.readAll();
|
||||
file.close();
|
||||
|
||||
// Translate the page
|
||||
if (ext == "html" || (ext == "js" && !list.last().startsWith("excanvas"))) {
|
||||
QString dataStr = QString::fromUtf8(data.constData());
|
||||
translateDocument(dataStr);
|
||||
if (url.endsWith("about.html")) {
|
||||
dataStr.replace("${VERSION}", VERSION);
|
||||
}
|
||||
data = dataStr.toUtf8();
|
||||
}
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt(ext);
|
||||
m_generator.setMessage(data);
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
}
|
||||
|
||||
void HttpConnection::respondNotFound() {
|
||||
m_generator.setStatusLine(404, "File not found");
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
}
|
||||
|
||||
void HttpConnection::respondTorrentsJson() {
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt("js");
|
||||
m_generator.setMessage(btjson::getTorrents());
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
}
|
||||
|
||||
void HttpConnection::respondGenPropertiesJson(const QString& hash) {
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt("js");
|
||||
m_generator.setMessage(btjson::getPropertiesForTorrent(hash));
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
}
|
||||
|
||||
void HttpConnection::respondTrackersPropertiesJson(const QString& hash) {
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt("js");
|
||||
m_generator.setMessage(btjson::getTrackersForTorrent(hash));
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
}
|
||||
|
||||
void HttpConnection::respondFilesPropertiesJson(const QString& hash) {
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt("js");
|
||||
m_generator.setMessage(btjson::getFilesForTorrent(hash));
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
}
|
||||
|
||||
void HttpConnection::respondPreferencesJson() {
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt("js");
|
||||
m_generator.setMessage(prefjson::getPreferences());
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
}
|
||||
|
||||
void HttpConnection::respondGlobalTransferInfoJson() {
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt("js");
|
||||
m_generator.setMessage(btjson::getTransferInfo());
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
}
|
||||
|
||||
void HttpConnection::respondCommand(const QString& command) {
|
||||
qDebug() << Q_FUNC_INFO << command;
|
||||
if (command == "download") {
|
||||
QString urls = m_parser.post("urls");
|
||||
QStringList list = urls.split('\n');
|
||||
foreach (QString url, list) {
|
||||
url = url.trimmed();
|
||||
if (!url.isEmpty()) {
|
||||
if (url.startsWith("bc://bt/", Qt::CaseInsensitive)) {
|
||||
qDebug("Converting bc link to magnet link");
|
||||
url = misc::bcLinkToMagnet(url);
|
||||
}
|
||||
if (url.startsWith("magnet:", Qt::CaseInsensitive)) {
|
||||
emit MagnetReadyToBeDownloaded(url);
|
||||
} else {
|
||||
qDebug("Downloading url: %s", qPrintable(url));
|
||||
emit UrlReadyToBeDownloaded(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (command == "addTrackers") {
|
||||
QString hash = m_parser.post("hash");
|
||||
if (!hash.isEmpty()) {
|
||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash);
|
||||
if (h.is_valid() && h.has_metadata()) {
|
||||
QString urls = m_parser.post("urls");
|
||||
QStringList list = urls.split('\n');
|
||||
foreach (const QString& url, list) {
|
||||
announce_entry e(url.toStdString());
|
||||
h.add_tracker(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (command == "upload") {
|
||||
qDebug() << Q_FUNC_INFO << "upload";
|
||||
const QList<QByteArray>& torrents = m_parser.torrents();
|
||||
foreach(const QByteArray& torrentContent, torrents) {
|
||||
// Get a unique filename
|
||||
QTemporaryFile *tmpfile = new QTemporaryFile(QDir::temp().absoluteFilePath("qBT-XXXXXX.torrent"));
|
||||
tmpfile->setAutoRemove(false);
|
||||
if (tmpfile->open()) {
|
||||
QString filePath = tmpfile->fileName();
|
||||
tmpfile->write(torrentContent);
|
||||
tmpfile->close();
|
||||
// XXX: tmpfile needs to be deleted on Windows before using the file
|
||||
// or it will complain that the file is used by another process.
|
||||
delete tmpfile;
|
||||
emit torrentReadyToBeDownloaded(filePath, false, QString(), false);
|
||||
// Clean up
|
||||
fsutils::forceRemove(filePath);
|
||||
} else {
|
||||
std::cerr << "I/O Error: Could not create temporary file" << std::endl;
|
||||
delete tmpfile;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Prepare response
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt("html");
|
||||
m_generator.setMessage(QString("<script type=\"text/javascript\">window.parent.hideAll();</script>"));
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
return;
|
||||
}
|
||||
if (command == "resumeall") {
|
||||
emit resumeAllTorrents();
|
||||
return;
|
||||
}
|
||||
if (command == "pauseall") {
|
||||
emit pauseAllTorrents();
|
||||
return;
|
||||
}
|
||||
if (command == "resume") {
|
||||
emit resumeTorrent(m_parser.post("hash"));
|
||||
return;
|
||||
}
|
||||
if (command == "setPreferences") {
|
||||
prefjson::setPreferences(m_parser.post("json"));
|
||||
return;
|
||||
}
|
||||
if (command == "setFilePrio") {
|
||||
QString hash = m_parser.post("hash");
|
||||
int file_id = m_parser.post("id").toInt();
|
||||
int priority = m_parser.post("priority").toInt();
|
||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash);
|
||||
if (h.is_valid() && h.has_metadata()) {
|
||||
h.file_priority(file_id, priority);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (command == "getGlobalUpLimit") {
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt("html");
|
||||
m_generator.setMessage(QByteArray::number(QBtSession::instance()->getSession()->settings().upload_rate_limit));
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
return;
|
||||
}
|
||||
if (command == "getGlobalDlLimit") {
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt("html");
|
||||
m_generator.setMessage(QByteArray::number(QBtSession::instance()->getSession()->settings().download_rate_limit));
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
return;
|
||||
}
|
||||
if (command == "getTorrentUpLimit") {
|
||||
QString hash = m_parser.post("hash");
|
||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash);
|
||||
if (h.is_valid()) {
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt("html");
|
||||
m_generator.setMessage(QByteArray::number(h.upload_limit()));
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (command == "getTorrentDlLimit") {
|
||||
QString hash = m_parser.post("hash");
|
||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash);
|
||||
if (h.is_valid()) {
|
||||
m_generator.setStatusLine(200, "OK");
|
||||
m_generator.setContentTypeByExt("html");
|
||||
m_generator.setMessage(QByteArray::number(h.download_limit()));
|
||||
m_generator.setContentEncoding(m_parser.acceptsEncoding());
|
||||
write();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (command == "setTorrentUpLimit") {
|
||||
QString hash = m_parser.post("hash");
|
||||
qlonglong limit = m_parser.post("limit").toLongLong();
|
||||
if (limit == 0) limit = -1;
|
||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash);
|
||||
if (h.is_valid()) {
|
||||
h.set_upload_limit(limit);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (command == "setTorrentDlLimit") {
|
||||
QString hash = m_parser.post("hash");
|
||||
qlonglong limit = m_parser.post("limit").toLongLong();
|
||||
if (limit == 0) limit = -1;
|
||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash);
|
||||
if (h.is_valid()) {
|
||||
h.set_download_limit(limit);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (command == "setGlobalUpLimit") {
|
||||
qlonglong limit = m_parser.post("limit").toLongLong();
|
||||
if (limit == 0) limit = -1;
|
||||
QBtSession::instance()->setUploadRateLimit(limit);
|
||||
Preferences::instance()->setGlobalUploadLimit(limit/1024.);
|
||||
return;
|
||||
}
|
||||
if (command == "setGlobalDlLimit") {
|
||||
qlonglong limit = m_parser.post("limit").toLongLong();
|
||||
if (limit == 0) limit = -1;
|
||||
QBtSession::instance()->setDownloadRateLimit(limit);
|
||||
Preferences::instance()->setGlobalDownloadLimit(limit/1024.);
|
||||
return;
|
||||
}
|
||||
if (command == "pause") {
|
||||
emit pauseTorrent(m_parser.post("hash"));
|
||||
return;
|
||||
}
|
||||
if (command == "delete") {
|
||||
QStringList hashes = m_parser.post("hashes").split("|");
|
||||
foreach (const QString &hash, hashes) {
|
||||
emit deleteTorrent(hash, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (command == "deletePerm") {
|
||||
QStringList hashes = m_parser.post("hashes").split("|");
|
||||
foreach (const QString &hash, hashes) {
|
||||
emit deleteTorrent(hash, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (command == "increasePrio") {
|
||||
increaseTorrentsPriority(m_parser.post("hashes").split("|"));
|
||||
return;
|
||||
}
|
||||
if (command == "decreasePrio") {
|
||||
decreaseTorrentsPriority(m_parser.post("hashes").split("|"));
|
||||
return;
|
||||
}
|
||||
if (command == "topPrio") {
|
||||
foreach (const QString &hash, m_parser.post("hashes").split("|")) {
|
||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash);
|
||||
if (h.is_valid()) h.queue_position_top();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (command == "bottomPrio") {
|
||||
foreach (const QString &hash, m_parser.post("hashes").split("|")) {
|
||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash);
|
||||
if (h.is_valid()) h.queue_position_bottom();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (command == "recheck") {
|
||||
QBtSession::instance()->recheckTorrent(m_parser.post("hash"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void HttpConnection::decreaseTorrentsPriority(const QStringList &hashes) {
|
||||
qDebug() << Q_FUNC_INFO << hashes;
|
||||
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 {
|
||||
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()) {
|
||||
QTorrentHandle h = torrent_queue.top().second;
|
||||
try {
|
||||
h.queue_position_down();
|
||||
} catch(invalid_handle& h) {}
|
||||
torrent_queue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void HttpConnection::increaseTorrentsPriority(const QStringList &hashes)
|
||||
bool HttpConnection::acceptsGzipEncoding(const QString& encoding)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << hashes;
|
||||
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 {
|
||||
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()) {
|
||||
QTorrentHandle h = torrent_queue.top().second;
|
||||
try {
|
||||
h.queue_position_up();
|
||||
} catch(invalid_handle& h) {}
|
||||
torrent_queue.pop();
|
||||
}
|
||||
int pos = encoding.indexOf("gzip", 0, Qt::CaseInsensitive);
|
||||
if (pos == -1)
|
||||
return false;
|
||||
|
||||
// Let's see if there's a qvalue of 0.0 following
|
||||
if (encoding[pos + 4] != ';') //there isn't, so it accepts gzip anyway
|
||||
return true;
|
||||
|
||||
//So let's find = and the next comma
|
||||
pos = encoding.indexOf("=", pos + 4, Qt::CaseInsensitive);
|
||||
int comma_pos = encoding.indexOf(",", pos, Qt::CaseInsensitive);
|
||||
|
||||
QString value;
|
||||
if (comma_pos == -1)
|
||||
value = encoding.mid(pos + 1, comma_pos);
|
||||
else
|
||||
value = encoding.mid(pos + 1, comma_pos - (pos + 1));
|
||||
|
||||
if (value.toDouble() == 0.0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user