Implemented basic vhost functionality
This commit is contained in:
@@ -1,17 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "webserverlib_global.h"
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "httpcontainers.h"
|
#include "httpresponse.h"
|
||||||
|
#include "httprequest.h"
|
||||||
|
|
||||||
class QTcpSocket;
|
class QTcpSocket;
|
||||||
|
|
||||||
class WebListener;
|
class WebListener;
|
||||||
|
|
||||||
class HttpClientConnection : public QObject
|
class WEBSERVERLIB_EXPORT HttpClientConnection : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
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
|
QString HttpResponse::statusString() const
|
||||||
|
{
|
||||||
|
return statusString(statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString HttpResponse::statusString(HttpResponse::StatusCode statusCode)
|
||||||
{
|
{
|
||||||
switch(statusCode) {
|
switch(statusCode) {
|
||||||
case HttpResponse::StatusCode::Continue: return QStringLiteral("Continue");
|
case HttpResponse::StatusCode::Continue: return QStringLiteral("Continue");
|
||||||
@@ -73,3 +78,37 @@ QString HttpResponse::statusString() const
|
|||||||
case HttpResponse::StatusCode::NetworkAuthenticationRequired: return QStringLiteral("Network Authentication Required");
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include "webserverlib_global.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QByteArray>
|
|
||||||
|
|
||||||
struct HttpRequest {
|
struct WEBSERVERLIB_EXPORT HttpResponse {
|
||||||
QString method;
|
|
||||||
QString path;
|
|
||||||
QString protocol;
|
|
||||||
QHash<QString, QString> headers;
|
|
||||||
QByteArray body;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HttpResponse {
|
|
||||||
enum class StatusCode {
|
enum class StatusCode {
|
||||||
// 1xx Informational responses
|
// 1xx Informational responses
|
||||||
Continue = 100, // Continue
|
Continue = 100, // Continue
|
||||||
@@ -98,4 +91,39 @@ struct HttpResponse {
|
|||||||
QHash<QString, QString> headers;
|
QHash<QString, QString> headers;
|
||||||
|
|
||||||
QString statusString() const;
|
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 <QObject>
|
||||||
#include "webserverlib_global.h"
|
#include "webserverlib_global.h"
|
||||||
|
|
||||||
|
class HttpClientConnection;
|
||||||
|
class HttpRequest;
|
||||||
|
|
||||||
class WEBSERVERLIB_EXPORT WebApplication : public QObject
|
class WEBSERVERLIB_EXPORT WebApplication : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -11,4 +14,6 @@ public:
|
|||||||
WebApplication(QObject *parent = Q_NULLPTR);
|
WebApplication(QObject *parent = Q_NULLPTR);
|
||||||
|
|
||||||
virtual void start() = 0;
|
virtual void start() = 0;
|
||||||
|
|
||||||
|
virtual void handleRequest(HttpClientConnection *connection, const HttpRequest &request) = 0;
|
||||||
};
|
};
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "utils/netutils.h"
|
#include "utils/netutils.h"
|
||||||
#include "httpclientconnection.h"
|
#include "httpclientconnection.h"
|
||||||
|
#include "webapplication.h"
|
||||||
|
|
||||||
WebListener::WebListener(const QJsonObject &config, const QHash<QString, WebApplication*> &applications, QObject *parent) :
|
WebListener::WebListener(const QJsonObject &config, const QHash<QString, WebApplication*> &applications, QObject *parent) :
|
||||||
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")
|
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());
|
.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)
|
void WebListener::handleRequest(HttpClientConnection *connection, const HttpRequest &request)
|
||||||
{
|
{
|
||||||
HttpResponse response;
|
QString host;
|
||||||
response.protocol = request.protocol;
|
|
||||||
response.statusCode = HttpResponse::StatusCode::OK;
|
{
|
||||||
connection->sendResponse(response, request.path);
|
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)
|
void WebListener::acceptError(QAbstractSocket::SocketError socketError)
|
||||||
|
@@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
#include <QAbstractSocket>
|
#include <QAbstractSocket>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
class QJsonObject;
|
class QJsonObject;
|
||||||
template <class Key, class T> class QHash;
|
|
||||||
class QTcpServer;
|
class QTcpServer;
|
||||||
|
|
||||||
class WebApplication;
|
class WebApplication;
|
||||||
@@ -29,7 +29,10 @@ private Q_SLOTS:
|
|||||||
void newConnection();
|
void newConnection();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using HostsContainer = QHash<QString, WebApplication*>;
|
||||||
|
|
||||||
QTcpServer *m_tcpServer;
|
QTcpServer *m_tcpServer;
|
||||||
QHostAddress m_address;
|
QHostAddress m_address;
|
||||||
quint16 m_port;
|
quint16 m_port;
|
||||||
|
HostsContainer m_hosts;
|
||||||
};
|
};
|
||||||
|
@@ -12,14 +12,16 @@ SOURCES += \
|
|||||||
webapplication.cpp \
|
webapplication.cpp \
|
||||||
webplugin.cpp \
|
webplugin.cpp \
|
||||||
httpclientconnection.cpp \
|
httpclientconnection.cpp \
|
||||||
httpcontainers.cpp
|
httprequest.cpp \
|
||||||
|
httpresponse.cpp
|
||||||
|
|
||||||
HEADERS += webserverlib_global.h \
|
HEADERS += webserverlib_global.h \
|
||||||
weblistener.h \
|
weblistener.h \
|
||||||
webapplication.h \
|
webapplication.h \
|
||||||
webplugin.h \
|
webplugin.h \
|
||||||
httpclientconnection.h \
|
httpclientconnection.h \
|
||||||
httpcontainers.h
|
httprequest.h \
|
||||||
|
httpresponse.h
|
||||||
|
|
||||||
FORMS +=
|
FORMS +=
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user