feat(core): add HttpServer

Includes cpp-httplib v0.5.6.
This commit is contained in:
Oleg Shparber 2020-01-28 01:43:52 -05:00 committed by Oleg Shparber
parent 58b92765ce
commit 090f527054
6 changed files with 4970 additions and 0 deletions

View File

@ -3,8 +3,12 @@ add_library(Core STATIC
applicationsingleton.cpp applicationsingleton.cpp
extractor.cpp extractor.cpp
filemanager.cpp filemanager.cpp
httpserver.cpp
networkaccessmanager.cpp networkaccessmanager.cpp
settings.cpp settings.cpp
# Show headers without .cpp in Qt Creator.
httplib.h
) )
target_link_libraries(Core Registry Ui) target_link_libraries(Core Registry Ui)
@ -15,3 +19,10 @@ target_link_libraries(Core Qt5::Network Qt5::WebKit Qt5::Widgets)
find_package(LibArchive REQUIRED) find_package(LibArchive REQUIRED)
include_directories(${LibArchive_INCLUDE_DIRS}) include_directories(${LibArchive_INCLUDE_DIRS})
target_link_libraries(Core ${LibArchive_LIBRARIES}) target_link_libraries(Core ${LibArchive_LIBRARIES})
# Required by cpp-httplib.
if(NOT WIN32)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(Core Threads::Threads)
endif()

View File

@ -24,6 +24,7 @@
#include "extractor.h" #include "extractor.h"
#include "filemanager.h" #include "filemanager.h"
#include "httpserver.h"
#include "networkaccessmanager.h" #include "networkaccessmanager.h"
#include "settings.h" #include "settings.h"
@ -63,6 +64,7 @@ Application::Application(QObject *parent)
m_networkManager = new NetworkAccessManager(this); m_networkManager = new NetworkAccessManager(this);
m_fileManager = new FileManager(this); m_fileManager = new FileManager(this);
m_httpServer = new HttpServer(this);
// Extractor setup // Extractor setup
m_extractorThread = new QThread(this); m_extractorThread = new QThread(this);
@ -134,6 +136,11 @@ FileManager *Application::fileManager() const
return m_fileManager; return m_fileManager;
} }
HttpServer *Application::httpServer() const
{
return m_httpServer;
}
QString Application::cacheLocation() QString Application::cacheLocation()
{ {
#ifndef PORTABLE_BUILD #ifndef PORTABLE_BUILD

View File

@ -45,6 +45,7 @@ namespace Core {
class Extractor; class Extractor;
class FileManager; class FileManager;
class HttpServer;
class Settings; class Settings;
class Application final : public QObject class Application final : public QObject
@ -64,6 +65,7 @@ public:
Registry::DocsetRegistry *docsetRegistry(); Registry::DocsetRegistry *docsetRegistry();
FileManager *fileManager() const; FileManager *fileManager() const;
HttpServer *httpServer() const;
static QString cacheLocation(); static QString cacheLocation();
static QString configLocation(); static QString configLocation();
@ -96,6 +98,7 @@ private:
QNetworkAccessManager *m_networkManager = nullptr; QNetworkAccessManager *m_networkManager = nullptr;
FileManager *m_fileManager = nullptr; FileManager *m_fileManager = nullptr;
HttpServer *m_httpServer = nullptr;
QThread *m_extractorThread = nullptr; QThread *m_extractorThread = nullptr;
Extractor *m_extractor = nullptr; Extractor *m_extractor = nullptr;

4786
src/libs/core/httplib.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,100 @@
/****************************************************************************
**
** Copyright (C) 2020 Oleg Shparber
** Contact: https://go.zealdocs.org/l/contact
**
** This file is part of Zeal.
**
** Zeal 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 3 of the License, or
** (at your option) any later version.
**
** Zeal 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 Zeal. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#include "httpserver.h"
#include "application.h"
#include "httplib.h"
#include <QLoggingCategory>
#include <QRegularExpression>
using namespace Zeal::Core;
namespace {
constexpr char LocalHttpServerHost[] = "127.0.0.22";
} // namespace
static Q_LOGGING_CATEGORY(log, "zeal.core.httpserver")
HttpServer::HttpServer(QObject *parent)
: QObject(parent)
{
m_server = std::make_unique<httplib::Server>();
const int port = m_server->bind_to_any_port(LocalHttpServerHost);
m_baseUrl.setScheme(QStringLiteral("http"));
m_baseUrl.setHost(LocalHttpServerHost);
m_baseUrl.setPort(port);
m_server->set_error_handler([](const auto& req, auto& res) {
const QString html = QStringLiteral("<b>ERROR %1</b><br><pre>Request path: %2</pre>")
.arg(res.status)
.arg(QString::fromStdString(req.path));
res.set_content(html.toUtf8().data(), "text/html");
});
m_future = std::async(std::launch::async, &httplib::Server::listen_after_bind, m_server.get());
qCDebug(log, "Listening on %s...", qPrintable(m_baseUrl.toString()));
}
HttpServer::~HttpServer()
{
m_server->stop();
auto status = m_future.wait_for(std::chrono::seconds(2));
if (status != std::future_status::ready) {
qCWarning(log) << "Failed to stop server within timeout.";
}
}
QUrl HttpServer::baseUrl() const
{
return m_baseUrl;
}
QUrl HttpServer::mount(const QString &prefix, const QString &path)
{
const QString pfx = sanitizePrefix(prefix);
const bool ok = m_server->set_mount_point(pfx.toUtf8(), path.toUtf8());
if (!ok) {
qCWarning(log, "Failed to mount '%s' to '%s'.", qPrintable(path), qPrintable(pfx));
return QUrl();
}
qCDebug(log, "Mounted '%s' to '%s'.", qPrintable(path), qPrintable(pfx));
QUrl mountUrl = m_baseUrl;
mountUrl.setPath(m_baseUrl.path() + pfx);
return mountUrl;
}
QString HttpServer::sanitizePrefix(const QString &prefix)
{
QString pfx = (prefix.startsWith(QLatin1String("/")) ? prefix.right(1) : prefix).toLower();
pfx.replace(QRegularExpression(QStringLiteral("[^a-zA-Z0-9-_]")), QStringLiteral("_"));
pfx.prepend(QLatin1Char('/'));
return pfx;
}

View File

@ -0,0 +1,63 @@
/****************************************************************************
**
** Copyright (C) 2020 Oleg Shparber
** Contact: https://go.zealdocs.org/l/contact
**
** This file is part of Zeal.
**
** Zeal 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 3 of the License, or
** (at your option) any later version.
**
** Zeal 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 Zeal. If not, see <http://www.gnu.org/licenses/>.
**
****************************************************************************/
#ifndef ZEAL_CORE_HTTPSERVER_H
#define ZEAL_CORE_HTTPSERVER_H
#include <QObject>
#include <QUrl>
#include <future>
#include <memory>
namespace httplib {
class Server;
} // namespace httplib
namespace Zeal {
namespace Core {
class HttpServer : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(HttpServer)
public:
explicit HttpServer(QObject *parent = nullptr);
~HttpServer() override;
QUrl baseUrl() const;
QUrl mount(const QString &prefix, const QString &path);
private:
static QString sanitizePrefix(const QString &prefix);
std::unique_ptr<httplib::Server> m_server;
std::future<bool> m_future;
QUrl m_baseUrl;
};
} // namespace Core
} // namespace Zeal
#endif // ZEAL_CORE_HTTPSERVER_H