Implemented basic vhost functionality
This commit is contained in:
@@ -1,17 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "webserverlib_global.h"
|
||||
#include <QObject>
|
||||
|
||||
#include <QIODevice>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "httpcontainers.h"
|
||||
#include "httpresponse.h"
|
||||
#include "httprequest.h"
|
||||
|
||||
class QTcpSocket;
|
||||
|
||||
class WebListener;
|
||||
|
||||
class HttpClientConnection : public QObject
|
||||
class WEBSERVERLIB_EXPORT HttpClientConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
34
webserverlib/httprequest.cpp
Normal file
34
webserverlib/httprequest.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "httprequest.h"
|
||||
|
||||
const QString HttpRequest::HEADER_ACCEPT(QStringLiteral("Accept"));
|
||||
const QString HttpRequest::HEADER_ACCEPTCHARSET(QStringLiteral("Accept-Charset"));
|
||||
const QString HttpRequest::HEADER_ACCEPTENCODING(QStringLiteral("Accept-Encoding"));
|
||||
const QString HttpRequest::HEADER_ACCEPTLANGUAGE(QStringLiteral("Accept-Language"));
|
||||
const QString HttpRequest::HEADER_AUTHORIZATION(QStringLiteral("Authorization"));
|
||||
const QString HttpRequest::HEADER_CACHECONTROL(QStringLiteral("Cache-Control"));
|
||||
const QString HttpRequest::HEADER_CONNECTION(QStringLiteral("Connection"));
|
||||
const QString HttpRequest::HEADER_COOKIE(QStringLiteral("Cookie"));
|
||||
const QString HttpRequest::HEADER_CONTENTLENGTH(QStringLiteral("Content-Length"));
|
||||
const QString HttpRequest::HEADER_CONTENTMD5(QStringLiteral("Content-MD5"));
|
||||
const QString HttpRequest::HEADER_CONTENTTYPE(QStringLiteral("Content-Type"));
|
||||
const QString HttpRequest::HEADER_DATE(QStringLiteral("Date"));
|
||||
const QString HttpRequest::HEADER_EXPECT(QStringLiteral("Expect"));
|
||||
const QString HttpRequest::HEADER_FORWARDED(QStringLiteral("Forwarded"));
|
||||
const QString HttpRequest::HEADER_FROM(QStringLiteral("From"));
|
||||
const QString HttpRequest::HEADER_HOST(QStringLiteral("Host"));
|
||||
const QString HttpRequest::HEADER_IFMATCH(QStringLiteral("If-Match"));
|
||||
const QString HttpRequest::HEADER_IFMODIFIEDSINCE(QStringLiteral("If-Modified-Since"));
|
||||
const QString HttpRequest::HEADER_IFNONEMATCH(QStringLiteral("If-None-Match"));
|
||||
const QString HttpRequest::HEADER_IFRANGE(QStringLiteral("If-Range"));
|
||||
const QString HttpRequest::HEADER_IFUNMODIFIEDSINCE(QStringLiteral("If-Unmodified-Since"));
|
||||
const QString HttpRequest::HEADER_MAXFORWARDS(QStringLiteral("Max-Forwards"));
|
||||
const QString HttpRequest::HEADER_PRAGMA(QStringLiteral("Pragma"));
|
||||
const QString HttpRequest::HEADER_PROXYAUTHORIZATION(QStringLiteral("Proxy-Authorization"));
|
||||
const QString HttpRequest::HEADER_RANGE(QStringLiteral("Range"));
|
||||
const QString HttpRequest::HEADER_REFERER(QStringLiteral("Referer"));
|
||||
const QString HttpRequest::HEADER_TE(QStringLiteral("TE"));
|
||||
const QString HttpRequest::HEADER_TRANSFERENCODING(QStringLiteral("Transfer-Encoding"));
|
||||
const QString HttpRequest::HEADER_UPGRADE(QStringLiteral("Upgrade"));
|
||||
const QString HttpRequest::HEADER_USERAGENT(QStringLiteral("User-Agent"));
|
||||
const QString HttpRequest::HEADER_VIA(QStringLiteral("Via"));
|
||||
const QString HttpRequest::HEADER_WARNING(QStringLiteral("Warning"));
|
48
webserverlib/httprequest.h
Normal file
48
webserverlib/httprequest.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "webserverlib_global.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
#include <QByteArray>
|
||||
|
||||
struct WEBSERVERLIB_EXPORT HttpRequest {
|
||||
QString method;
|
||||
QString path;
|
||||
QString protocol;
|
||||
QHash<QString, QString> headers;
|
||||
QByteArray body;
|
||||
|
||||
static const QString HEADER_ACCEPT;
|
||||
static const QString HEADER_ACCEPTCHARSET;
|
||||
static const QString HEADER_ACCEPTENCODING;
|
||||
static const QString HEADER_ACCEPTLANGUAGE;
|
||||
static const QString HEADER_AUTHORIZATION;
|
||||
static const QString HEADER_CACHECONTROL;
|
||||
static const QString HEADER_CONNECTION;
|
||||
static const QString HEADER_COOKIE;
|
||||
static const QString HEADER_CONTENTLENGTH;
|
||||
static const QString HEADER_CONTENTMD5;
|
||||
static const QString HEADER_CONTENTTYPE;
|
||||
static const QString HEADER_DATE;
|
||||
static const QString HEADER_EXPECT;
|
||||
static const QString HEADER_FORWARDED;
|
||||
static const QString HEADER_FROM;
|
||||
static const QString HEADER_HOST;
|
||||
static const QString HEADER_IFMATCH;
|
||||
static const QString HEADER_IFMODIFIEDSINCE;
|
||||
static const QString HEADER_IFNONEMATCH;
|
||||
static const QString HEADER_IFRANGE;
|
||||
static const QString HEADER_IFUNMODIFIEDSINCE;
|
||||
static const QString HEADER_MAXFORWARDS;
|
||||
static const QString HEADER_PRAGMA;
|
||||
static const QString HEADER_PROXYAUTHORIZATION;
|
||||
static const QString HEADER_RANGE;
|
||||
static const QString HEADER_REFERER;
|
||||
static const QString HEADER_TE;
|
||||
static const QString HEADER_TRANSFERENCODING;
|
||||
static const QString HEADER_UPGRADE;
|
||||
static const QString HEADER_USERAGENT;
|
||||
static const QString HEADER_VIA;
|
||||
static const QString HEADER_WARNING;
|
||||
};
|
@@ -1,6 +1,11 @@
|
||||
#include "httpcontainers.h"
|
||||
#include "httpresponse.h"
|
||||
|
||||
QString HttpResponse::statusString() const
|
||||
{
|
||||
return statusString(statusCode);
|
||||
}
|
||||
|
||||
QString HttpResponse::statusString(HttpResponse::StatusCode statusCode)
|
||||
{
|
||||
switch(statusCode) {
|
||||
case HttpResponse::StatusCode::Continue: return QStringLiteral("Continue");
|
||||
@@ -73,3 +78,37 @@ QString HttpResponse::statusString() const
|
||||
case HttpResponse::StatusCode::NetworkAuthenticationRequired: return QStringLiteral("Network Authentication Required");
|
||||
}
|
||||
}
|
||||
|
||||
const QString HttpResponse::HEADER_ACCEPTRANGES(QStringLiteral("Accept-Ranges"));
|
||||
const QString HttpResponse::HEADER_AGE(QStringLiteral("Age"));
|
||||
const QString HttpResponse::HEADER_ALLOW(QStringLiteral("Allow"));
|
||||
const QString HttpResponse::HEADER_CACHECONTROL(QStringLiteral("Cache-Control"));
|
||||
const QString HttpResponse::HEADER_CONNECTION(QStringLiteral("Connection"));
|
||||
const QString HttpResponse::HEADER_CONTENTENCODING(QStringLiteral("Content-Encoding"));
|
||||
const QString HttpResponse::HEADER_CONTENTLANGUAGE(QStringLiteral("Content-Language"));
|
||||
const QString HttpResponse::HEADER_CONTENTLENGTH(QStringLiteral("Content-Length"));
|
||||
const QString HttpResponse::HEADER_CONTENTLOCATION(QStringLiteral("Content-Location"));
|
||||
const QString HttpResponse::HEADER_CONTENTMD5(QStringLiteral("Content-MD5"));
|
||||
const QString HttpResponse::HEADER_CONTENTDISPOSITION(QStringLiteral("Content-Disposition"));
|
||||
const QString HttpResponse::HEADER_CONTENTRANGE(QStringLiteral("Content-Range"));
|
||||
const QString HttpResponse::HEADER_CONTENTSECURITYPOLICY(QStringLiteral("Content-Security-Policy"));
|
||||
const QString HttpResponse::HEADER_CONTENTTYPE(QStringLiteral("Content-Type"));
|
||||
const QString HttpResponse::HEADER_DATE(QStringLiteral("Date"));
|
||||
const QString HttpResponse::HEADER_ETAG(QStringLiteral("ETag"));
|
||||
const QString HttpResponse::HEADER_EXPIRES(QStringLiteral("Expires"));
|
||||
const QString HttpResponse::HEADER_LASTMODIFIED(QStringLiteral("Last-Modified"));
|
||||
const QString HttpResponse::HEADER_LINK(QStringLiteral("Link"));
|
||||
const QString HttpResponse::HEADER_LOCATION(QStringLiteral("Location"));
|
||||
const QString HttpResponse::HEADER_P3P(QStringLiteral("P3P"));
|
||||
const QString HttpResponse::HEADER_PRAGMA(QStringLiteral("Pragma"));
|
||||
const QString HttpResponse::HEADER_PROXYAUTHENTICATE(QStringLiteral("Proxy-Authenticate"));
|
||||
const QString HttpResponse::HEADER_REFRESH(QStringLiteral("Refresh"));
|
||||
const QString HttpResponse::HEADER_RETRYAFTER(QStringLiteral("Retry-After"));
|
||||
const QString HttpResponse::HEADER_SERVER(QStringLiteral("Server"));
|
||||
const QString HttpResponse::HEADER_SETCOOKIE(QStringLiteral("Set-Cookie"));
|
||||
const QString HttpResponse::HEADER_TRAILER(QStringLiteral("Trailer"));
|
||||
const QString HttpResponse::HEADER_TRANSFERENCODING(QStringLiteral("Transfer-Encoding"));
|
||||
const QString HttpResponse::HEADER_VARY(QStringLiteral("Vary"));
|
||||
const QString HttpResponse::HEADER_VIA(QStringLiteral("Via"));
|
||||
const QString HttpResponse::HEADER_WARNING(QStringLiteral("Warning"));
|
||||
const QString HttpResponse::HEADER_WWWAUTHENTICATE(QStringLiteral("WWW-Authenticate"));
|
@@ -1,18 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "webserverlib_global.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QHash>
|
||||
#include <QByteArray>
|
||||
|
||||
struct HttpRequest {
|
||||
QString method;
|
||||
QString path;
|
||||
QString protocol;
|
||||
QHash<QString, QString> headers;
|
||||
QByteArray body;
|
||||
};
|
||||
|
||||
struct HttpResponse {
|
||||
struct WEBSERVERLIB_EXPORT HttpResponse {
|
||||
enum class StatusCode {
|
||||
// 1xx Informational responses
|
||||
Continue = 100, // Continue
|
||||
@@ -98,4 +91,39 @@ struct HttpResponse {
|
||||
QHash<QString, QString> headers;
|
||||
|
||||
QString statusString() const;
|
||||
static QString statusString(StatusCode statusCode);
|
||||
|
||||
static const QString HEADER_ACCEPTRANGES;
|
||||
static const QString HEADER_AGE;
|
||||
static const QString HEADER_ALLOW;
|
||||
static const QString HEADER_CACHECONTROL;
|
||||
static const QString HEADER_CONNECTION;
|
||||
static const QString HEADER_CONTENTENCODING;
|
||||
static const QString HEADER_CONTENTLANGUAGE;
|
||||
static const QString HEADER_CONTENTLENGTH;
|
||||
static const QString HEADER_CONTENTLOCATION;
|
||||
static const QString HEADER_CONTENTMD5;
|
||||
static const QString HEADER_CONTENTDISPOSITION;
|
||||
static const QString HEADER_CONTENTRANGE;
|
||||
static const QString HEADER_CONTENTSECURITYPOLICY;
|
||||
static const QString HEADER_CONTENTTYPE;
|
||||
static const QString HEADER_DATE;
|
||||
static const QString HEADER_ETAG;
|
||||
static const QString HEADER_EXPIRES;
|
||||
static const QString HEADER_LASTMODIFIED;
|
||||
static const QString HEADER_LINK;
|
||||
static const QString HEADER_LOCATION;
|
||||
static const QString HEADER_P3P;
|
||||
static const QString HEADER_PRAGMA;
|
||||
static const QString HEADER_PROXYAUTHENTICATE;
|
||||
static const QString HEADER_REFRESH;
|
||||
static const QString HEADER_RETRYAFTER;
|
||||
static const QString HEADER_SERVER;
|
||||
static const QString HEADER_SETCOOKIE;
|
||||
static const QString HEADER_TRAILER;
|
||||
static const QString HEADER_TRANSFERENCODING;
|
||||
static const QString HEADER_VARY;
|
||||
static const QString HEADER_VIA;
|
||||
static const QString HEADER_WARNING;
|
||||
static const QString HEADER_WWWAUTHENTICATE;
|
||||
};
|
@@ -3,6 +3,9 @@
|
||||
#include <QObject>
|
||||
#include "webserverlib_global.h"
|
||||
|
||||
class HttpClientConnection;
|
||||
class HttpRequest;
|
||||
|
||||
class WEBSERVERLIB_EXPORT WebApplication : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -11,4 +14,6 @@ public:
|
||||
WebApplication(QObject *parent = Q_NULLPTR);
|
||||
|
||||
virtual void start() = 0;
|
||||
|
||||
virtual void handleRequest(HttpClientConnection *connection, const HttpRequest &request) = 0;
|
||||
};
|
||||
|
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "utils/netutils.h"
|
||||
#include "httpclientconnection.h"
|
||||
#include "webapplication.h"
|
||||
|
||||
WebListener::WebListener(const QJsonObject &config, const QHash<QString, WebApplication*> &applications, QObject *parent) :
|
||||
QObject(parent)
|
||||
@@ -55,7 +56,7 @@ WebListener::WebListener(const QJsonObject &config, const QHash<QString, WebAppl
|
||||
throw std::runtime_error(QString("listener %0:%1 vhost %2 references unknown application %3")
|
||||
.arg(m_address.toString()).arg(m_port).arg(iter.key(), applicationName).toStdString());
|
||||
|
||||
qDebug() << iter.key() << applicationName;
|
||||
m_hosts.insert(iter.key(), *applicationsIter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,10 +73,45 @@ void WebListener::start()
|
||||
|
||||
void WebListener::handleRequest(HttpClientConnection *connection, const HttpRequest &request)
|
||||
{
|
||||
HttpResponse response;
|
||||
response.protocol = request.protocol;
|
||||
response.statusCode = HttpResponse::StatusCode::OK;
|
||||
connection->sendResponse(response, request.path);
|
||||
QString host;
|
||||
|
||||
{
|
||||
const auto hostHeaderIter = qAsConst(request.headers).find(HttpRequest::HEADER_HOST);
|
||||
if(hostHeaderIter != request.headers.constEnd())
|
||||
host = hostHeaderIter.value();
|
||||
}
|
||||
|
||||
if(host.isEmpty())
|
||||
{
|
||||
const auto iter = m_hosts.find(QStringLiteral("*"));
|
||||
if(iter == m_hosts.constEnd())
|
||||
{
|
||||
HttpResponse response;
|
||||
response.protocol = request.protocol;
|
||||
response.statusCode = HttpResponse::StatusCode::BadRequest;
|
||||
connection->sendResponse(response, tr("Your request didn't contain a Host header and there is no fallback host configured!"));
|
||||
return;
|
||||
}
|
||||
|
||||
iter.value()->handleRequest(connection, request);
|
||||
return;
|
||||
}
|
||||
|
||||
auto iter = m_hosts.find(host);
|
||||
if(iter == m_hosts.constEnd())
|
||||
{
|
||||
iter = m_hosts.find(QStringLiteral("*"));
|
||||
if(iter == m_hosts.constEnd())
|
||||
{
|
||||
HttpResponse response;
|
||||
response.protocol = request.protocol;
|
||||
response.statusCode = HttpResponse::StatusCode::BadRequest;
|
||||
connection->sendResponse(response, tr("Your requested Host \"%0\" is unknown and there is no fallback host configured!"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
iter.value()->handleRequest(connection, request);
|
||||
}
|
||||
|
||||
void WebListener::acceptError(QAbstractSocket::SocketError socketError)
|
||||
|
@@ -5,9 +5,9 @@
|
||||
|
||||
#include <QAbstractSocket>
|
||||
#include <QHostAddress>
|
||||
#include <QHash>
|
||||
|
||||
class QJsonObject;
|
||||
template <class Key, class T> class QHash;
|
||||
class QTcpServer;
|
||||
|
||||
class WebApplication;
|
||||
@@ -29,7 +29,10 @@ private Q_SLOTS:
|
||||
void newConnection();
|
||||
|
||||
private:
|
||||
using HostsContainer = QHash<QString, WebApplication*>;
|
||||
|
||||
QTcpServer *m_tcpServer;
|
||||
QHostAddress m_address;
|
||||
quint16 m_port;
|
||||
HostsContainer m_hosts;
|
||||
};
|
||||
|
@@ -12,14 +12,16 @@ SOURCES += \
|
||||
webapplication.cpp \
|
||||
webplugin.cpp \
|
||||
httpclientconnection.cpp \
|
||||
httpcontainers.cpp
|
||||
httprequest.cpp \
|
||||
httpresponse.cpp
|
||||
|
||||
HEADERS += webserverlib_global.h \
|
||||
weblistener.h \
|
||||
webapplication.h \
|
||||
webplugin.h \
|
||||
httpclientconnection.h \
|
||||
httpcontainers.h
|
||||
httprequest.h \
|
||||
httpresponse.h
|
||||
|
||||
FORMS +=
|
||||
|
||||
|
Reference in New Issue
Block a user