Vladimir Golovnev (Glassez)
10 years ago
37 changed files with 1918 additions and 1709 deletions
@ -0,0 +1,47 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent. |
||||||
|
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru> |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef HTTP_IREQUESTHANDLER_H |
||||||
|
#define HTTP_IREQUESTHANDLER_H |
||||||
|
|
||||||
|
#include "types.h" |
||||||
|
|
||||||
|
namespace Http |
||||||
|
{ |
||||||
|
|
||||||
|
class IRequestHandler |
||||||
|
{ |
||||||
|
public: |
||||||
|
virtual ~IRequestHandler() {} |
||||||
|
virtual Response processRequest(const Request &request, const Environment &env) = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
#endif // HTTP_IREQUESTHANDLER_H
|
||||||
|
|
@ -0,0 +1,74 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent. |
||||||
|
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru> |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "responsebuilder.h" |
||||||
|
|
||||||
|
using namespace Http; |
||||||
|
|
||||||
|
ResponseBuilder::ResponseBuilder(QObject *parent) |
||||||
|
: QObject(parent) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
void ResponseBuilder::status(uint code, const QString &text) |
||||||
|
{ |
||||||
|
m_response.status = ResponseStatus(code, text); |
||||||
|
} |
||||||
|
|
||||||
|
void ResponseBuilder::header(const QString &name, const QString &value) |
||||||
|
{ |
||||||
|
m_response.headers[name] = value; |
||||||
|
} |
||||||
|
|
||||||
|
void ResponseBuilder::print(const QString &text, const QString &type) |
||||||
|
{ |
||||||
|
print_impl(text.toUtf8(), type); |
||||||
|
} |
||||||
|
|
||||||
|
void ResponseBuilder::print(const QByteArray &data, const QString &type) |
||||||
|
{ |
||||||
|
print_impl(data, type); |
||||||
|
} |
||||||
|
|
||||||
|
void ResponseBuilder::clear() |
||||||
|
{ |
||||||
|
m_response = Response(); |
||||||
|
} |
||||||
|
|
||||||
|
Response ResponseBuilder::response() const |
||||||
|
{ |
||||||
|
return m_response; |
||||||
|
} |
||||||
|
|
||||||
|
void ResponseBuilder::print_impl(const QByteArray &data, const QString &type) |
||||||
|
{ |
||||||
|
if (!m_response.headers.contains(HEADER_CONTENT_TYPE)) |
||||||
|
m_response.headers[HEADER_CONTENT_TYPE] = type; |
||||||
|
|
||||||
|
m_response.content += data; |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent. |
||||||
|
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru> |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef HTTP_RESPONSEBUILDER_H |
||||||
|
#define HTTP_RESPONSEBUILDER_H |
||||||
|
|
||||||
|
#include <QObject> |
||||||
|
#include "types.h" |
||||||
|
|
||||||
|
namespace Http |
||||||
|
{ |
||||||
|
|
||||||
|
class ResponseBuilder : public QObject |
||||||
|
{ |
||||||
|
public: |
||||||
|
explicit ResponseBuilder(QObject *parent = 0); |
||||||
|
|
||||||
|
protected: |
||||||
|
void status(uint code = 200, const QString &text = QLatin1String("OK")); |
||||||
|
void header(const QString &name, const QString &value); |
||||||
|
void print(const QString &text, const QString &type = CONTENT_TYPE_HTML); |
||||||
|
void print(const QByteArray &data, const QString &type = CONTENT_TYPE_HTML); |
||||||
|
void clear(); |
||||||
|
|
||||||
|
Response response() const; |
||||||
|
|
||||||
|
private: |
||||||
|
void print_impl(const QByteArray &data, const QString &type); |
||||||
|
|
||||||
|
Response m_response; |
||||||
|
}; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
#endif // HTTP_RESPONSEBUILDER_H
|
@ -1,35 +0,0 @@ |
|||||||
#ifndef QPEER_H |
|
||||||
#define QPEER_H |
|
||||||
|
|
||||||
#include <libtorrent/entry.hpp> |
|
||||||
#include <QString> |
|
||||||
|
|
||||||
struct QPeer { |
|
||||||
|
|
||||||
bool operator!=(const QPeer &other) const { |
|
||||||
return qhash() != other.qhash(); |
|
||||||
} |
|
||||||
|
|
||||||
bool operator==(const QPeer &other) const { |
|
||||||
return qhash() == other.qhash(); |
|
||||||
} |
|
||||||
|
|
||||||
QString qhash() const { |
|
||||||
return ip+":"+QString::number(port); |
|
||||||
} |
|
||||||
|
|
||||||
libtorrent::entry toEntry(bool no_peer_id) const { |
|
||||||
libtorrent::entry::dictionary_type peer_map; |
|
||||||
if (!no_peer_id) |
|
||||||
peer_map["id"] = libtorrent::entry(peer_id.toStdString()); |
|
||||||
peer_map["ip"] = libtorrent::entry(ip.toStdString()); |
|
||||||
peer_map["port"] = libtorrent::entry(port); |
|
||||||
return libtorrent::entry(peer_map); |
|
||||||
} |
|
||||||
|
|
||||||
QString ip; |
|
||||||
QString peer_id; |
|
||||||
int port; |
|
||||||
}; |
|
||||||
|
|
||||||
#endif // QPEER_H
|
|
@ -1,9 +0,0 @@ |
|||||||
INCLUDEPATH += $$PWD |
|
||||||
|
|
||||||
HEADERS += \ |
|
||||||
$$PWD/qtracker.h \ |
|
||||||
$$PWD/trackerannouncerequest.h \ |
|
||||||
$$PWD/qpeer.h |
|
||||||
|
|
||||||
SOURCES += \ |
|
||||||
$$PWD/qtracker.cpp |
|
@ -1,15 +0,0 @@ |
|||||||
#ifndef TRACKERANNOUNCEREQUEST_H |
|
||||||
#define TRACKERANNOUNCEREQUEST_H |
|
||||||
|
|
||||||
#include <qpeer.h> |
|
||||||
|
|
||||||
struct TrackerAnnounceRequest { |
|
||||||
QString info_hash; |
|
||||||
QString event; |
|
||||||
int numwant; |
|
||||||
QPeer peer; |
|
||||||
// Extensions
|
|
||||||
bool no_peer_id; |
|
||||||
}; |
|
||||||
|
|
||||||
#endif // TRACKERANNOUNCEREQUEST_H
|
|
@ -1,167 +0,0 @@ |
|||||||
/*
|
|
||||||
* Bittorrent Client using Qt and libtorrent. |
|
||||||
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru> |
|
||||||
* Copyright (C) 2012, Christophe Dumez <chris@qbittorrent.org> |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or |
|
||||||
* modify it under the terms of the GNU General Public License |
|
||||||
* as published by the Free Software Foundation; either version 2 |
|
||||||
* of the License, or (at your option) any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; if not, write to the Free Software |
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
||||||
* |
|
||||||
* In addition, as a special exception, the copyright holders give permission to |
|
||||||
* link this program with the OpenSSL project's "OpenSSL" library (or with |
|
||||||
* modified versions of it that use the same license as the "OpenSSL" library), |
|
||||||
* and distribute the linked executables. You must obey the GNU General Public |
|
||||||
* License in all respects for all of the code used other than "OpenSSL". If you |
|
||||||
* 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. |
|
||||||
*/ |
|
||||||
|
|
||||||
#include <QDebug> |
|
||||||
#include <QDir> |
|
||||||
#include <QTemporaryFile> |
|
||||||
#include <QNetworkCookie> |
|
||||||
#include "preferences.h" |
|
||||||
#include "webapplication.h" |
|
||||||
#include "abstractrequesthandler.h" |
|
||||||
|
|
||||||
AbstractRequestHandler::AbstractRequestHandler(const HttpRequest &request, const HttpEnvironment &env, WebApplication *app) |
|
||||||
: app_(app), session_(0), request_(request), env_(env) |
|
||||||
{ |
|
||||||
sessionInitialize(); |
|
||||||
if (!sessionActive() && !isAuthNeeded()) |
|
||||||
sessionStart(); |
|
||||||
} |
|
||||||
|
|
||||||
HttpResponse AbstractRequestHandler::run() |
|
||||||
{ |
|
||||||
if (isBanned()) { |
|
||||||
status(403, "Forbidden"); |
|
||||||
print(QObject::tr("Your IP address has been banned after too many failed authentication attempts."), CONTENT_TYPE_TXT); |
|
||||||
} |
|
||||||
else { |
|
||||||
processRequest(); |
|
||||||
} |
|
||||||
|
|
||||||
return response_; |
|
||||||
} |
|
||||||
|
|
||||||
bool AbstractRequestHandler::isAuthNeeded() |
|
||||||
{ |
|
||||||
return |
|
||||||
( |
|
||||||
env_.clientAddress != QHostAddress::LocalHost && |
|
||||||
env_.clientAddress != QHostAddress::LocalHostIPv6 |
|
||||||
) || Preferences::instance()->isWebUiLocalAuthEnabled(); |
|
||||||
} |
|
||||||
|
|
||||||
void AbstractRequestHandler::status(uint code, const QString& text) |
|
||||||
{ |
|
||||||
response_.status = HttpResponseStatus(code, text); |
|
||||||
} |
|
||||||
|
|
||||||
void AbstractRequestHandler::header(const QString& name, const QString& value) |
|
||||||
{ |
|
||||||
response_.headers[name] = value; |
|
||||||
} |
|
||||||
|
|
||||||
void AbstractRequestHandler::print(const QString& text, const QString& type) |
|
||||||
{ |
|
||||||
print_impl(text.toUtf8(), type); |
|
||||||
} |
|
||||||
|
|
||||||
void AbstractRequestHandler::print(const QByteArray& data, const QString& type) |
|
||||||
{ |
|
||||||
print_impl(data, type); |
|
||||||
} |
|
||||||
|
|
||||||
void AbstractRequestHandler::print_impl(const QByteArray& data, const QString& type) |
|
||||||
{ |
|
||||||
if (!response_.headers.contains(HEADER_CONTENT_TYPE)) |
|
||||||
response_.headers[HEADER_CONTENT_TYPE] = type; |
|
||||||
|
|
||||||
response_.content += data; |
|
||||||
} |
|
||||||
|
|
||||||
void AbstractRequestHandler::printFile(const QString& path) |
|
||||||
{ |
|
||||||
QByteArray data; |
|
||||||
QString type; |
|
||||||
|
|
||||||
if (!app_->readFile(path, data, type)) { |
|
||||||
status(404, "Not Found"); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
print(data, type); |
|
||||||
} |
|
||||||
|
|
||||||
void AbstractRequestHandler::sessionInitialize() |
|
||||||
{ |
|
||||||
app_->sessionInitialize(this); |
|
||||||
} |
|
||||||
|
|
||||||
void AbstractRequestHandler::sessionStart() |
|
||||||
{ |
|
||||||
if (app_->sessionStart(this)) { |
|
||||||
QNetworkCookie cookie(C_SID.toUtf8(), session_->id.toUtf8()); |
|
||||||
cookie.setPath("/"); |
|
||||||
header(HEADER_SET_COOKIE, cookie.toRawForm()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void AbstractRequestHandler::sessionEnd() |
|
||||||
{ |
|
||||||
if (sessionActive()) { |
|
||||||
QNetworkCookie cookie(C_SID.toUtf8(), session_->id.toUtf8()); |
|
||||||
cookie.setPath("/"); |
|
||||||
cookie.setExpirationDate(QDateTime::currentDateTime()); |
|
||||||
|
|
||||||
if (app_->sessionEnd(this)) |
|
||||||
header(HEADER_SET_COOKIE, cookie.toRawForm()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool AbstractRequestHandler::isBanned() const |
|
||||||
{ |
|
||||||
return app_->isBanned(this); |
|
||||||
} |
|
||||||
|
|
||||||
int AbstractRequestHandler::failedAttempts() const |
|
||||||
{ |
|
||||||
return app_->failedAttempts(this); |
|
||||||
} |
|
||||||
|
|
||||||
void AbstractRequestHandler::resetFailedAttempts() |
|
||||||
{ |
|
||||||
app_->resetFailedAttempts(this); |
|
||||||
} |
|
||||||
|
|
||||||
void AbstractRequestHandler::increaseFailedAttempts() |
|
||||||
{ |
|
||||||
app_->increaseFailedAttempts(this); |
|
||||||
} |
|
||||||
|
|
||||||
QString AbstractRequestHandler::saveTmpFile(const QByteArray &data) |
|
||||||
{ |
|
||||||
QTemporaryFile tmpfile(QDir::temp().absoluteFilePath("qBT-XXXXXX.torrent")); |
|
||||||
tmpfile.setAutoRemove(false); |
|
||||||
if (tmpfile.open()) { |
|
||||||
tmpfile.write(data); |
|
||||||
tmpfile.close(); |
|
||||||
return tmpfile.fileName(); |
|
||||||
} |
|
||||||
|
|
||||||
qWarning() << "I/O Error: Could not create temporary file"; |
|
||||||
return QString(); |
|
||||||
} |
|
@ -0,0 +1,413 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent. |
||||||
|
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru> |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <QCoreApplication> |
||||||
|
#include <QDateTime> |
||||||
|
#include <QDebug> |
||||||
|
#include <QDir> |
||||||
|
#include <QFile> |
||||||
|
#include <QNetworkCookie> |
||||||
|
#include <QTemporaryFile> |
||||||
|
#include <QTimer> |
||||||
|
|
||||||
|
#include "preferences.h" |
||||||
|
#include "websessiondata.h" |
||||||
|
#include "abstractwebapplication.h" |
||||||
|
|
||||||
|
// UnbanTimer
|
||||||
|
|
||||||
|
class UnbanTimer: public QTimer |
||||||
|
{ |
||||||
|
public: |
||||||
|
UnbanTimer(const QHostAddress& peer_ip, QObject *parent) |
||||||
|
: QTimer(parent), m_peerIp(peer_ip) |
||||||
|
{ |
||||||
|
setSingleShot(true); |
||||||
|
setInterval(BAN_TIME); |
||||||
|
} |
||||||
|
|
||||||
|
inline const QHostAddress& peerIp() const { return m_peerIp; } |
||||||
|
|
||||||
|
private: |
||||||
|
QHostAddress m_peerIp; |
||||||
|
}; |
||||||
|
|
||||||
|
// WebSession
|
||||||
|
|
||||||
|
struct WebSession |
||||||
|
{ |
||||||
|
const QString id; |
||||||
|
uint timestamp; |
||||||
|
WebSessionData data; |
||||||
|
|
||||||
|
WebSession(const QString& id) |
||||||
|
: id(id) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
void updateTimestamp() |
||||||
|
{ |
||||||
|
timestamp = QDateTime::currentDateTime().toTime_t(); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// AbstractWebApplication
|
||||||
|
|
||||||
|
AbstractWebApplication::AbstractWebApplication(QObject *parent) |
||||||
|
: Http::ResponseBuilder(parent) |
||||||
|
, session_(0) |
||||||
|
{ |
||||||
|
QTimer *timer = new QTimer(this); |
||||||
|
timer->setInterval(60000); // 1 min.
|
||||||
|
connect(timer, SIGNAL(timeout()), SLOT(removeInactiveSessions())); |
||||||
|
} |
||||||
|
|
||||||
|
AbstractWebApplication::~AbstractWebApplication() |
||||||
|
{ |
||||||
|
// cleanup sessions data
|
||||||
|
qDeleteAll(sessions_); |
||||||
|
} |
||||||
|
|
||||||
|
Http::Response AbstractWebApplication::processRequest(const Http::Request &request, const Http::Environment &env) |
||||||
|
{ |
||||||
|
request_ = request; |
||||||
|
env_ = env; |
||||||
|
|
||||||
|
clear(); // clear response
|
||||||
|
|
||||||
|
sessionInitialize(); |
||||||
|
if (!sessionActive() && !isAuthNeeded()) |
||||||
|
sessionStart(); |
||||||
|
|
||||||
|
if (isBanned()) { |
||||||
|
status(403, "Forbidden"); |
||||||
|
print(QObject::tr("Your IP address has been banned after too many failed authentication attempts."), Http::CONTENT_TYPE_TXT); |
||||||
|
} |
||||||
|
else { |
||||||
|
processRequest(); |
||||||
|
} |
||||||
|
|
||||||
|
return response(); |
||||||
|
} |
||||||
|
|
||||||
|
void AbstractWebApplication::UnbanTimerEvent() |
||||||
|
{ |
||||||
|
UnbanTimer* ubantimer = static_cast<UnbanTimer*>(sender()); |
||||||
|
qDebug("Ban period has expired for %s", qPrintable(ubantimer->peerIp().toString())); |
||||||
|
clientFailedAttempts_.remove(ubantimer->peerIp()); |
||||||
|
ubantimer->deleteLater(); |
||||||
|
} |
||||||
|
|
||||||
|
void AbstractWebApplication::removeInactiveSessions() |
||||||
|
{ |
||||||
|
const uint now = QDateTime::currentDateTime().toTime_t(); |
||||||
|
|
||||||
|
foreach (const QString &id, sessions_.keys()) { |
||||||
|
if ((now - sessions_[id]->timestamp) > INACTIVE_TIME) |
||||||
|
delete sessions_.take(id); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool AbstractWebApplication::sessionInitialize() |
||||||
|
{ |
||||||
|
static const QString SID_START = QLatin1String(C_SID) + QLatin1String("="); |
||||||
|
|
||||||
|
if (session_ == 0) |
||||||
|
{ |
||||||
|
QString cookie = request_.headers.value("cookie"); |
||||||
|
//qDebug() << Q_FUNC_INFO << "cookie: " << cookie;
|
||||||
|
|
||||||
|
QString sessionId; |
||||||
|
int pos = cookie.indexOf(SID_START); |
||||||
|
if (pos >= 0) |
||||||
|
{ |
||||||
|
pos += SID_START.length(); |
||||||
|
int end = cookie.indexOf(QRegExp("[,;]"), pos); |
||||||
|
sessionId = cookie.mid(pos, end >= 0 ? end - pos : end); |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: Additional session check
|
||||||
|
|
||||||
|
if (!sessionId.isNull()) |
||||||
|
{ |
||||||
|
if (sessions_.contains(sessionId)) |
||||||
|
{ |
||||||
|
session_ = sessions_[sessionId]; |
||||||
|
session_->updateTimestamp(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
qDebug() << Q_FUNC_INFO << "session does not exist!"; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
bool AbstractWebApplication::readFile(const QString& path, QByteArray &data, QString &type) |
||||||
|
{ |
||||||
|
QString ext = ""; |
||||||
|
int index = path.lastIndexOf('.') + 1; |
||||||
|
if (index > 0) |
||||||
|
ext = path.mid(index); |
||||||
|
|
||||||
|
// find translated file in cache
|
||||||
|
if (translatedFiles_.contains(path)) |
||||||
|
{ |
||||||
|
data = translatedFiles_[path]; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
QFile file(path); |
||||||
|
if (!file.open(QIODevice::ReadOnly)) |
||||||
|
{ |
||||||
|
qDebug("File %s was not found!", qPrintable(path)); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
data = file.readAll(); |
||||||
|
file.close(); |
||||||
|
|
||||||
|
// Translate the file
|
||||||
|
if ((ext == "html") || ((ext == "js") && !path.endsWith("excanvas-compressed.js"))) |
||||||
|
{ |
||||||
|
QString dataStr = QString::fromUtf8(data.constData()); |
||||||
|
translateDocument(dataStr); |
||||||
|
|
||||||
|
if (path.endsWith("about.html")) |
||||||
|
{ |
||||||
|
dataStr.replace("${VERSION}", VERSION); |
||||||
|
} |
||||||
|
|
||||||
|
data = dataStr.toUtf8(); |
||||||
|
translatedFiles_[path] = data; // cashing translated file
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
type = CONTENT_TYPE_BY_EXT[ext]; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
WebSessionData *AbstractWebApplication::session() |
||||||
|
{ |
||||||
|
Q_ASSERT(session_ != 0); |
||||||
|
return &session_->data; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
QString AbstractWebApplication::generateSid() |
||||||
|
{ |
||||||
|
QString sid; |
||||||
|
|
||||||
|
qsrand(QDateTime::currentDateTime().toTime_t()); |
||||||
|
do |
||||||
|
{ |
||||||
|
const size_t size = 6; |
||||||
|
quint32 tmp[size]; |
||||||
|
|
||||||
|
for (size_t i = 0; i < size; ++i) |
||||||
|
tmp[i] = qrand(); |
||||||
|
|
||||||
|
sid = QByteArray::fromRawData(reinterpret_cast<const char *>(tmp), sizeof(quint32) * size).toBase64(); |
||||||
|
} |
||||||
|
while (sessions_.contains(sid)); |
||||||
|
|
||||||
|
return sid; |
||||||
|
} |
||||||
|
|
||||||
|
void AbstractWebApplication::translateDocument(QString& data) |
||||||
|
{ |
||||||
|
const QRegExp regex("QBT_TR\\((([^\\)]|\\)(?!QBT_TR))+)\\)QBT_TR"); |
||||||
|
const QRegExp mnemonic("\\(?&([a-zA-Z]?\\))?"); |
||||||
|
const std::string contexts[] = { |
||||||
|
"TransferListFiltersWidget", "TransferListWidget", "PropertiesWidget", |
||||||
|
"HttpServer", "confirmDeletionDlg", "TrackerList", "TorrentFilesModel", |
||||||
|
"options_imp", "Preferences", "TrackersAdditionDlg", "ScanFoldersModel", |
||||||
|
"PropTabBar", "TorrentModel", "downloadFromURL", "MainWindow", "misc", |
||||||
|
"StatusBar" |
||||||
|
}; |
||||||
|
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
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool AbstractWebApplication::isBanned() const |
||||||
|
{ |
||||||
|
return clientFailedAttempts_.value(env_.clientAddress, 0) >= MAX_AUTH_FAILED_ATTEMPTS; |
||||||
|
} |
||||||
|
|
||||||
|
int AbstractWebApplication::failedAttempts() const |
||||||
|
{ |
||||||
|
return clientFailedAttempts_.value(env_.clientAddress, 0); |
||||||
|
} |
||||||
|
|
||||||
|
void AbstractWebApplication::resetFailedAttempts() |
||||||
|
{ |
||||||
|
clientFailedAttempts_.remove(env_.clientAddress); |
||||||
|
} |
||||||
|
|
||||||
|
void AbstractWebApplication::increaseFailedAttempts() |
||||||
|
{ |
||||||
|
const int nb_fail = clientFailedAttempts_.value(env_.clientAddress, 0) + 1; |
||||||
|
|
||||||
|
clientFailedAttempts_[env_.clientAddress] = nb_fail; |
||||||
|
if (nb_fail == MAX_AUTH_FAILED_ATTEMPTS) |
||||||
|
{ |
||||||
|
// Max number of failed attempts reached
|
||||||
|
// Start ban period
|
||||||
|
UnbanTimer* ubantimer = new UnbanTimer(env_.clientAddress, this); |
||||||
|
connect(ubantimer, SIGNAL(timeout()), SLOT(UnbanTimerEvent())); |
||||||
|
ubantimer->start(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool AbstractWebApplication::isAuthNeeded() |
||||||
|
{ |
||||||
|
return (env_.clientAddress != QHostAddress::LocalHost |
||||||
|
&& env_.clientAddress != QHostAddress::LocalHostIPv6) |
||||||
|
|| Preferences::instance()->isWebUiLocalAuthEnabled(); |
||||||
|
} |
||||||
|
|
||||||
|
void AbstractWebApplication::printFile(const QString& path) |
||||||
|
{ |
||||||
|
QByteArray data; |
||||||
|
QString type; |
||||||
|
|
||||||
|
if (!readFile(path, data, type)) { |
||||||
|
status(404, "Not Found"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
print(data, type); |
||||||
|
} |
||||||
|
|
||||||
|
bool AbstractWebApplication::sessionStart() |
||||||
|
{ |
||||||
|
if (session_ == 0) |
||||||
|
{ |
||||||
|
session_ = new WebSession(generateSid()); |
||||||
|
session_->updateTimestamp(); |
||||||
|
sessions_[session_->id] = session_; |
||||||
|
|
||||||
|
QNetworkCookie cookie(C_SID, session_->id.toUtf8()); |
||||||
|
cookie.setPath(QLatin1String("/")); |
||||||
|
header(Http::HEADER_SET_COOKIE, cookie.toRawForm()); |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
bool AbstractWebApplication::sessionEnd() |
||||||
|
{ |
||||||
|
if ((session_ != 0) && (sessions_.contains(session_->id))) |
||||||
|
{ |
||||||
|
QNetworkCookie cookie(C_SID, session_->id.toUtf8()); |
||||||
|
cookie.setPath(QLatin1String("/")); |
||||||
|
cookie.setExpirationDate(QDateTime::currentDateTime()); |
||||||
|
|
||||||
|
sessions_.remove(session_->id); |
||||||
|
delete session_; |
||||||
|
session_ = 0; |
||||||
|
|
||||||
|
header(Http::HEADER_SET_COOKIE, cookie.toRawForm()); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
QString AbstractWebApplication::saveTmpFile(const QByteArray &data) |
||||||
|
{ |
||||||
|
QTemporaryFile tmpfile(QDir::temp().absoluteFilePath("qBT-XXXXXX.torrent")); |
||||||
|
tmpfile.setAutoRemove(false); |
||||||
|
if (tmpfile.open()) { |
||||||
|
tmpfile.write(data); |
||||||
|
tmpfile.close(); |
||||||
|
return tmpfile.fileName(); |
||||||
|
} |
||||||
|
|
||||||
|
qWarning() << "I/O Error: Could not create temporary file"; |
||||||
|
return QString(); |
||||||
|
} |
||||||
|
|
||||||
|
QStringMap AbstractWebApplication::initializeContentTypeByExtMap() |
||||||
|
{ |
||||||
|
QStringMap map; |
||||||
|
|
||||||
|
map["htm"] = Http::CONTENT_TYPE_HTML; |
||||||
|
map["html"] = Http::CONTENT_TYPE_HTML; |
||||||
|
map["css"] = Http::CONTENT_TYPE_CSS; |
||||||
|
map["gif"] = Http::CONTENT_TYPE_GIF; |
||||||
|
map["png"] = Http::CONTENT_TYPE_PNG; |
||||||
|
map["js"] = Http::CONTENT_TYPE_JS; |
||||||
|
|
||||||
|
return map; |
||||||
|
} |
||||||
|
|
||||||
|
const QStringMap AbstractWebApplication::CONTENT_TYPE_BY_EXT = AbstractWebApplication::initializeContentTypeByExtMap(); |
@ -1,716 +0,0 @@ |
|||||||
/*
|
|
||||||
* Bittorrent Client using Qt and libtorrent. |
|
||||||
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru> |
|
||||||
* Copyright (C) 2012, Christophe Dumez <chris@qbittorrent.org> |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or |
|
||||||
* modify it under the terms of the GNU General Public License |
|
||||||
* as published by the Free Software Foundation; either version 2 |
|
||||||
* of the License, or (at your option) any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; if not, write to the Free Software |
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
||||||
* |
|
||||||
* In addition, as a special exception, the copyright holders give permission to |
|
||||||
* link this program with the OpenSSL project's "OpenSSL" library (or with |
|
||||||
* modified versions of it that use the same license as the "OpenSSL" library), |
|
||||||
* and distribute the linked executables. You must obey the GNU General Public |
|
||||||
* License in all respects for all of the code used other than "OpenSSL". If you |
|
||||||
* 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. |
|
||||||
*/ |
|
||||||
|
|
||||||
#include <QDebug> |
|
||||||
#ifdef DISABLE_GUI |
|
||||||
#include <QCoreApplication> |
|
||||||
#else |
|
||||||
#include <QApplication> |
|
||||||
#endif |
|
||||||
#include <QTimer> |
|
||||||
#include <QCryptographicHash> |
|
||||||
#include <queue> |
|
||||||
#include <vector> |
|
||||||
#include <libtorrent/session.hpp> |
|
||||||
#ifndef DISABLE_GUI |
|
||||||
#include "iconprovider.h" |
|
||||||
#endif |
|
||||||
#include "misc.h" |
|
||||||
#include "fs_utils.h" |
|
||||||
#include "preferences.h" |
|
||||||
#include "btjson.h" |
|
||||||
#include "prefjson.h" |
|
||||||
#include "qbtsession.h" |
|
||||||
#include "requesthandler.h" |
|
||||||
#include "webapplication.h" |
|
||||||
|
|
||||||
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"; |
|
||||||
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"; |
|
||||||
const QString MAX_AGE_MONTH = "public, max-age=2592000"; |
|
||||||
|
|
||||||
#define ADD_ACTION(scope, action) actions[#scope][#action] = &RequestHandler::action_##scope##_##action |
|
||||||
|
|
||||||
QMap<QString, QMap<QString, RequestHandler::Action> > RequestHandler::initializeActions() |
|
||||||
{ |
|
||||||
QMap<QString,QMap<QString, RequestHandler::Action> > actions; |
|
||||||
|
|
||||||
ADD_ACTION(public, webui); |
|
||||||
ADD_ACTION(public, index); |
|
||||||
ADD_ACTION(public, login); |
|
||||||
ADD_ACTION(public, logout); |
|
||||||
ADD_ACTION(public, theme); |
|
||||||
ADD_ACTION(public, images); |
|
||||||
ADD_ACTION(query, torrents); |
|
||||||
ADD_ACTION(query, preferences); |
|
||||||
ADD_ACTION(query, transferInfo); |
|
||||||
ADD_ACTION(query, propertiesGeneral); |
|
||||||
ADD_ACTION(query, propertiesTrackers); |
|
||||||
ADD_ACTION(query, propertiesFiles); |
|
||||||
ADD_ACTION(sync, maindata); |
|
||||||
ADD_ACTION(command, shutdown); |
|
||||||
ADD_ACTION(command, download); |
|
||||||
ADD_ACTION(command, upload); |
|
||||||
ADD_ACTION(command, addTrackers); |
|
||||||
ADD_ACTION(command, resumeAll); |
|
||||||
ADD_ACTION(command, pauseAll); |
|
||||||
ADD_ACTION(command, resume); |
|
||||||
ADD_ACTION(command, pause); |
|
||||||
ADD_ACTION(command, setPreferences); |
|
||||||
ADD_ACTION(command, setFilePrio); |
|
||||||
ADD_ACTION(command, getGlobalUpLimit); |
|
||||||
ADD_ACTION(command, getGlobalDlLimit); |
|
||||||
ADD_ACTION(command, setGlobalUpLimit); |
|
||||||
ADD_ACTION(command, setGlobalDlLimit); |
|
||||||
ADD_ACTION(command, getTorrentUpLimit); |
|
||||||
ADD_ACTION(command, getTorrentDlLimit); |
|
||||||
ADD_ACTION(command, setTorrentUpLimit); |
|
||||||
ADD_ACTION(command, setTorrentDlLimit); |
|
||||||
ADD_ACTION(command, alternativeSpeedLimitsEnabled); |
|
||||||
ADD_ACTION(command, toggleAlternativeSpeedLimits); |
|
||||||
ADD_ACTION(command, toggleSequentialDownload); |
|
||||||
ADD_ACTION(command, toggleFirstLastPiecePrio); |
|
||||||
ADD_ACTION(command, delete); |
|
||||||
ADD_ACTION(command, deletePerm); |
|
||||||
ADD_ACTION(command, increasePrio); |
|
||||||
ADD_ACTION(command, decreasePrio); |
|
||||||
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; |
|
||||||
} |
|
||||||
|
|
||||||
#define CHECK_URI(ARGS_NUM) \ |
|
||||||
if (args_.size() != ARGS_NUM) { \ |
|
||||||
status(404, "Not Found"); \ |
|
||||||
return; \ |
|
||||||
} |
|
||||||
#define CHECK_PARAMETERS(PARAMETERS) \ |
|
||||||
QStringList parameters; \ |
|
||||||
parameters << PARAMETERS; \ |
|
||||||
if (parameters.size() != request().posts.size()) { \ |
|
||||||
status(400, "Bad Request"); \ |
|
||||||
return; \ |
|
||||||
} \ |
|
||||||
foreach (QString key, request().posts.keys()) { \ |
|
||||||
if (!parameters.contains(key, Qt::CaseInsensitive)) { \ |
|
||||||
status(400, "Bad Request"); \ |
|
||||||
return; \ |
|
||||||
} \ |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_public_index() |
|
||||||
{ |
|
||||||
QString path; |
|
||||||
|
|
||||||
if (!args_.isEmpty()) { |
|
||||||
if (args_.back() == "favicon.ico") |
|
||||||
path = ":/icons/skin/qbittorrent16.png"; |
|
||||||
else |
|
||||||
path = WWW_FOLDER + args_.join("/"); |
|
||||||
} |
|
||||||
|
|
||||||
printFile(path); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_public_webui() |
|
||||||
{ |
|
||||||
if (!sessionActive()) |
|
||||||
printFile(PRIVATE_FOLDER + "login.html"); |
|
||||||
else |
|
||||||
printFile(PRIVATE_FOLDER + "index.html"); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_public_login() |
|
||||||
{ |
|
||||||
const Preferences* const pref = Preferences::instance(); |
|
||||||
QCryptographicHash md5(QCryptographicHash::Md5); |
|
||||||
|
|
||||||
md5.addData(request().posts["password"].toLocal8Bit()); |
|
||||||
QString pass = md5.result().toHex(); |
|
||||||
|
|
||||||
bool equalUser = misc::slowEquals(request().posts["username"].toUtf8(), pref->getWebUiUsername().toUtf8()); |
|
||||||
bool equalPass = misc::slowEquals(pass.toUtf8(), pref->getWebUiPassword().toUtf8()); |
|
||||||
|
|
||||||
if (equalUser && equalPass) { |
|
||||||
sessionStart(); |
|
||||||
print(QByteArray("Ok."), CONTENT_TYPE_TXT); |
|
||||||
} |
|
||||||
else { |
|
||||||
QString addr = env().clientAddress.toString(); |
|
||||||
increaseFailedAttempts(); |
|
||||||
qDebug("client IP: %s (%d failed attempts)", qPrintable(addr), failedAttempts()); |
|
||||||
print(QByteArray("Fails."), CONTENT_TYPE_TXT); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_public_logout() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
sessionEnd(); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_public_theme() |
|
||||||
{ |
|
||||||
if (args_.size() != 1) { |
|
||||||
status(404, "Not Found"); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
#ifdef DISABLE_GUI |
|
||||||
QString url = ":/icons/oxygen/" + args_.front() + ".png"; |
|
||||||
#else |
|
||||||
QString url = IconProvider::instance()->getIconPath(args_.front()); |
|
||||||
#endif |
|
||||||
qDebug() << Q_FUNC_INFO << "There icon:" << url; |
|
||||||
|
|
||||||
printFile(url); |
|
||||||
header(HEADER_CACHE_CONTROL, MAX_AGE_MONTH); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_public_images() |
|
||||||
{ |
|
||||||
const QString path = ":/icons/" + args_.join("/"); |
|
||||||
printFile(path); |
|
||||||
header(HEADER_CACHE_CONTROL, MAX_AGE_MONTH); |
|
||||||
} |
|
||||||
|
|
||||||
// GET params:
|
|
||||||
// - filter (string): all, downloading, completed, paused, active, inactive
|
|
||||||
// - label (string): torrent label for filtering by it (empty string means "unlabeled"; no "label" param presented means "any label")
|
|
||||||
// - sort (string): name of column for sorting by its value
|
|
||||||
// - reverse (bool): enable reverse sorting
|
|
||||||
// - limit (int): set limit number of torrents returned (if greater than 0, otherwise - unlimited)
|
|
||||||
// - offset (int): set offset (if less than 0 - offset from end)
|
|
||||||
void RequestHandler::action_query_torrents() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
const QStringMap& gets = request().gets; |
|
||||||
|
|
||||||
print(btjson::getTorrents( |
|
||||||
gets["filter"], gets["label"], gets["sort"], gets["reverse"] == "true", |
|
||||||
gets["limit"].toInt(), gets["offset"].toInt() |
|
||||||
), CONTENT_TYPE_JS); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_query_preferences() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
print(prefjson::getPreferences(), CONTENT_TYPE_JS); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_query_transferInfo() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
print(btjson::getTransferInfo(), CONTENT_TYPE_JS); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_query_propertiesGeneral() |
|
||||||
{ |
|
||||||
CHECK_URI(1); |
|
||||||
print(btjson::getPropertiesForTorrent(args_.front()), CONTENT_TYPE_JS); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_query_propertiesTrackers() |
|
||||||
{ |
|
||||||
CHECK_URI(1); |
|
||||||
print(btjson::getTrackersForTorrent(args_.front()), CONTENT_TYPE_JS); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_query_propertiesFiles() |
|
||||||
{ |
|
||||||
CHECK_URI(1); |
|
||||||
print(btjson::getFilesForTorrent(args_.front()), CONTENT_TYPE_JS); |
|
||||||
} |
|
||||||
|
|
||||||
// GET param:
|
|
||||||
// - rid (int): last response id
|
|
||||||
void RequestHandler::action_sync_maindata() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
print(btjson::getSyncMainData(request().gets["rid"].toInt(), session()->syncMainDataLastResponse, session()->syncMainDataLastAcceptedResponse)); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_version_api() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
print(QString::number(API_VERSION), CONTENT_TYPE_TXT); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_version_api_min() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
print(QString::number(API_VERSION_MIN), CONTENT_TYPE_TXT); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_version_qbittorrent() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
print(QString(VERSION), CONTENT_TYPE_TXT); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_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.
|
|
||||||
|
|
||||||
CHECK_URI(0); |
|
||||||
QTimer::singleShot(0, qApp, SLOT(quit())); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_download() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("urls"); |
|
||||||
QString urls = request().posts["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); |
|
||||||
} |
|
||||||
else if (url.startsWith("magnet:", Qt::CaseInsensitive)) { |
|
||||||
QBtSession::instance()->addMagnetSkipAddDlg(url); |
|
||||||
} |
|
||||||
else { |
|
||||||
qDebug("Downloading url: %s", qPrintable(url)); |
|
||||||
QBtSession::instance()->downloadUrlAndSkipDialog(url); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_upload() |
|
||||||
{ |
|
||||||
qDebug() << Q_FUNC_INFO; |
|
||||||
CHECK_URI(0); |
|
||||||
|
|
||||||
foreach(const UploadedFile& torrent, request().files) { |
|
||||||
QString filePath = saveTmpFile(torrent.data); |
|
||||||
|
|
||||||
if (!filePath.isEmpty()) { |
|
||||||
QTorrentHandle h = QBtSession::instance()->addTorrent(filePath); |
|
||||||
if (!h.is_valid()) { |
|
||||||
status(415, "Internal Server Error"); |
|
||||||
print(QObject::tr("Error: '%1' is not a valid torrent file.\n").arg(torrent.filename), CONTENT_TYPE_TXT); |
|
||||||
} |
|
||||||
// Clean up
|
|
||||||
fsutils::forceRemove(filePath); |
|
||||||
} |
|
||||||
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); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_addTrackers() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hash" << "urls"); |
|
||||||
QString hash = request().posts["hash"]; |
|
||||||
|
|
||||||
if (!hash.isEmpty()) { |
|
||||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
||||||
|
|
||||||
if (h.is_valid() && h.has_metadata()) { |
|
||||||
QString urls = request().posts["urls"]; |
|
||||||
QStringList list = urls.split('\n'); |
|
||||||
|
|
||||||
foreach (const QString& url, list) { |
|
||||||
announce_entry e(url.toStdString()); |
|
||||||
h.add_tracker(e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_resumeAll() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
QBtSession::instance()->resumeAllTorrents(); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_pauseAll() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
QBtSession::instance()->pauseAllTorrents(); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_resume() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hash"); |
|
||||||
QBtSession::instance()->resumeTorrent(request().posts["hash"]); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_pause() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hash"); |
|
||||||
QBtSession::instance()->pauseTorrent(request().posts["hash"]); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_setPreferences() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("json"); |
|
||||||
prefjson::setPreferences(request().posts["json"]); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_setFilePrio() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hash" << "id" << "priority"); |
|
||||||
QString hash = request().posts["hash"]; |
|
||||||
int file_id = request().posts["id"].toInt(); |
|
||||||
int priority = request().posts["priority"].toInt(); |
|
||||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
||||||
|
|
||||||
if (h.is_valid() && h.has_metadata()) |
|
||||||
h.file_priority(file_id, priority); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_getGlobalUpLimit() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
print(QByteArray::number(QBtSession::instance()->getSession()->settings().upload_rate_limit)); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_getGlobalDlLimit() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
print(QByteArray::number(QBtSession::instance()->getSession()->settings().download_rate_limit)); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_setGlobalUpLimit() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("limit"); |
|
||||||
qlonglong limit = request().posts["limit"].toLongLong(); |
|
||||||
if (limit == 0) limit = -1; |
|
||||||
|
|
||||||
QBtSession::instance()->setUploadRateLimit(limit); |
|
||||||
if (Preferences::instance()->isAltBandwidthEnabled()) |
|
||||||
Preferences::instance()->setAltGlobalUploadLimit(limit / 1024.); |
|
||||||
else |
|
||||||
Preferences::instance()->setGlobalUploadLimit(limit / 1024.); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_setGlobalDlLimit() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("limit"); |
|
||||||
qlonglong limit = request().posts["limit"].toLongLong(); |
|
||||||
if (limit == 0) limit = -1; |
|
||||||
|
|
||||||
QBtSession::instance()->setDownloadRateLimit(limit); |
|
||||||
if (Preferences::instance()->isAltBandwidthEnabled()) |
|
||||||
Preferences::instance()->setAltGlobalDownloadLimit(limit / 1024.); |
|
||||||
else |
|
||||||
Preferences::instance()->setGlobalDownloadLimit(limit / 1024.); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_getTorrentUpLimit() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hash"); |
|
||||||
QString hash = request().posts["hash"]; |
|
||||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
||||||
|
|
||||||
if (h.is_valid()) |
|
||||||
print(QByteArray::number(h.upload_limit())); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_getTorrentDlLimit() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hash"); |
|
||||||
QString hash = request().posts["hash"]; |
|
||||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
||||||
|
|
||||||
if (h.is_valid()) |
|
||||||
print(QByteArray::number(h.download_limit())); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_setTorrentUpLimit() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hash" << "limit"); |
|
||||||
QString hash = request().posts["hash"]; |
|
||||||
qlonglong limit = request().posts["limit"].toLongLong(); |
|
||||||
if (limit == 0) limit = -1; |
|
||||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
||||||
|
|
||||||
if (h.is_valid()) |
|
||||||
h.set_upload_limit(limit); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_setTorrentDlLimit() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hash" << "limit"); |
|
||||||
QString hash = request().posts["hash"]; |
|
||||||
qlonglong limit = request().posts["limit"].toLongLong(); |
|
||||||
if (limit == 0) limit = -1; |
|
||||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
||||||
|
|
||||||
if (h.is_valid()) |
|
||||||
h.set_download_limit(limit); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_toggleAlternativeSpeedLimits() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
QBtSession::instance()->useAlternativeSpeedsLimit(!Preferences::instance()->isAltBandwidthEnabled()); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_alternativeSpeedLimitsEnabled() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
print(QByteArray::number(Preferences::instance()->isAltBandwidthEnabled())); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_toggleSequentialDownload() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hashes"); |
|
||||||
QStringList hashes = request().posts["hashes"].split("|"); |
|
||||||
foreach (const QString &hash, hashes) { |
|
||||||
try { |
|
||||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
||||||
h.toggleSequentialDownload(); |
|
||||||
} |
|
||||||
catch(invalid_handle&) {} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_toggleFirstLastPiecePrio() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hashes"); |
|
||||||
QStringList hashes = request().posts["hashes"].split("|"); |
|
||||||
foreach (const QString &hash, hashes) { |
|
||||||
try { |
|
||||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
||||||
h.toggleFirstLastPiecePrio(); |
|
||||||
} |
|
||||||
catch(invalid_handle&) {} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_delete() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hashes"); |
|
||||||
QStringList hashes = request().posts["hashes"].split("|"); |
|
||||||
foreach (const QString &hash, hashes) |
|
||||||
QBtSession::instance()->deleteTorrent(hash, false); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_deletePerm() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hashes"); |
|
||||||
QStringList hashes = request().posts["hashes"].split("|"); |
|
||||||
foreach (const QString &hash, hashes) |
|
||||||
QBtSession::instance()->deleteTorrent(hash, true); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_increasePrio() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hashes"); |
|
||||||
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 { |
|
||||||
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&) {} |
|
||||||
|
|
||||||
torrent_queue.pop(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_decreasePrio() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hashes"); |
|
||||||
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 { |
|
||||||
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&) {} |
|
||||||
|
|
||||||
torrent_queue.pop(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_topPrio() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hashes"); |
|
||||||
foreach (const QString &hash, request().posts["hashes"].split("|")) { |
|
||||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
||||||
if (h.is_valid()) h.queue_position_top(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_bottomPrio() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hashes"); |
|
||||||
foreach (const QString &hash, request().posts["hashes"].split("|")) { |
|
||||||
QTorrentHandle h = QBtSession::instance()->getTorrentHandle(hash); |
|
||||||
if (h.is_valid()) h.queue_position_bottom(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::action_command_recheck() |
|
||||||
{ |
|
||||||
CHECK_URI(0); |
|
||||||
CHECK_PARAMETERS("hash"); |
|
||||||
QBtSession::instance()->recheckTorrent(request().posts["hash"]); |
|
||||||
} |
|
||||||
|
|
||||||
bool RequestHandler::isPublicScope() |
|
||||||
{ |
|
||||||
return (scope_ == DEFAULT_SCOPE || scope_ == VERSION_INFO); |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::processRequest() |
|
||||||
{ |
|
||||||
if (args_.contains(".") || args_.contains("..")) { |
|
||||||
qDebug() << Q_FUNC_INFO << "Invalid path:" << request().path; |
|
||||||
status(404, "Not Found"); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
if (!isPublicScope() && !sessionActive()) { |
|
||||||
status(403, "Forbidden"); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
if (actions_.value(scope_).value(action_) != 0) { |
|
||||||
(this->*(actions_[scope_][action_]))(); |
|
||||||
} |
|
||||||
else { |
|
||||||
status(404, "Not Found"); |
|
||||||
qDebug() << Q_FUNC_INFO << "Resource not found:" << request().path; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void RequestHandler::parsePath() |
|
||||||
{ |
|
||||||
if(request().path == "/") action_ = WEBUI_ACTION; |
|
||||||
|
|
||||||
// check action for requested path
|
|
||||||
QStringList pathItems = request().path.split('/', QString::SkipEmptyParts); |
|
||||||
if (!pathItems.empty()) { |
|
||||||
if (actions_.contains(pathItems.front())) { |
|
||||||
scope_ = pathItems.front(); |
|
||||||
pathItems.pop_front(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (!pathItems.empty()) { |
|
||||||
if (actions_[scope_].contains(pathItems.front())) { |
|
||||||
action_ = pathItems.front(); |
|
||||||
pathItems.pop_front(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
args_ = pathItems; |
|
||||||
} |
|
||||||
|
|
||||||
RequestHandler::RequestHandler(const HttpRequest &request, const HttpEnvironment &env, WebApplication *app) |
|
||||||
: AbstractRequestHandler(request, env, app), scope_(DEFAULT_SCOPE), action_(DEFAULT_ACTION) |
|
||||||
{ |
|
||||||
parsePath(); |
|
||||||
} |
|
||||||
|
|
||||||
QMap<QString, QMap<QString, RequestHandler::Action> > RequestHandler::actions_ = RequestHandler::initializeActions(); |
|
@ -1,108 +0,0 @@ |
|||||||
/*
|
|
||||||
* Bittorrent Client using Qt and libtorrent. |
|
||||||
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru> |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or |
|
||||||
* modify it under the terms of the GNU General Public License |
|
||||||
* as published by the Free Software Foundation; either version 2 |
|
||||||
* of the License, or (at your option) any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; if not, write to the Free Software |
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
||||||
* |
|
||||||
* In addition, as a special exception, the copyright holders give permission to |
|
||||||
* link this program with the OpenSSL project's "OpenSSL" library (or with |
|
||||||
* modified versions of it that use the same license as the "OpenSSL" library), |
|
||||||
* and distribute the linked executables. You must obey the GNU General Public |
|
||||||
* License in all respects for all of the code used other than "OpenSSL". If you |
|
||||||
* 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. |
|
||||||
*/ |
|
||||||
|
|
||||||
#ifndef REQUESTHANDLER_H |
|
||||||
#define REQUESTHANDLER_H |
|
||||||
|
|
||||||
#include <QStringList> |
|
||||||
#include "httptypes.h" |
|
||||||
#include "abstractrequesthandler.h" |
|
||||||
|
|
||||||
class WebApplication; |
|
||||||
|
|
||||||
class RequestHandler: public AbstractRequestHandler |
|
||||||
{ |
|
||||||
public: |
|
||||||
RequestHandler( |
|
||||||
const HttpRequest& request, const HttpEnvironment& env, |
|
||||||
WebApplication* app); |
|
||||||
|
|
||||||
private: |
|
||||||
// Actions
|
|
||||||
void action_public_webui(); |
|
||||||
void action_public_index(); |
|
||||||
void action_public_login(); |
|
||||||
void action_public_logout(); |
|
||||||
void action_public_theme(); |
|
||||||
void action_public_images(); |
|
||||||
void action_query_torrents(); |
|
||||||
void action_query_preferences(); |
|
||||||
void action_query_transferInfo(); |
|
||||||
void action_query_propertiesGeneral(); |
|
||||||
void action_query_propertiesTrackers(); |
|
||||||
void action_query_propertiesFiles(); |
|
||||||
void action_sync_maindata(); |
|
||||||
void action_command_shutdown(); |
|
||||||
void action_command_download(); |
|
||||||
void action_command_upload(); |
|
||||||
void action_command_addTrackers(); |
|
||||||
void action_command_resumeAll(); |
|
||||||
void action_command_pauseAll(); |
|
||||||
void action_command_resume(); |
|
||||||
void action_command_pause(); |
|
||||||
void action_command_setPreferences(); |
|
||||||
void action_command_setFilePrio(); |
|
||||||
void action_command_getGlobalUpLimit(); |
|
||||||
void action_command_getGlobalDlLimit(); |
|
||||||
void action_command_setGlobalUpLimit(); |
|
||||||
void action_command_setGlobalDlLimit(); |
|
||||||
void action_command_getTorrentUpLimit(); |
|
||||||
void action_command_getTorrentDlLimit(); |
|
||||||
void action_command_setTorrentUpLimit(); |
|
||||||
void action_command_setTorrentDlLimit(); |
|
||||||
void action_command_alternativeSpeedLimitsEnabled(); |
|
||||||
void action_command_toggleAlternativeSpeedLimits(); |
|
||||||
void action_command_toggleSequentialDownload(); |
|
||||||
void action_command_toggleFirstLastPiecePrio(); |
|
||||||
void action_command_delete(); |
|
||||||
void action_command_deletePerm(); |
|
||||||
void action_command_increasePrio(); |
|
||||||
void action_command_decreasePrio(); |
|
||||||
void action_command_topPrio(); |
|
||||||
void action_command_bottomPrio(); |
|
||||||
void action_command_recheck(); |
|
||||||
void action_version_api(); |
|
||||||
void action_version_api_min(); |
|
||||||
void action_version_qbittorrent(); |
|
||||||
|
|
||||||
typedef void (RequestHandler::*Action)(); |
|
||||||
|
|
||||||
QString scope_; |
|
||||||
QString action_; |
|
||||||
QStringList args_; |
|
||||||
|
|
||||||
void processRequest(); |
|
||||||
|
|
||||||
bool isPublicScope(); |
|
||||||
void parsePath(); |
|
||||||
|
|
||||||
static QMap<QString, QMap<QString, Action> > initializeActions(); |
|
||||||
static QMap<QString, QMap<QString, Action> > actions_; |
|
||||||
}; |
|
||||||
|
|
||||||
#endif // REQUESTHANDLER_H
|
|
@ -0,0 +1,41 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent. |
||||||
|
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru> |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef WEBSESSIONDATA |
||||||
|
#define WEBSESSIONDATA |
||||||
|
|
||||||
|
#include <QVariant> |
||||||
|
|
||||||
|
struct WebSessionData |
||||||
|
{ |
||||||
|
QVariantMap syncMainDataLastResponse; |
||||||
|
QVariantMap syncMainDataLastAcceptedResponse; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // WEBSESSIONDATA
|
||||||
|
|
@ -0,0 +1,102 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent. |
||||||
|
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru> |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "webui.h" |
||||||
|
#include "http/server.h" |
||||||
|
#include "webapplication.h" |
||||||
|
#include "dnsupdater.h" |
||||||
|
#include "preferences.h" |
||||||
|
#include "logger.h" |
||||||
|
|
||||||
|
WebUI::WebUI(QObject *parent) : QObject(parent) |
||||||
|
{ |
||||||
|
init(); |
||||||
|
connect(Preferences::instance(), SIGNAL(changed()), SLOT(init())); |
||||||
|
} |
||||||
|
|
||||||
|
void WebUI::init() |
||||||
|
{ |
||||||
|
Preferences* const pref = Preferences::instance(); |
||||||
|
Logger* const logger = Logger::instance(); |
||||||
|
|
||||||
|
if (pref->isWebUiEnabled()) { |
||||||
|
const quint16 port = pref->getWebUiPort(); |
||||||
|
|
||||||
|
if (httpServer_) { |
||||||
|
if (httpServer_->serverPort() != port) |
||||||
|
httpServer_->close(); |
||||||
|
} |
||||||
|
else { |
||||||
|
webapp_ = new WebApplication(this); |
||||||
|
httpServer_ = new Http::Server(webapp_, this); |
||||||
|
} |
||||||
|
|
||||||
|
#ifndef QT_NO_OPENSSL |
||||||
|
if (pref->isWebUiHttpsEnabled()) { |
||||||
|
QSslCertificate cert(pref->getWebUiHttpsCertificate()); |
||||||
|
QSslKey key; |
||||||
|
key = QSslKey(pref->getWebUiHttpsKey(), QSsl::Rsa); |
||||||
|
if (!cert.isNull() && !key.isNull()) |
||||||
|
httpServer_->enableHttps(cert, key); |
||||||
|
else |
||||||
|
httpServer_->disableHttps(); |
||||||
|
} |
||||||
|
else { |
||||||
|
httpServer_->disableHttps(); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
if (!httpServer_->isListening()) { |
||||||
|
bool success = httpServer_->listen(QHostAddress::Any, port); |
||||||
|
if (success) |
||||||
|
logger->addMessage(tr("The Web UI is listening on port %1").arg(port)); |
||||||
|
else |
||||||
|
logger->addMessage(tr("Web User Interface Error - Unable to bind Web UI to port %1").arg(port), Log::CRITICAL); |
||||||
|
} |
||||||
|
|
||||||
|
// DynDNS
|
||||||
|
if (pref->isDynDNSEnabled()) { |
||||||
|
if (!dynDNSUpdater_) |
||||||
|
dynDNSUpdater_ = new DNSUpdater(this); |
||||||
|
else |
||||||
|
dynDNSUpdater_->updateCredentials(); |
||||||
|
} |
||||||
|
else { |
||||||
|
if (dynDNSUpdater_) |
||||||
|
delete dynDNSUpdater_; |
||||||
|
} |
||||||
|
} |
||||||
|
else { |
||||||
|
if (httpServer_) |
||||||
|
delete httpServer_; |
||||||
|
if (webapp_) |
||||||
|
delete webapp_; |
||||||
|
if (dynDNSUpdater_) |
||||||
|
delete dynDNSUpdater_; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
/*
|
||||||
|
* Bittorrent Client using Qt and libtorrent. |
||||||
|
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru> |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or |
||||||
|
* modify it under the terms of the GNU General Public License |
||||||
|
* as published by the Free Software Foundation; either version 2 |
||||||
|
* of the License, or (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; if not, write to the Free Software |
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||||||
|
* |
||||||
|
* In addition, as a special exception, the copyright holders give permission to |
||||||
|
* link this program with the OpenSSL project's "OpenSSL" library (or with |
||||||
|
* modified versions of it that use the same license as the "OpenSSL" library), |
||||||
|
* and distribute the linked executables. You must obey the GNU General Public |
||||||
|
* License in all respects for all of the code used other than "OpenSSL". If you |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef WEBUI_H |
||||||
|
#define WEBUI_H |
||||||
|
|
||||||
|
#include <QObject> |
||||||
|
#include <QPointer> |
||||||
|
|
||||||
|
namespace Http { class Server; } |
||||||
|
class DNSUpdater; |
||||||
|
class AbstractWebApplication; |
||||||
|
|
||||||
|
class WebUI : public QObject |
||||||
|
{ |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
public: |
||||||
|
explicit WebUI(QObject *parent = 0); |
||||||
|
|
||||||
|
private slots: |
||||||
|
void init(); |
||||||
|
|
||||||
|
private: |
||||||
|
QPointer<Http::Server> httpServer_; |
||||||
|
QPointer<DNSUpdater> dynDNSUpdater_; |
||||||
|
QPointer<AbstractWebApplication> webapp_; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif // WEBUI_H
|
@ -1,30 +1,25 @@ |
|||||||
INCLUDEPATH += $$PWD |
INCLUDEPATH += $$PWD |
||||||
|
|
||||||
HEADERS += $$PWD/httpserver.h \ |
HEADERS += \ |
||||||
$$PWD/httpconnection.h \ |
$$PWD/webui.h \ |
||||||
$$PWD/btjson.h \ |
$$PWD/btjson.h \ |
||||||
$$PWD/prefjson.h \ |
$$PWD/prefjson.h \ |
||||||
$$PWD/jsonutils.h \ |
$$PWD/jsonutils.h \ |
||||||
$$PWD/extra_translations.h \ |
$$PWD/extra_translations.h \ |
||||||
$$PWD/webapplication.h \ |
$$PWD/webapplication.h \ |
||||||
$$PWD/abstractrequesthandler.h \ |
$$PWD/qtorrentfilter.h \ |
||||||
$$PWD/requesthandler.h \ |
$$PWD/websessiondata.h \ |
||||||
$$PWD/qtorrentfilter.h |
$$PWD/abstractwebapplication.h |
||||||
|
|
||||||
SOURCES += $$PWD/httpserver.cpp \ |
SOURCES += \ |
||||||
$$PWD/httpconnection.cpp \ |
$$PWD/webui.cpp \ |
||||||
$$PWD/httprequestparser.cpp \ |
|
||||||
$$PWD/httpresponsegenerator.cpp \ |
|
||||||
$$PWD/btjson.cpp \ |
$$PWD/btjson.cpp \ |
||||||
$$PWD/prefjson.cpp \ |
$$PWD/prefjson.cpp \ |
||||||
$$PWD/webapplication.cpp \ |
$$PWD/webapplication.cpp \ |
||||||
$$PWD/abstractrequesthandler.cpp \ |
$$PWD/qtorrentfilter.cpp \ |
||||||
$$PWD/requesthandler.cpp \ |
$$PWD/abstractwebapplication.cpp |
||||||
$$PWD/qtorrentfilter.cpp |
|
||||||
|
|
||||||
# QJson JSON parser/serializer for using with Qt4 |
# QJson JSON parser/serializer for using with Qt4 |
||||||
lessThan(QT_MAJOR_VERSION, 5) { |
lessThan(QT_MAJOR_VERSION, 5): include(qjson/qjson.pri) |
||||||
include(qjson/qjson.pri) |
|
||||||
} |
|
||||||
|
|
||||||
RESOURCES += $$PWD/webui.qrc |
RESOURCES += $$PWD/webui.qrc |
||||||
|
Loading…
Reference in new issue