Fix prefjson::setPreferences() doesn't actually save.

This commit is contained in:
Vladimir Golovnev (Glassez)
2015-01-28 12:03:22 +03:00
parent 8e1698d563
commit 2707f5205f
37 changed files with 1972 additions and 1763 deletions

View File

@@ -3,7 +3,6 @@ INCLUDEPATH += $$PWD
unix:!macx:dbus: include(qtnotify/qtnotify.pri)
include(qtlibtorrent/qtlibtorrent.pri)
include(tracker/tracker.pri)
HEADERS += \
$$PWD/misc.h \
@@ -16,10 +15,15 @@ HEADERS += \
$$PWD/smtp.h \
$$PWD/dnsupdater.h \
$$PWD/logger.h \
$$PWD/httptypes.h \
$$PWD/httprequestparser.h \
$$PWD/httpresponsegenerator.h \
$$PWD/preferences.h
$$PWD/preferences.h \
$$PWD/qtracker.h \
$$PWD/http/irequesthandler.h \
$$PWD/http/connection.h \
$$PWD/http/requestparser.h \
$$PWD/http/responsegenerator.h \
$$PWD/http/server.h \
$$PWD/http/types.h \
$$PWD/http/responsebuilder.h
SOURCES += \
$$PWD/downloadthread.cpp \
@@ -30,6 +34,10 @@ SOURCES += \
$$PWD/smtp.cpp \
$$PWD/dnsupdater.cpp \
$$PWD/logger.cpp \
$$PWD/httprequestparser.cpp \
$$PWD/httpresponsegenerator.cpp \
$$PWD/preferences.cpp
$$PWD/preferences.cpp \
$$PWD/qtracker.cpp \
$$PWD/http/connection.cpp \
$$PWD/http/requestparser.cpp \
$$PWD/http/responsegenerator.cpp \
$$PWD/http/server.cpp \
$$PWD/http/responsebuilder.cpp

View File

@@ -0,0 +1,111 @@
/*
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#include <QTcpSocket>
#include <QDebug>
#include "types.h"
#include "requestparser.h"
#include "responsegenerator.h"
#include "irequesthandler.h"
#include "connection.h"
using namespace Http;
Connection::Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent)
: QObject(parent)
, m_socket(socket)
, m_requestHandler(requestHandler)
{
m_socket->setParent(this);
connect(m_socket, SIGNAL(readyRead()), SLOT(read()));
connect(m_socket, SIGNAL(disconnected()), SLOT(deleteLater()));
}
Connection::~Connection()
{
}
void Connection::read()
{
m_receivedData.append(m_socket->readAll());
Request request;
RequestParser::ErrorCode err = RequestParser::parse(m_receivedData, request);
switch (err)
{
case RequestParser::IncompleteRequest:
// Partial request waiting for the rest
break;
case RequestParser::BadRequest:
sendResponse(Response(400, "Bad Request"));
break;
case RequestParser::NoError:
Environment env;
env.clientAddress = m_socket->peerAddress();
Response response = m_requestHandler->processRequest(request, env);
if (acceptsGzipEncoding(request.headers["accept-encoding"]))
response.headers[HEADER_CONTENT_ENCODING] = "gzip";
sendResponse(response);
break;
}
}
void Connection::sendResponse(const Response &response)
{
m_socket->write(ResponseGenerator::generate(response));
m_socket->disconnectFromHost();
}
bool Connection::acceptsGzipEncoding(const QString &encoding)
{
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;
}

View File

@@ -0,0 +1,71 @@
/*
* 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
* 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.
*
* Contact : chris@qbittorrent.org
*/
#ifndef HTTP_CONNECTION_H
#define HTTP_CONNECTION_H
#include <QObject>
#include "types.h"
QT_BEGIN_NAMESPACE
class QTcpSocket;
QT_END_NAMESPACE
namespace Http
{
class IRequestHandler;
class Connection : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Connection)
public:
Connection(QTcpSocket *socket, IRequestHandler *requestHandler, QObject *parent = 0);
~Connection();
private slots:
void read();
private:
static bool acceptsGzipEncoding(const QString &encoding);
void sendResponse(const Response &response);
QTcpSocket *m_socket;
IRequestHandler *m_requestHandler;
QByteArray m_receivedData;
};
}
#endif // HTTP_CONNECTION_H

View File

@@ -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

View File

@@ -38,7 +38,7 @@
#include <QDir>
#include <QTemporaryFile>
#include <QDebug>
#include "httprequestparser.h"
#include "requestparser.h"
const QByteArray EOL("\r\n");
const QByteArray EOH("\r\n\r\n");
@@ -51,19 +51,21 @@ inline QString unquoted(const QString& str)
return str;
}
HttpRequestParser::ErrorCode HttpRequestParser::parse(const QByteArray& data, HttpRequest& request, uint maxContentLength)
using namespace Http;
RequestParser::ErrorCode RequestParser::parse(const QByteArray& data, Request& request, uint maxContentLength)
{
return HttpRequestParser(maxContentLength).parseHttpRequest(data, request);
return RequestParser(maxContentLength).parseHttpRequest(data, request);
}
HttpRequestParser::HttpRequestParser(uint maxContentLength)
: maxContentLength_(maxContentLength)
RequestParser::RequestParser(uint maxContentLength)
: m_maxContentLength(maxContentLength)
{
}
HttpRequestParser::ErrorCode HttpRequestParser::parseHttpRequest(const QByteArray& data, HttpRequest& request)
RequestParser::ErrorCode RequestParser::parseHttpRequest(const QByteArray& data, Request& request)
{
request_ = HttpRequest();
m_request = Request();
// Parse HTTP request header
const int header_end = data.indexOf(EOH);
@@ -81,10 +83,10 @@ HttpRequestParser::ErrorCode HttpRequestParser::parseHttpRequest(const QByteArra
// Parse HTTP request message
int content_length = 0;
if (request_.headers.contains("content-length"))
if (m_request.headers.contains("content-length"))
{
content_length = request_.headers["content-length"].toInt();
if (content_length > static_cast<int>(maxContentLength_))
content_length = m_request.headers["content-length"].toInt();
if (content_length > static_cast<int>(m_maxContentLength))
{
qWarning() << Q_FUNC_INFO << "bad request: message too long";
return BadRequest;
@@ -108,20 +110,20 @@ HttpRequestParser::ErrorCode HttpRequestParser::parseHttpRequest(const QByteArra
// qDebug() << "HTTP Request header:";
// qDebug() << data.left(header_end) << "\n";
request = request_;
request = m_request;
return NoError;
}
bool HttpRequestParser::parseStartingLine(const QString &line)
bool RequestParser::parseStartingLine(const QString &line)
{
const QRegExp rx("^([A-Z]+)\\s+(\\S+)\\s+HTTP/\\d\\.\\d$");
if (rx.indexIn(line.trimmed()) >= 0)
{
request_.method = rx.cap(1);
m_request.method = rx.cap(1);
QUrl url = QUrl::fromEncoded(rx.cap(2).toLatin1());
request_.path = url.path(); // Path
m_request.path = url.path(); // Path
// Parse GET parameters
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
@@ -132,7 +134,7 @@ bool HttpRequestParser::parseStartingLine(const QString &line)
while (i.hasNext())
{
QPair<QString, QString> pair = i.next();
request_.gets[pair.first] = pair.second;
m_request.gets[pair.first] = pair.second;
}
return true;
@@ -142,7 +144,7 @@ bool HttpRequestParser::parseStartingLine(const QString &line)
return false;
}
bool HttpRequestParser::parseHeaderLine(const QString &line, QPair<QString, QString>& out)
bool RequestParser::parseHeaderLine(const QString &line, QPair<QString, QString>& out)
{
int i = line.indexOf(QLatin1Char(':'));
if (i == -1)
@@ -155,7 +157,7 @@ bool HttpRequestParser::parseHeaderLine(const QString &line, QPair<QString, QStr
return true;
}
bool HttpRequestParser::parseHttpHeader(const QByteArray &data)
bool RequestParser::parseHttpHeader(const QByteArray &data)
{
QString str = QString::fromUtf8(data);
QStringList lines = str.trimmed().split(EOL);
@@ -191,13 +193,13 @@ bool HttpRequestParser::parseHttpHeader(const QByteArray &data)
if (!parseHeaderLine(*it, header))
return false;
request_.headers[header.first] = header.second;
m_request.headers[header.first] = header.second;
}
return true;
}
QList<QByteArray> HttpRequestParser::splitMultipartData(const QByteArray& data, const QByteArray& boundary)
QList<QByteArray> RequestParser::splitMultipartData(const QByteArray& data, const QByteArray& boundary)
{
QList<QByteArray> ret;
QByteArray sep = boundary + EOL;
@@ -223,14 +225,14 @@ QList<QByteArray> HttpRequestParser::splitMultipartData(const QByteArray& data,
return ret;
}
bool HttpRequestParser::parseContent(const QByteArray& data)
bool RequestParser::parseContent(const QByteArray& data)
{
// Parse message content
qDebug() << Q_FUNC_INFO << "Content-Length: " << request_.headers["content-length"];
qDebug() << Q_FUNC_INFO << "Content-Length: " << m_request.headers["content-length"];
qDebug() << Q_FUNC_INFO << "data.size(): " << data.size();
// Parse url-encoded POST data
if (request_.headers["content-type"].startsWith("application/x-www-form-urlencoded"))
if (m_request.headers["content-type"].startsWith("application/x-www-form-urlencoded"))
{
QUrl url;
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
@@ -243,7 +245,7 @@ bool HttpRequestParser::parseContent(const QByteArray& data)
while (i.hasNext())
{
QPair<QString, QString> pair = i.next();
request_.posts[pair.first.toLower()] = pair.second;
m_request.posts[pair.first.toLower()] = pair.second;
}
return true;
@@ -268,7 +270,7 @@ Content-Disposition: form-data; name=\"Upload\"
Submit Query
--cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5--
**/
QString content_type = request_.headers["content-type"];
QString content_type = m_request.headers["content-type"];
if (content_type.startsWith("multipart/form-data"))
{
const QRegExp boundaryRegexQuoted("boundary=\"([ \\w'()+,-\\./:=\\?]+)\"");
@@ -309,7 +311,7 @@ Submit Query
return false;
}
bool HttpRequestParser::parseFormData(const QByteArray& data)
bool RequestParser::parseFormData(const QByteArray& data)
{
// Parse form data header
const int header_end = data.indexOf(EOH);
@@ -347,17 +349,17 @@ bool HttpRequestParser::parseFormData(const QByteArray& data)
ufile.type = disposition["content-type"];
ufile.data = data.mid(header_end + EOH.length());
request_.files[disposition["name"]] = ufile;
m_request.files[disposition["name"]] = ufile;
}
else
{
request_.posts[disposition["name"]] = QString::fromUtf8(data.mid(header_end + EOH.length()));
m_request.posts[disposition["name"]] = QString::fromUtf8(data.mid(header_end + EOH.length()));
}
return true;
}
bool HttpRequestParser::parseHeaderValue(const QString& value, QStringMap& out)
bool RequestParser::parseHeaderValue(const QString& value, QStringMap& out)
{
QStringList items = value.split(QLatin1Char(';'));
out[""] = items[0];

View File

@@ -29,24 +29,27 @@
* Contact : chris@qbittorrent.org
*/
#ifndef HTTPREQUESTPARSER_H
#define HTTPREQUESTPARSER_H
#ifndef HTTP_REQUESTPARSER_H
#define HTTP_REQUESTPARSER_H
#include "httptypes.h"
#include "types.h"
class HttpRequestParser
namespace Http
{
class RequestParser
{
public:
enum ErrorCode { NoError = 0, IncompleteRequest, BadRequest };
// when result != NoError parsed request is undefined
// Warning! Header names are converted to lower-case.
static ErrorCode parse(const QByteArray& data, HttpRequest& request, uint maxContentLength = 10000000 /* ~10MB */);
static ErrorCode parse(const QByteArray& data, Request& request, uint maxContentLength = 10000000 /* ~10MB */);
private:
HttpRequestParser(uint maxContentLength);
RequestParser(uint maxContentLength);
ErrorCode parseHttpRequest(const QByteArray& data, HttpRequest& request);
ErrorCode parseHttpRequest(const QByteArray& data, Request& request);
bool parseHttpHeader(const QByteArray& data);
bool parseStartingLine(const QString &line);
@@ -57,8 +60,10 @@ private:
static bool parseHeaderLine(const QString& line, QPair<QString, QString>& out);
static bool parseHeaderValue(const QString& value, QStringMap& out);
const uint maxContentLength_;
HttpRequest request_;
const uint m_maxContentLength;
Request m_request;
};
#endif
}
#endif // HTTP_REQUESTPARSER_H

View File

@@ -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;
}

View File

@@ -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

View File

@@ -30,11 +30,13 @@
*/
#include <zlib.h>
#include "httpresponsegenerator.h"
#include "responsegenerator.h"
bool gCompress(QByteArray data, QByteArray& dest_buffer);
QByteArray HttpResponseGenerator::generate(HttpResponse response)
using namespace Http;
QByteArray ResponseGenerator::generate(Response response)
{
if (response.headers[HEADER_CONTENT_ENCODING] == "gzip")
{

View File

@@ -30,15 +30,20 @@
*/
#ifndef HTTPRESPONSEGENERATOR_H
#define HTTPRESPONSEGENERATOR_H
#ifndef HTTP_RESPONSEGENERATOR_H
#define HTTP_RESPONSEGENERATOR_H
#include "httptypes.h"
#include "types.h"
class HttpResponseGenerator
namespace Http
{
class ResponseGenerator
{
public:
static QByteArray generate(HttpResponse response);
static QByteArray generate(Response response);
};
#endif
}
#endif // HTTP_RESPONSEGENERATOR_H

100
src/core/http/server.cpp Normal file
View File

@@ -0,0 +1,100 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
* Copyright (C) 2006 Ishan Arora <ishan@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.
*/
#ifndef QT_NO_OPENSSL
#include <QSslSocket>
#else
#include <QTcpSocket>
#endif
#include "connection.h"
#include "server.h"
using namespace Http;
Server::Server(IRequestHandler *requestHandler, QObject* parent)
: QTcpServer(parent)
, m_requestHandler(requestHandler)
#ifndef QT_NO_OPENSSL
, m_https(false)
#endif
{
}
Server::~Server()
{
}
#ifndef QT_NO_OPENSSL
void Server::enableHttps(const QSslCertificate &certificate, const QSslKey &key)
{
m_certificate = certificate;
m_key = key;
m_https = true;
}
void Server::disableHttps()
{
m_https = false;
m_certificate.clear();
m_key.clear();
}
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
void Server::incomingConnection(qintptr socketDescriptor)
#else
void Server::incomingConnection(int socketDescriptor)
#endif
{
QTcpSocket *serverSocket;
#ifndef QT_NO_OPENSSL
if (m_https)
serverSocket = new QSslSocket(this);
else
#endif
serverSocket = new QTcpSocket(this);
if (serverSocket->setSocketDescriptor(socketDescriptor))
{
#ifndef QT_NO_OPENSSL
if (m_https)
{
static_cast<QSslSocket*>(serverSocket)->setProtocol(QSsl::AnyProtocol);
static_cast<QSslSocket*>(serverSocket)->setPrivateKey(m_key);
static_cast<QSslSocket*>(serverSocket)->setLocalCertificate(m_certificate);
static_cast<QSslSocket*>(serverSocket)->startServerEncryption();
}
#endif
new Connection(serverSocket, m_requestHandler, this);
}
else
{
serverSocket->deleteLater();
}
}

80
src/core/http/server.h Normal file
View File

@@ -0,0 +1,80 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2014 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Ishan Arora and 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.
*
* Contact : chris@qbittorrent.org
*/
#ifndef HTTP_SERVER_H
#define HTTP_SERVER_H
#include <QTcpServer>
#ifndef QT_NO_OPENSSL
#include <QSslCertificate>
#include <QSslKey>
#endif
namespace Http
{
class IRequestHandler;
class Connection;
class Server : public QTcpServer
{
Q_OBJECT
Q_DISABLE_COPY(Server)
public:
Server(IRequestHandler *requestHandler, QObject *parent = 0);
~Server();
#ifndef QT_NO_OPENSSL
void enableHttps(const QSslCertificate &certificate, const QSslKey &key);
void disableHttps();
#endif
private:
#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
void incomingConnection(qintptr socketDescriptor);
#else
void incomingConnection(int socketDescriptor);
#endif
private:
IRequestHandler *m_requestHandler;
#ifndef QT_NO_OPENSSL
bool m_https;
QSslCertificate m_certificate;
QSslKey m_key;
#endif
};
}
#endif // HTTP_SERVER_H

View File

@@ -26,8 +26,8 @@
* exception statement from your version.
*/
#ifndef HTTPTYPES_H
#define HTTPTYPES_H
#ifndef HTTP_TYPES_H
#define HTTP_TYPES_H
#include <QString>
#include <QMap>
@@ -35,6 +35,9 @@
typedef QMap<QString, QString> QStringMap;
namespace Http
{
const QString HEADER_SET_COOKIE = "Set-Cookie";
const QString HEADER_CONTENT_TYPE = "Content-Type";
const QString HEADER_CONTENT_ENCODING = "Content-Encoding";
@@ -48,43 +51,45 @@ const QString CONTENT_TYPE_JS = "text/javascript; charset=UTF-8";
const QString CONTENT_TYPE_PNG = "image/png";
const QString CONTENT_TYPE_TXT = "text/plain; charset=UTF-8";
struct HttpEnvironment
struct Environment
{
QHostAddress clientAddress;
QHostAddress clientAddress;
};
struct UploadedFile
{
QString filename; // original filename
QString type; // MIME type
QByteArray data; // File data
QString filename; // original filename
QString type; // MIME type
QByteArray data; // File data
};
struct HttpRequest
struct Request
{
QString method;
QString path;
QStringMap headers;
QStringMap gets;
QStringMap posts;
QMap<QString, UploadedFile> files;
QString method;
QString path;
QStringMap headers;
QStringMap gets;
QStringMap posts;
QMap<QString, UploadedFile> files;
};
struct HttpResponseStatus
struct ResponseStatus
{
uint code;
QString text;
uint code;
QString text;
HttpResponseStatus(uint code = 200, const QString& text = "OK"): code(code), text(text) {}
ResponseStatus(uint code = 200, const QString& text = "OK"): code(code), text(text) {}
};
struct HttpResponse
struct Response
{
HttpResponseStatus status;
QStringMap headers;
QByteArray content;
ResponseStatus status;
QStringMap headers;
QByteArray content;
HttpResponse(uint code = 200, const QString& text = "OK"): status(code, text) {}
Response(uint code = 200, const QString& text = "OK"): status(code, text) {}
};
#endif // HTTPTYPES_H
}
#endif // HTTP_TYPES_H

View File

@@ -57,7 +57,6 @@
#include "geoipmanager.h"
#endif
#include "torrentpersistentdata.h"
#include "httpserver.h"
#include "bandwidthscheduler.h"
#include <libtorrent/version.hpp>
#include <libtorrent/extensions/ut_metadata.hpp>
@@ -79,7 +78,6 @@
#include <libtorrent/magnet_uri.hpp>
#include <queue>
#include <string.h>
#include "dnsupdater.h"
#if LIBTORRENT_VERSION_NUM < 10000
#include <libtorrent/upnp.hpp>
@@ -117,7 +115,6 @@ QBtSession::QBtSession()
#if LIBTORRENT_VERSION_NUM < 10000
, m_upnp(0), m_natpmp(0)
#endif
, m_dynDNSUpdater(0)
, m_alertDispatcher(0)
{
BigRatioTimer = new QTimer(this);
@@ -159,6 +156,7 @@ QBtSession::QBtSession()
connect(m_scanFolders, SIGNAL(torrentsAdded(QStringList&)), SLOT(addTorrentsFromScanFolder(QStringList&)));
// Apply user settings to Bittorrent session
configureSession();
connect(pref, SIGNAL(changed()), SLOT(configureSession()));
// Torrent speed monitor
m_speedMonitor = new TorrentSpeedMonitor(this);
m_torrentStatistics = new TorrentStatistics(this, this);
@@ -191,9 +189,6 @@ QBtSession::~QBtSession() {
delete downloader;
if (bd_scheduler)
delete bd_scheduler;
// HTTP Server
if (httpServer)
delete httpServer;
delete m_alertDispatcher;
delete m_torrentStatistics;
qDebug("Deleting the session");
@@ -583,9 +578,6 @@ void QBtSession::configureSession() {
}else{
disableIPFilter();
}
// Update Web UI
// Use a QTimer because the function can be called from qBtSession constructor
QTimer::singleShot(0, this, SLOT(initWebUi()));
// * Proxy settings
proxy_settings proxySettings;
if (pref->isProxyEnabled()) {
@@ -655,64 +647,6 @@ void QBtSession::configureSession() {
qDebug("Session configured");
}
void QBtSession::initWebUi() {
Preferences* const pref = Preferences::instance();
if (pref->isWebUiEnabled()) {
const quint16 port = pref->getWebUiPort();
if (httpServer) {
if (httpServer->serverPort() != port) {
httpServer->close();
}
} else {
httpServer = new HttpServer(this);
}
#ifndef QT_NO_OPENSSL
if (pref->isWebUiHttpsEnabled()) {
QSslCertificate cert(pref->getWebUiHttpsCertificate());
QSslKey key;
const QByteArray raw_key = pref->getWebUiHttpsKey();
key = QSslKey(raw_key, QSsl::Rsa);
if (!cert.isNull() && !key.isNull())
httpServer->enableHttps(cert, key);
else
httpServer->disableHttps();
} else {
httpServer->disableHttps();
}
#endif
if (!httpServer->isListening()) {
Logger* const logger = Logger::instance();
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 (!m_dynDNSUpdater)
m_dynDNSUpdater = new DNSUpdater(this);
else
m_dynDNSUpdater->updateCredentials();
} else {
if (m_dynDNSUpdater) {
delete m_dynDNSUpdater;
m_dynDNSUpdater = 0;
}
}
} else {
if (httpServer)
delete httpServer;
if (m_dynDNSUpdater) {
delete m_dynDNSUpdater;
m_dynDNSUpdater = 0;
}
}
}
void QBtSession::useAlternativeSpeedsLimit(bool alternative) {
qDebug() << Q_FUNC_INFO << alternative;
// Save new state to remember it on startup
@@ -1495,6 +1429,7 @@ void QBtSession::enableUPnP(bool b) {
s->start_upnp();
s->start_natpmp();
#endif
// TODO: Remove dependency from WebUI
// Use UPnP/NAT-PMP for Web UI too
if (pref->isWebUiEnabled() && pref->useUPnPForWebUIPort()) {
const qint16 port = pref->getWebUiPort();

View File

@@ -90,12 +90,10 @@ namespace libtorrent {
class DownloadThread;
class FilterParserThread;
class HttpServer;
class BandwidthScheduler;
class ScanFoldersModel;
class TorrentSpeedMonitor;
class TorrentStatistics;
class DNSUpdater;
class QAlertDispatcher;
enum TorrentExportFolder {
@@ -209,7 +207,6 @@ public slots:
#endif
void addMagnetInteractive(const QString& uri);
void downloadFromURLList(const QStringList& urls);
void configureSession();
void banIP(QString ip);
void recursiveTorrentDownload(const QTorrentHandle &h);
void unhideMagnet(const QString &hash);
@@ -264,9 +261,9 @@ private slots:
void mergeTorrents(QTorrentHandle& h_ex, boost::intrusive_ptr<libtorrent::torrent_info> t);
void mergeTorrents(QTorrentHandle& h_ex, const QString& magnet_uri);
void exportTorrentFile(const QTorrentHandle &h, TorrentExportFolder folder = RegularTorrentExportFolder);
void initWebUi();
void handleIPFilterParsed(int ruleCount);
void handleIPFilterError();
void configureSession();
signals:
void addedTorrent(const QTorrentHandle& h);
@@ -327,8 +324,6 @@ private:
// IP filtering
QPointer<FilterParserThread> filterParser;
QString filterPath;
// Web UI
QPointer<HttpServer> httpServer;
QList<QUrl> url_skippingDlg;
// GeoIP
#ifndef DISABLE_GUI
@@ -344,8 +339,6 @@ private:
libtorrent::upnp *m_upnp;
libtorrent::natpmp *m_natpmp;
#endif
// DynDNS
DNSUpdater *m_dynDNSUpdater;
QAlertDispatcher* m_alertDispatcher;
TorrentStatistics* m_torrentStatistics;
};

View File

@@ -1,5 +1,6 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -28,163 +29,171 @@
* Contact : chris@qbittorrent.org
*/
#include <QTcpSocket>
#include <libtorrent/bencode.hpp>
#include <libtorrent/entry.hpp>
#include "qtracker.h"
#include "preferences.h"
#include "httpresponsegenerator.h"
#include "httprequestparser.h"
#include <vector>
#include <libtorrent/bencode.hpp>
using namespace libtorrent;
#include "preferences.h"
#include "http/server.h"
#include "qtracker.h"
QTracker::QTracker(QObject *parent) :
QTcpServer(parent)
// QPeer
bool QPeer::operator!=(const QPeer &other) const
{
Q_ASSERT(Preferences::instance()->isTrackerEnabled());
connect(this, SIGNAL(newConnection()), this, SLOT(handlePeerConnection()));
return qhash() != other.qhash();
}
QTracker::~QTracker() {
if (isListening()) {
bool QPeer::operator==(const QPeer &other) const
{
return qhash() == other.qhash();
}
QString QPeer::qhash() const
{
return ip + ":" + QString::number(port);
}
libtorrent::entry QPeer::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);
}
// QTracker
QTracker::QTracker(QObject *parent)
: Http::ResponseBuilder(parent)
, m_server(new Http::Server(this, this))
{
}
QTracker::~QTracker()
{
if (m_server->isListening())
qDebug("Shutting down the embedded tracker...");
close();
}
// TODO: Store the torrent list
}
void QTracker::handlePeerConnection()
{
QTcpSocket *socket;
while((socket = nextPendingConnection()))
{
qDebug("QTracker: New peer connection");
connect(socket, SIGNAL(readyRead()), SLOT(readRequest()));
}
}
bool QTracker::start()
{
const int listen_port = Preferences::instance()->getTrackerPort();
//
if (isListening()) {
if (serverPort() == listen_port) {
if (m_server->isListening()) {
if (m_server->serverPort() == listen_port) {
// Already listening on the right port, just return
return true;
}
// Wrong port, closing the server
close();
m_server->close();
}
qDebug("Starting the embedded tracker...");
// Listen on the predefined port
return listen(QHostAddress::Any, listen_port);
return m_server->listen(QHostAddress::Any, listen_port);
}
void QTracker::readRequest()
Http::Response QTracker::processRequest(const Http::Request &request, const Http::Environment &env)
{
QTcpSocket *socket = static_cast<QTcpSocket*>(sender());
QByteArray input = socket->readAll();
//qDebug("QTracker: Raw request:\n%s", input.data());
HttpRequest request;
if (HttpRequestParser::parse(input, request) != HttpRequestParser::NoError) {
qDebug("QTracker: Invalid HTTP Request:\n %s", qPrintable(input));
respondInvalidRequest(socket, 100, "Invalid request type");
return;
}
//qDebug("QTracker received the following request:\n%s", qPrintable(parser.toString()));
// Request is correct, is it a GET request?
if (request.method != "GET") {
qDebug("QTracker: Unsupported HTTP request: %s", qPrintable(request.method));
respondInvalidRequest(socket, 100, "Invalid request type");
return;
}
if (!request.path.startsWith("/announce", Qt::CaseInsensitive)) {
qDebug("QTracker: Unrecognized path: %s", qPrintable(request.path));
respondInvalidRequest(socket, 100, "Invalid request type");
return;
}
clear(); // clear response
// OK, this is a GET request
respondToAnnounceRequest(socket, request.gets);
//qDebug("QTracker received the following request:\n%s", qPrintable(parser.toString()));
// Is request a GET request?
if (request.method != "GET") {
qDebug("QTracker: Unsupported HTTP request: %s", qPrintable(request.method));
status(100, "Invalid request type");
}
else if (!request.path.startsWith("/announce", Qt::CaseInsensitive)) {
qDebug("QTracker: Unrecognized path: %s", qPrintable(request.path));
status(100, "Invalid request type");
}
else {
// OK, this is a GET request
m_request = request;
m_env = env;
respondToAnnounceRequest();
}
return response();
}
void QTracker::respondInvalidRequest(QTcpSocket *socket, int code, QString msg)
{
HttpResponse response(code, msg);
socket->write(HttpResponseGenerator::generate(response));
socket->disconnectFromHost();
}
void QTracker::respondToAnnounceRequest(QTcpSocket *socket,
const QMap<QString, QString>& get_parameters)
void QTracker::respondToAnnounceRequest()
{
const QStringMap &gets = m_request.gets;
TrackerAnnounceRequest annonce_req;
// IP
annonce_req.peer.ip = socket->peerAddress().toString();
annonce_req.peer.ip = m_env.clientAddress.toString();
// 1. Get info_hash
if (!get_parameters.contains("info_hash")) {
if (!gets.contains("info_hash")) {
qDebug("QTracker: Missing info_hash");
respondInvalidRequest(socket, 101, "Missing info_hash");
status(101, "Missing info_hash");
return;
}
annonce_req.info_hash = get_parameters.value("info_hash");
annonce_req.info_hash = gets.value("info_hash");
// info_hash cannot be longer than 20 bytes
/*if (annonce_req.info_hash.toLatin1().length() > 20) {
qDebug("QTracker: Info_hash is not 20 byte long: %s (%d)", qPrintable(annonce_req.info_hash), annonce_req.info_hash.toLatin1().length());
respondInvalidRequest(socket, 150, "Invalid infohash");
status(150, "Invalid infohash");
return;
}*/
// 2. Get peer ID
if (!get_parameters.contains("peer_id")) {
if (!gets.contains("peer_id")) {
qDebug("QTracker: Missing peer_id");
respondInvalidRequest(socket, 102, "Missing peer_id");
status(102, "Missing peer_id");
return;
}
annonce_req.peer.peer_id = get_parameters.value("peer_id");
annonce_req.peer.peer_id = gets.value("peer_id");
// peer_id cannot be longer than 20 bytes
/*if (annonce_req.peer.peer_id.length() > 20) {
qDebug("QTracker: peer_id is not 20 byte long: %s", qPrintable(annonce_req.peer.peer_id));
respondInvalidRequest(socket, 151, "Invalid peerid");
status(151, "Invalid peerid");
return;
}*/
// 3. Get port
if (!get_parameters.contains("port")) {
if (!gets.contains("port")) {
qDebug("QTracker: Missing port");
respondInvalidRequest(socket, 103, "Missing port");
status(103, "Missing port");
return;
}
bool ok = false;
annonce_req.peer.port = get_parameters.value("port").toInt(&ok);
annonce_req.peer.port = gets.value("port").toInt(&ok);
if (!ok || annonce_req.peer.port < 1 || annonce_req.peer.port > 65535) {
qDebug("QTracker: Invalid port number (%d)", annonce_req.peer.port);
respondInvalidRequest(socket, 103, "Missing port");
status(103, "Missing port");
return;
}
// 4. Get event
annonce_req.event = "";
if (get_parameters.contains("event")) {
annonce_req.event = get_parameters.value("event");
if (gets.contains("event")) {
annonce_req.event = gets.value("event");
qDebug("QTracker: event is %s", qPrintable(annonce_req.event));
}
// 5. Get numwant
annonce_req.numwant = 50;
if (get_parameters.contains("numwant")) {
int tmp = get_parameters.value("numwant").toInt();
if (gets.contains("numwant")) {
int tmp = gets.value("numwant").toInt();
if (tmp > 0) {
qDebug("QTracker: numwant=%d", tmp);
qDebug("QTracker: numwant = %d", tmp);
annonce_req.numwant = tmp;
}
}
// 6. no_peer_id (extension)
annonce_req.no_peer_id = false;
if (get_parameters.contains("no_peer_id")) {
if (gets.contains("no_peer_id"))
annonce_req.no_peer_id = true;
}
// 7. TODO: support "compact" extension
// Done parsing, now let's reply
if (m_torrents.contains(annonce_req.info_hash)) {
if (annonce_req.event == "stopped") {
@@ -207,33 +216,32 @@ void QTracker::respondToAnnounceRequest(QTcpSocket *socket,
}
peers[annonce_req.peer.qhash()] = annonce_req.peer;
m_torrents[annonce_req.info_hash] = peers;
// Reply
ReplyWithPeerList(socket, annonce_req);
replyWithPeerList(annonce_req);
}
void QTracker::ReplyWithPeerList(QTcpSocket *socket, const TrackerAnnounceRequest &annonce_req)
void QTracker::replyWithPeerList(const TrackerAnnounceRequest &annonce_req)
{
// Prepare the entry for bencoding
entry::dictionary_type reply_dict;
reply_dict["interval"] = entry(ANNOUNCE_INTERVAL);
libtorrent::entry::dictionary_type reply_dict;
reply_dict["interval"] = libtorrent::entry(ANNOUNCE_INTERVAL);
QList<QPeer> peers = m_torrents.value(annonce_req.info_hash).values();
entry::list_type peer_list;
libtorrent::entry::list_type peer_list;
foreach (const QPeer & p, peers) {
//if (p != annonce_req.peer)
peer_list.push_back(p.toEntry(annonce_req.no_peer_id));
}
reply_dict["peers"] = entry(peer_list);
entry reply_entry(reply_dict);
reply_dict["peers"] = libtorrent::entry(peer_list);
libtorrent::entry reply_entry(reply_dict);
// bencode
std::vector<char> buf;
bencode(std::back_inserter(buf), reply_entry);
libtorrent::bencode(std::back_inserter(buf), reply_entry);
QByteArray reply(&buf[0], static_cast<int>(buf.size()));
qDebug("QTracker: reply with the following bencoded data:\n %s", reply.constData());
// HTTP reply
HttpResponse response(200, "OK");
response.content = reply;
socket->write(HttpResponseGenerator::generate(response));
socket->disconnectFromHost();
print(reply, Http::CONTENT_TYPE_TXT);
}

View File

@@ -1,5 +1,6 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2015 Vladimir Golovnev <glassez@yandex.ru>
* Copyright (C) 2010 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
@@ -31,11 +32,33 @@
#ifndef QTRACKER_H
#define QTRACKER_H
#include <QTcpServer>
#include <libtorrent/entry.hpp>
#include <QHash>
#include "http/types.h"
#include "http/responsebuilder.h"
#include "http/irequesthandler.h"
#include "trackerannouncerequest.h"
#include "qpeer.h"
struct QPeer
{
QString ip;
QString peer_id;
int port;
bool operator!=(const QPeer &other) const;
bool operator==(const QPeer &other) const;
QString qhash() const;
libtorrent::entry toEntry(bool no_peer_id) const;
};
struct TrackerAnnounceRequest
{
QString info_hash;
QString event;
int numwant;
QPeer peer;
// Extensions
bool no_peer_id;
};
// static limits
const int MAX_TORRENTS = 100;
@@ -45,9 +68,11 @@ const int ANNOUNCE_INTERVAL = 1800; // 30min
typedef QHash<QString, QPeer> PeerList;
typedef QHash<QString, PeerList> TorrentList;
/* Basic Bittorrent tracker implementation in Qt4 */
namespace Http { class Server; }
/* Basic Bittorrent tracker implementation in Qt */
/* Following http://wiki.theory.org/BitTorrent_Tracker_Protocol */
class QTracker : public QTcpServer
class QTracker : public Http::ResponseBuilder, public Http::IRequestHandler
{
Q_OBJECT
Q_DISABLE_COPY(QTracker)
@@ -55,18 +80,19 @@ class QTracker : public QTcpServer
public:
explicit QTracker(QObject *parent = 0);
~QTracker();
bool start();
protected slots:
void readRequest();
void handlePeerConnection();
void respondInvalidRequest(QTcpSocket *socket, int code, QString msg);
void respondToAnnounceRequest(QTcpSocket *socket, const QMap<QString, QString>& get_parameters);
void ReplyWithPeerList(QTcpSocket *socket, const TrackerAnnounceRequest &annonce_req);
bool start();
Http::Response processRequest(const Http::Request &request, const Http::Environment &env);
private:
void respondToAnnounceRequest();
void replyWithPeerList(const TrackerAnnounceRequest &annonce_req);
Http::Server *m_server;
TorrentList m_torrents;
Http::Request m_request;
Http::Environment m_env;
};
#endif // QTRACKER_H

View File

@@ -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

View File

@@ -1,9 +0,0 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/qtracker.h \
$$PWD/trackerannouncerequest.h \
$$PWD/qpeer.h
SOURCES += \
$$PWD/qtracker.cpp

View File

@@ -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