Merge pull request #7610 from glassez/webapi2

Redesign Web API
This commit is contained in:
Vladimir Golovnev
2018-02-16 10:09:35 +03:00
committed by GitHub
96 changed files with 5007 additions and 3125 deletions

View File

@@ -19,6 +19,7 @@ bittorrent/torrentinfo.h
bittorrent/tracker.h
bittorrent/trackerentry.h
http/connection.h
http/httperror.h
http/irequesthandler.h
http/requestparser.h
http/responsebuilder.h
@@ -51,6 +52,7 @@ utils/random.h
utils/string.h
utils/version.h
asyncfilestorage.h
exceptions.h
filesystemwatcher.h
global.h
iconprovider.h
@@ -84,6 +86,7 @@ bittorrent/torrentinfo.cpp
bittorrent/tracker.cpp
bittorrent/trackerentry.cpp
http/connection.cpp
http/httperror.cpp
http/requestparser.cpp
http/responsebuilder.cpp
http/responsegenerator.cpp
@@ -113,6 +116,7 @@ utils/net.cpp
utils/random.cpp
utils/string.cpp
asyncfilestorage.cpp
exceptions.cpp
filesystemwatcher.cpp
iconprovider.cpp
logger.cpp

View File

@@ -17,9 +17,11 @@ HEADERS += \
$$PWD/bittorrent/torrentinfo.h \
$$PWD/bittorrent/tracker.h \
$$PWD/bittorrent/trackerentry.h \
$$PWD/exceptions.h \
$$PWD/filesystemwatcher.h \
$$PWD/global.h \
$$PWD/http/connection.h \
$$PWD/http/httperror.h \
$$PWD/http/irequesthandler.h \
$$PWD/http/requestparser.h \
$$PWD/http/responsebuilder.h \
@@ -82,8 +84,10 @@ SOURCES += \
$$PWD/bittorrent/torrentinfo.cpp \
$$PWD/bittorrent/tracker.cpp \
$$PWD/bittorrent/trackerentry.cpp \
$$PWD/exceptions.cpp \
$$PWD/filesystemwatcher.cpp \
$$PWD/http/connection.cpp \
$$PWD/http/httperror.cpp \
$$PWD/http/requestparser.cpp \
$$PWD/http/responsebuilder.cpp \
$$PWD/http/responsegenerator.cpp \

View File

@@ -60,23 +60,32 @@ TorrentInfo &TorrentInfo::operator=(const TorrentInfo &other)
return *this;
}
TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString &error)
TorrentInfo TorrentInfo::load(const QByteArray &data, QString *error) noexcept
{
error.clear();
libt::error_code ec;
TorrentInfo info(NativePtr(new libt::torrent_info(Utils::Fs::toNativePath(path).toStdString(), ec)));
if (ec) {
error = QString::fromUtf8(ec.message().c_str());
qDebug("Cannot load .torrent file: %s", qUtf8Printable(error));
TorrentInfo info(NativePtr(new libt::torrent_info(data.constData(), data.size(), ec)));
if (error) {
if (ec)
*error = QString::fromStdString(ec.message());
else
error->clear();
}
return info;
}
TorrentInfo TorrentInfo::loadFromFile(const QString &path)
TorrentInfo TorrentInfo::loadFromFile(const QString &path, QString *error) noexcept
{
QString error;
return loadFromFile(path, error);
libt::error_code ec;
TorrentInfo info(NativePtr(new libt::torrent_info(Utils::Fs::toNativePath(path).toStdString(), ec)));
if (error) {
if (ec)
*error = QString::fromStdString(ec.message());
else
error->clear();
}
return info;
}
bool TorrentInfo::isValid() const

View File

@@ -63,8 +63,8 @@ namespace BitTorrent
explicit TorrentInfo(NativeConstPtr nativeInfo = NativeConstPtr());
TorrentInfo(const TorrentInfo &other);
static TorrentInfo loadFromFile(const QString &path, QString &error);
static TorrentInfo loadFromFile(const QString &path);
static TorrentInfo load(const QByteArray &data, QString *error = nullptr) noexcept;
static TorrentInfo loadFromFile(const QString &path, QString *error = nullptr) noexcept;
TorrentInfo &operator=(const TorrentInfo &other);

View File

@@ -74,7 +74,7 @@ libtorrent::entry Peer::toEntry(bool noPeerId) const
// Tracker
Tracker::Tracker(QObject *parent)
: Http::ResponseBuilder(parent)
: QObject(parent)
, m_server(new Http::Server(this, this))
{
}

View File

@@ -31,6 +31,7 @@
#define BITTORRENT_TRACKER_H
#include <QHash>
#include <QObject>
#include "base/http/irequesthandler.h"
#include "base/http/responsebuilder.h"
@@ -75,7 +76,7 @@ namespace BitTorrent
/* Basic Bittorrent tracker implementation in Qt */
/* Following http://wiki.theory.org/BitTorrent_Tracker_Protocol */
class Tracker : public Http::ResponseBuilder, public Http::IRequestHandler
class Tracker : public QObject, public Http::IRequestHandler, private Http::ResponseBuilder
{
Q_OBJECT
Q_DISABLE_COPY(Tracker)

40
src/base/exceptions.cpp Normal file
View File

@@ -0,0 +1,40 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 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 "exceptions.h"
RuntimeError::RuntimeError(const QString &message)
: std::runtime_error {message.toUtf8().data()}
, m_message {message}
{
}
QString RuntimeError::message() const
{
return m_message;
}

42
src/base/exceptions.h Normal file
View File

@@ -0,0 +1,42 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2018 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.
*/
#pragma once
#include <stdexcept>
#include <QString>
class RuntimeError : public std::runtime_error
{
public:
explicit RuntimeError(const QString &message = "");
QString message() const;
private:
const QString m_message;
};

View File

@@ -0,0 +1,81 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017 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 "httperror.h"
HTTPError::HTTPError(int statusCode, const QString &statusText, const QString &message)
: RuntimeError {message}
, m_statusCode {statusCode}
, m_statusText {statusText}
{
}
int HTTPError::statusCode() const
{
return m_statusCode;
}
QString HTTPError::statusText() const
{
return m_statusText;
}
BadRequestHTTPError::BadRequestHTTPError(const QString &message)
: HTTPError(400, QLatin1String("Bad Request"), message)
{
}
ConflictHTTPError::ConflictHTTPError(const QString &message)
: HTTPError(409, QLatin1String("Conflict"), message)
{
}
ForbiddenHTTPError::ForbiddenHTTPError(const QString &message)
: HTTPError(403, QLatin1String("Forbidden"), message)
{
}
NotFoundHTTPError::NotFoundHTTPError(const QString &message)
: HTTPError(404, QLatin1String("Not Found"), message)
{
}
UnsupportedMediaTypeHTTPError::UnsupportedMediaTypeHTTPError(const QString &message)
: HTTPError(415, QLatin1String("Unsupported Media Type"), message)
{
}
UnauthorizedHTTPError::UnauthorizedHTTPError(const QString &message)
: HTTPError(401, QLatin1String("Unauthorized"), message)
{
}
InternalServerErrorHTTPError::InternalServerErrorHTTPError(const QString &message)
: HTTPError(500, QLatin1String("Internal Server Error"), message)
{
}

86
src/base/http/httperror.h Normal file
View File

@@ -0,0 +1,86 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2017 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.
*/
#pragma once
#include "base/exceptions.h"
class HTTPError : public RuntimeError
{
public:
HTTPError(int statusCode, const QString &statusText, const QString &message = "");
int statusCode() const;
QString statusText() const;
private:
const int m_statusCode;
const QString m_statusText;
};
class BadRequestHTTPError : public HTTPError
{
public:
explicit BadRequestHTTPError(const QString &message = "");
};
class ForbiddenHTTPError : public HTTPError
{
public:
explicit ForbiddenHTTPError(const QString &message = "");
};
class NotFoundHTTPError : public HTTPError
{
public:
explicit NotFoundHTTPError(const QString &message = "");
};
class ConflictHTTPError : public HTTPError
{
public:
explicit ConflictHTTPError(const QString &message = "");
};
class UnsupportedMediaTypeHTTPError : public HTTPError
{
public:
explicit UnsupportedMediaTypeHTTPError(const QString &message = "");
};
class UnauthorizedHTTPError : public HTTPError
{
public:
explicit UnauthorizedHTTPError(const QString &message = "");
};
class InternalServerErrorHTTPError : public HTTPError
{
public:
explicit InternalServerErrorHTTPError(const QString &message = "");
};

View File

@@ -30,11 +30,6 @@
using namespace Http;
ResponseBuilder::ResponseBuilder(QObject *parent)
: QObject(parent)
{
}
void ResponseBuilder::status(uint code, const QString &text)
{
m_response.status = ResponseStatus(code, text);

View File

@@ -29,17 +29,13 @@
#ifndef HTTP_RESPONSEBUILDER_H
#define HTTP_RESPONSEBUILDER_H
#include <QObject>
#include "types.h"
namespace Http
{
class ResponseBuilder : public QObject
class ResponseBuilder
{
public:
explicit ResponseBuilder(QObject *parent = nullptr);
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);

View File

@@ -37,6 +37,9 @@
namespace Http
{
const char METHOD_GET[] = "GET";
const char METHOD_POST[] = "POST";
const char HEADER_CACHE_CONTROL[] = "cache-control";
const char HEADER_CONTENT_ENCODING[] = "content-encoding";
const char HEADER_CONTENT_LENGTH[] = "content-length";
@@ -52,13 +55,14 @@ namespace Http
const char HEADER_X_FRAME_OPTIONS[] = "x-frame-options";
const char HEADER_X_XSS_PROTECTION[] = "x-xss-protection";
const char CONTENT_TYPE_CSS[] = "text/css; charset=UTF-8";
const char CONTENT_TYPE_GIF[] = "image/gif";
const char CONTENT_TYPE_HTML[] = "text/html; charset=UTF-8";
const char CONTENT_TYPE_JS[] = "application/javascript; charset=UTF-8";
const char CONTENT_TYPE_HTML[] = "text/html";
const char CONTENT_TYPE_JS[] = "application/javascript";
const char CONTENT_TYPE_JSON[] = "application/json";
const char CONTENT_TYPE_BMP[] = "image/bmp";
const char CONTENT_TYPE_GIF[] = "image/gif";
const char CONTENT_TYPE_JPEG[] = "image/jpeg";
const char CONTENT_TYPE_PNG[] = "image/png";
const char CONTENT_TYPE_TXT[] = "text/plain; charset=UTF-8";
const char CONTENT_TYPE_TXT[] = "text/plain";
const char CONTENT_TYPE_SVG[] = "image/svg+xml";
// portability: "\r\n" doesn't guarantee mapping to the correct value

View File

@@ -609,6 +609,26 @@ void Preferences::setWebUiHttpsKey(const QByteArray &data)
setValue("Preferences/WebUI/HTTPS/Key", data);
}
bool Preferences::isAltWebUiEnabled() const
{
return value("Preferences/WebUI/AlternativeUIEnabled", false).toBool();
}
void Preferences::setAltWebUiEnabled(bool enabled)
{
setValue("Preferences/WebUI/AlternativeUIEnabled", enabled);
}
QString Preferences::getWebUiRootFolder() const
{
return value("Preferences/WebUI/RootFolder").toString();
}
void Preferences::setWebUiRootFolder(const QString &path)
{
setValue("Preferences/WebUI/RootFolder", path);
}
bool Preferences::isDynDNSEnabled() const
{
return value("Preferences/DynDNS/Enabled", false).toBool();

View File

@@ -204,6 +204,10 @@ public:
void setWebUiHttpsCertificate(const QByteArray &data);
QByteArray getWebUiHttpsKey() const;
void setWebUiHttpsKey(const QByteArray &data);
bool isAltWebUiEnabled() const;
void setAltWebUiEnabled(bool enabled);
QString getWebUiRootFolder() const;
void setWebUiRootFolder(const QString &path);
// Dynamic DNS
bool isDynDNSEnabled() const;

View File

@@ -30,6 +30,10 @@
#include "fs.h"
#include <cstring>
#include <sys/stat.h>
#include <sys/types.h>
#include <QDebug>
#include <QDir>
#include <QFile>
@@ -47,6 +51,7 @@
#include <kernel/fs_info.h>
#else
#include <sys/vfs.h>
#include <unistd.h>
#endif
#include "base/bittorrent/torrenthandle.h"
@@ -281,3 +286,17 @@ QString Utils::Fs::tempPath()
QDir().mkdir(path);
return path;
}
bool Utils::Fs::isRegularFile(const QString &path)
{
struct ::stat st;
if (::stat(path.toUtf8().constData(), &st) != 0) {
// analyse erno and log the error
const auto err = errno;
qDebug("Could not get file stats for path '%s'. Error: %s"
, qUtf8Printable(path), qUtf8Printable(strerror(err)));
return false;
}
return (st.st_mode & S_IFMT) == S_IFREG;
}

View File

@@ -56,6 +56,7 @@ namespace Utils
bool sameFileNames(const QString &first, const QString &second);
QString expandPath(const QString &path);
QString expandPathAbs(const QString &path);
bool isRegularFile(const QString &path);
bool smartRemoveEmptyFolderTree(const QString &path);
bool forceRemove(const QString &filePath);

View File

@@ -40,6 +40,8 @@
#include <QThreadStorage>
#endif
#include "../tristatebool.h"
namespace
{
class NaturalCompare
@@ -184,3 +186,19 @@ QString Utils::String::wildcardToRegex(const QString &pattern)
{
return qt_regexp_toCanonical(pattern, QRegExp::Wildcard);
}
bool Utils::String::parseBool(const QString &string, const bool defaultValue)
{
if (defaultValue)
return (string.compare("false", Qt::CaseInsensitive) == 0) ? false : true;
return (string.compare("true", Qt::CaseInsensitive) == 0) ? true : false;
}
TriStateBool Utils::String::parseTriStateBool(const QString &string)
{
if (string.compare("true", Qt::CaseInsensitive) == 0)
return TriStateBool::True;
if (string.compare("false", Qt::CaseInsensitive) == 0)
return TriStateBool::False;
return TriStateBool::Undefined;
}

View File

@@ -34,6 +34,7 @@
class QByteArray;
class QLatin1String;
class TriStateBool;
namespace Utils
{
@@ -66,6 +67,9 @@ namespace Utils
return str;
}
bool parseBool(const QString &string, const bool defaultValue);
TriStateBool parseTriStateBool(const QString &string);
}
}