Implemented basic vhost functionality

This commit is contained in:
0xFEEDC0DE64
2018-09-22 03:05:34 +02:00
parent ecb30b5fd6
commit c8f6eeb80d
9 changed files with 219 additions and 21 deletions

View File

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

View 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"));

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

View File

@@ -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"));

View File

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

View File

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

View File

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

View File

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

View File

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