mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
setup the HTTPManager to serve files in the document root
This commit is contained in:
parent
c5e10465c4
commit
036dba9c2f
5 changed files with 62 additions and 436 deletions
|
@ -33,7 +33,7 @@ const quint16 DOMAIN_SERVER_HTTP_PORT = 8080;
|
|||
|
||||
DomainServer::DomainServer(int argc, char* argv[]) :
|
||||
QCoreApplication(argc, argv),
|
||||
_httpManager(DOMAIN_SERVER_HTTP_PORT),
|
||||
_httpManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath())),
|
||||
_assignmentQueueMutex(),
|
||||
_assignmentQueue(),
|
||||
_staticAssignmentFile(QString("%1/config.ds").arg(QCoreApplication::applicationDirPath())),
|
||||
|
@ -60,8 +60,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
|
||||
const char METAVOXEL_CONFIG_OPTION[] = "--metavoxelServerConfig";
|
||||
_metavoxelServerConfig = getCmdOption(argc, (const char**)argv, METAVOXEL_CONFIG_OPTION);
|
||||
|
||||
// QString documentRootString = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath());
|
||||
|
||||
//
|
||||
// char* documentRoot = new char[documentRootString.size() + 1];
|
||||
// strcpy(documentRoot, documentRootString.toLocal8Bit().constData());
|
||||
|
|
|
@ -22,11 +22,8 @@ HttpConnection::HttpConnection (QTcpSocket* socket, HttpManager* parentManager)
|
|||
QObject(parentManager),
|
||||
_parentManager(parentManager),
|
||||
_socket(socket),
|
||||
_unmasker(new MaskFilter(socket, this)),
|
||||
_stream(socket),
|
||||
_address(socket->peerAddress()),
|
||||
_webSocketPaused(false),
|
||||
_closeSent(false)
|
||||
_address(socket->peerAddress())
|
||||
{
|
||||
// take over ownership of the socket
|
||||
_socket->setParent(this);
|
||||
|
@ -50,11 +47,6 @@ HttpConnection::~HttpConnection ()
|
|||
}
|
||||
}
|
||||
|
||||
bool HttpConnection::isWebSocketRequest ()
|
||||
{
|
||||
return _requestHeaders.value("Upgrade") == "websocket";
|
||||
}
|
||||
|
||||
QList<FormData> HttpConnection::parseFormData () const
|
||||
{
|
||||
// make sure we have the correct MIME type
|
||||
|
@ -111,9 +103,7 @@ QList<FormData> HttpConnection::parseFormData () const
|
|||
return data;
|
||||
}
|
||||
|
||||
void HttpConnection::respond (
|
||||
const char* code, const QByteArray& content, const char* contentType, const Headers& headers)
|
||||
{
|
||||
void HttpConnection::respond (const char* code, const QByteArray& content, const char* contentType, const Headers& headers) {
|
||||
_socket->write("HTTP/1.1 ");
|
||||
_socket->write(code);
|
||||
_socket->write("\r\n");
|
||||
|
@ -139,6 +129,7 @@ void HttpConnection::respond (
|
|||
_socket->write("Connection: close\r\n\r\n");
|
||||
|
||||
if (csize > 0) {
|
||||
qDebug() << "Writing" << QString(content) << "\n";
|
||||
_socket->write(content);
|
||||
}
|
||||
|
||||
|
@ -148,55 +139,6 @@ void HttpConnection::respond (
|
|||
_socket->disconnectFromHost();
|
||||
}
|
||||
|
||||
void HttpConnection::switchToWebSocket (const char* protocol)
|
||||
{
|
||||
_socket->write("HTTP/1.1 101 Switching Protocols\r\n");
|
||||
_socket->write("Upgrade: websocket\r\n");
|
||||
_socket->write("Connection: Upgrade\r\n");
|
||||
_socket->write("Sec-WebSocket-Accept: ");
|
||||
|
||||
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||
hash.addData(_requestHeaders.value("Sec-WebSocket-Key"));
|
||||
hash.addData("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); // from WebSocket draft RFC
|
||||
_socket->write(hash.result().toBase64());
|
||||
|
||||
if (protocol != 0) {
|
||||
_socket->write("\r\nSec-WebSocket-Protocol: ");
|
||||
_socket->write(protocol);
|
||||
}
|
||||
_socket->write("\r\n\r\n");
|
||||
|
||||
// connect socket, start reading frames
|
||||
setWebSocketPaused(false);
|
||||
}
|
||||
|
||||
void HttpConnection::setWebSocketPaused (bool paused)
|
||||
{
|
||||
if ((_webSocketPaused = paused)) {
|
||||
_socket->disconnect(this, SLOT(readFrames()));
|
||||
|
||||
} else {
|
||||
connect(_socket, SIGNAL(readyRead()), SLOT(readFrames()));
|
||||
readFrames();
|
||||
}
|
||||
}
|
||||
|
||||
void HttpConnection::closeWebSocket (quint16 reasonCode, const char* reason)
|
||||
{
|
||||
if (reasonCode == NoReason) {
|
||||
writeFrameHeader(ConnectionClose);
|
||||
|
||||
} else {
|
||||
int rlen = (reason == 0) ? 0 : qstrlen(reason);
|
||||
writeFrameHeader(ConnectionClose, 2 + rlen);
|
||||
_stream << reasonCode;
|
||||
if (rlen > 0) {
|
||||
_socket->write(reason);
|
||||
}
|
||||
}
|
||||
_closeSent = true;
|
||||
}
|
||||
|
||||
void HttpConnection::readRequest ()
|
||||
{
|
||||
if (!_socket->canReadLine()) {
|
||||
|
@ -245,7 +187,7 @@ void HttpConnection::readHeaders ()
|
|||
|
||||
QByteArray clength = _requestHeaders.value("Content-Length");
|
||||
if (clength.isEmpty()) {
|
||||
_parentManager->handleRequest(this, "", _requestUrl.path());
|
||||
_parentManager->handleRequest(this, _requestUrl.path());
|
||||
|
||||
} else {
|
||||
_requestContent.resize(clength.toInt());
|
||||
|
@ -276,8 +218,7 @@ void HttpConnection::readHeaders ()
|
|||
}
|
||||
}
|
||||
|
||||
void HttpConnection::readContent ()
|
||||
{
|
||||
void HttpConnection::readContent() {
|
||||
int size = _requestContent.size();
|
||||
if (_socket->bytesAvailable() < size) {
|
||||
return;
|
||||
|
@ -285,201 +226,5 @@ void HttpConnection::readContent ()
|
|||
_socket->read(_requestContent.data(), size);
|
||||
_socket->disconnect(this, SLOT(readContent()));
|
||||
|
||||
_parentManager->handleRequest(this, "", _requestUrl.path());
|
||||
}
|
||||
|
||||
void HttpConnection::readFrames()
|
||||
{
|
||||
// read as many messages as are available
|
||||
while (maybeReadFrame());
|
||||
}
|
||||
|
||||
void unget (QIODevice* device, quint32 value) {
|
||||
device->ungetChar(value & 0xFF);
|
||||
device->ungetChar((value >> 8) & 0xFF);
|
||||
device->ungetChar((value >> 16) & 0xFF);
|
||||
device->ungetChar(value >> 24);
|
||||
}
|
||||
|
||||
bool HttpConnection::maybeReadFrame ()
|
||||
{
|
||||
// make sure we have at least the first two bytes
|
||||
qint64 available = _socket->bytesAvailable();
|
||||
if (available < 2 || _webSocketPaused) {
|
||||
return false;
|
||||
}
|
||||
// read the first two, which tell us whether we need more for the length
|
||||
quint8 finalOpcode, maskLength;
|
||||
_stream >> finalOpcode;
|
||||
_stream >> maskLength;
|
||||
available -= 2;
|
||||
|
||||
int byteLength = maskLength & 0x7F;
|
||||
bool masked = (maskLength & 0x80) != 0;
|
||||
int baseLength = (masked ? 4 : 0);
|
||||
int length = -1;
|
||||
if (byteLength == 127) {
|
||||
if (available >= 8) {
|
||||
quint64 longLength;
|
||||
_stream >> longLength;
|
||||
if (available >= baseLength + 8 + longLength) {
|
||||
length = longLength;
|
||||
} else {
|
||||
unget(_socket, longLength & 0xFFFFFFFF);
|
||||
unget(_socket, longLength >> 32);
|
||||
}
|
||||
}
|
||||
} else if (byteLength == 126) {
|
||||
if (available >= 2) {
|
||||
quint16 shortLength;
|
||||
_stream >> shortLength;
|
||||
if (available >= baseLength + 2 + shortLength) {
|
||||
length = shortLength;
|
||||
} else {
|
||||
_socket->ungetChar(shortLength & 0xFF);
|
||||
_socket->ungetChar(shortLength >> 8);
|
||||
}
|
||||
}
|
||||
} else if (available >= baseLength + byteLength) {
|
||||
length = byteLength;
|
||||
}
|
||||
if (length == -1) {
|
||||
_socket->ungetChar(maskLength);
|
||||
_socket->ungetChar(finalOpcode);
|
||||
return false;
|
||||
}
|
||||
|
||||
// read the mask and set it in the filter
|
||||
quint32 mask = 0;
|
||||
if (masked) {
|
||||
_stream >> mask;
|
||||
}
|
||||
_unmasker->setMask(mask);
|
||||
|
||||
// if not final, add to continuing message
|
||||
FrameOpcode opcode = (FrameOpcode)(finalOpcode & 0x0F);
|
||||
if ((finalOpcode & 0x80) == 0) {
|
||||
if (opcode != ContinuationFrame) {
|
||||
_continuingOpcode = opcode;
|
||||
}
|
||||
_continuingMessage += _unmasker->read(length);
|
||||
return true;
|
||||
}
|
||||
|
||||
// if continuing, add to and read from buffer
|
||||
QIODevice* device = _unmasker;
|
||||
FrameOpcode copcode = opcode;
|
||||
if (opcode == ContinuationFrame) {
|
||||
_continuingMessage += _unmasker->read(length);
|
||||
device = new QBuffer(&_continuingMessage, this);
|
||||
device->open(QIODevice::ReadOnly);
|
||||
copcode = _continuingOpcode;
|
||||
}
|
||||
|
||||
// act according to opcode
|
||||
switch (copcode) {
|
||||
case TextFrame:
|
||||
emit webSocketMessageAvailable(device, length, true);
|
||||
break;
|
||||
|
||||
case BinaryFrame:
|
||||
emit webSocketMessageAvailable(device, length, false);
|
||||
break;
|
||||
|
||||
case ConnectionClose:
|
||||
// if this is not a response to our own close request, send a close reply
|
||||
if (!_closeSent) {
|
||||
closeWebSocket(GoingAway);
|
||||
}
|
||||
if (length >= 2) {
|
||||
QDataStream stream(device);
|
||||
quint16 reasonCode;
|
||||
stream >> reasonCode;
|
||||
emit webSocketClosed(reasonCode, device->read(length - 2));
|
||||
} else {
|
||||
emit webSocketClosed(0, QByteArray());
|
||||
}
|
||||
_socket->disconnectFromHost();
|
||||
break;
|
||||
|
||||
case Ping:
|
||||
// send the pong out immediately
|
||||
writeFrameHeader(Pong, length, true);
|
||||
_socket->write(device->read(length));
|
||||
break;
|
||||
|
||||
case Pong:
|
||||
qWarning() << "Got unsolicited WebSocket pong." << _address << device->read(length);
|
||||
break;
|
||||
|
||||
default:
|
||||
qWarning() << "Received unknown WebSocket opcode." << _address << opcode <<
|
||||
device->read(length);
|
||||
break;
|
||||
}
|
||||
|
||||
// clear the continuing message buffer
|
||||
if (opcode == ContinuationFrame) {
|
||||
_continuingMessage.clear();
|
||||
delete device;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HttpConnection::writeFrameHeader (FrameOpcode opcode, int size, bool final)
|
||||
{
|
||||
if (_closeSent) {
|
||||
qWarning() << "Writing frame header after close message." << _address << opcode;
|
||||
return;
|
||||
}
|
||||
_socket->putChar((final ? 0x80 : 0x0) | opcode);
|
||||
if (size < 126) {
|
||||
_socket->putChar(size);
|
||||
|
||||
} else if (size < 65536) {
|
||||
_socket->putChar(126);
|
||||
_stream << (quint16)size;
|
||||
|
||||
} else {
|
||||
_socket->putChar(127);
|
||||
_stream << (quint64)size;
|
||||
}
|
||||
}
|
||||
|
||||
MaskFilter::MaskFilter (QIODevice* device, QObject* parent) :
|
||||
QIODevice(parent),
|
||||
_device(device)
|
||||
{
|
||||
open(ReadOnly);
|
||||
}
|
||||
|
||||
void MaskFilter::setMask (quint32 mask)
|
||||
{
|
||||
_mask[0] = (mask >> 24);
|
||||
_mask[1] = (mask >> 16) & 0xFF;
|
||||
_mask[2] = (mask >> 8) & 0xFF;
|
||||
_mask[3] = mask & 0xFF;
|
||||
_position = 0;
|
||||
reset();
|
||||
}
|
||||
|
||||
qint64 MaskFilter::bytesAvailable () const
|
||||
{
|
||||
return _device->bytesAvailable() + QIODevice::bytesAvailable();
|
||||
}
|
||||
|
||||
qint64 MaskFilter::readData (char* data, qint64 maxSize)
|
||||
{
|
||||
qint64 bytes = _device->read(data, maxSize);
|
||||
for (char* end = data + bytes; data < end; data++) {
|
||||
*data ^= _mask[_position];
|
||||
_position = (_position + 1) % 4;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
qint64 MaskFilter::writeData (const char* data, qint64 maxSize)
|
||||
{
|
||||
return _device->write(data, maxSize);
|
||||
_parentManager->handleRequest(this, _requestUrl.path());
|
||||
}
|
||||
|
|
|
@ -81,11 +81,6 @@ public:
|
|||
*/
|
||||
const QByteArray& requestContent () const { return _requestContent; }
|
||||
|
||||
/**
|
||||
* Checks whether the request is asking to switch to a WebSocket.
|
||||
*/
|
||||
bool isWebSocketRequest ();
|
||||
|
||||
/**
|
||||
* Parses the request content as form data, returning a list of header/content pairs.
|
||||
*/
|
||||
|
@ -97,28 +92,6 @@ public:
|
|||
void respond (const char* code, const QByteArray& content = QByteArray(),
|
||||
const char* contentType = "text/plain; charset=ISO-8859-1",
|
||||
const Headers& headers = Headers());
|
||||
|
||||
/**
|
||||
* Switches to a WebSocket.
|
||||
*/
|
||||
void switchToWebSocket (const char* protocol = 0);
|
||||
|
||||
/**
|
||||
* Writes a header for a WebSocket message of the specified size. The body of the message
|
||||
* should be written through the socket.
|
||||
*/
|
||||
void writeWebSocketHeader (int size) { writeFrameHeader(BinaryFrame, size); }
|
||||
|
||||
/**
|
||||
* Pauses or unpauses the WebSocket. A paused WebSocket buffers messages until unpaused.
|
||||
*/
|
||||
void setWebSocketPaused (bool paused);
|
||||
|
||||
/**
|
||||
* Closes the WebSocket.
|
||||
*/
|
||||
void closeWebSocket (quint16 reasonCode = NormalClosure, const char* reason = 0);
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
|
@ -148,36 +121,14 @@ protected slots:
|
|||
*/
|
||||
void readContent ();
|
||||
|
||||
/**
|
||||
* Reads any incoming WebSocket frames.
|
||||
*/
|
||||
void readFrames ();
|
||||
|
||||
protected:
|
||||
|
||||
/** The available WebSocket frame opcodes. */
|
||||
enum FrameOpcode { ContinuationFrame, TextFrame, BinaryFrame,
|
||||
ConnectionClose = 0x08, Ping, Pong };
|
||||
|
||||
/**
|
||||
* Attempts to read a single WebSocket frame, returning true if successful.
|
||||
*/
|
||||
bool maybeReadFrame ();
|
||||
|
||||
/**
|
||||
* Writes a WebSocket frame header.
|
||||
*/
|
||||
void writeFrameHeader (FrameOpcode opcode, int size = 0, bool final = true);
|
||||
|
||||
/** The parent HTTP manager. */
|
||||
HttpManager* _parentManager;
|
||||
|
||||
/** The underlying socket. */
|
||||
QTcpSocket* _socket;
|
||||
|
||||
/** The mask filter for WebSocket frames. */
|
||||
MaskFilter* _unmasker;
|
||||
|
||||
|
||||
/** The data stream for writing to the socket. */
|
||||
QDataStream _stream;
|
||||
|
||||
|
@ -198,64 +149,6 @@ protected:
|
|||
|
||||
/** The content of the request. */
|
||||
QByteArray _requestContent;
|
||||
|
||||
/** The opcode for the WebSocket message being continued. */
|
||||
FrameOpcode _continuingOpcode;
|
||||
|
||||
/** The WebSocket message being continued. */
|
||||
QByteArray _continuingMessage;
|
||||
|
||||
/** Whether or not the WebSocket is paused (buffering messages for future processing). */
|
||||
bool _webSocketPaused;
|
||||
|
||||
/** Whether or not we've sent a WebSocket close message. */
|
||||
bool _closeSent;
|
||||
};
|
||||
|
||||
/**
|
||||
* A filter device that applies a 32-bit mask.
|
||||
*/
|
||||
class MaskFilter : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new masker to filter the supplied device.
|
||||
*/
|
||||
MaskFilter (QIODevice* device, QObject* parent = 0);
|
||||
|
||||
/**
|
||||
* Sets the mask to apply.
|
||||
*/
|
||||
void setMask (quint32 mask);
|
||||
|
||||
/**
|
||||
* Returns the number of bytes available to read.
|
||||
*/
|
||||
virtual qint64 bytesAvailable () const;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Reads masked data from the underlying device.
|
||||
*/
|
||||
virtual qint64 readData (char* data, qint64 maxSize);
|
||||
|
||||
/**
|
||||
* Writes masked data to the underlying device.
|
||||
*/
|
||||
virtual qint64 writeData (const char* data, qint64 maxSize);
|
||||
|
||||
/** The underlying device. */
|
||||
QIODevice* _device;
|
||||
|
||||
/** The current mask. */
|
||||
char _mask[4];
|
||||
|
||||
/** The current position within the mask. */
|
||||
int _position;
|
||||
};
|
||||
|
||||
#endif // HTTP_CONNECTION
|
||||
|
|
|
@ -10,40 +10,59 @@
|
|||
// (https://github.com/ey6es/witgap/tree/master/src/cpp/server/http)
|
||||
//
|
||||
|
||||
#include <QTcpSocket>
|
||||
#include <QtDebug>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QMimeDatabase>
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
|
||||
#include "HttpConnection.h"
|
||||
#include "HttpManager.h"
|
||||
|
||||
void HttpSubrequestHandler::registerSubhandler (const QString& name, HttpRequestHandler* handler) {
|
||||
_subhandlers.insert(name, handler);
|
||||
}
|
||||
|
||||
bool HttpSubrequestHandler::handleRequest (
|
||||
HttpConnection* connection, const QString& name, const QString& path) {
|
||||
QString subpath = path;
|
||||
if (subpath.startsWith('/')) {
|
||||
subpath.remove(0, 1);
|
||||
bool HttpManager::handleRequest(HttpConnection* connection, const QString& path) {
|
||||
QString subPath = path;
|
||||
|
||||
// remove any slash at the beginning of the path
|
||||
if (subPath.startsWith('/')) {
|
||||
subPath.remove(0, 1);
|
||||
}
|
||||
QString subname;
|
||||
int idx = subpath.indexOf('/');
|
||||
if (idx == -1) {
|
||||
subname = subpath;
|
||||
subpath = "";
|
||||
|
||||
QString filePath;
|
||||
|
||||
// if the last thing is a trailing slash then we want to look for index file
|
||||
if (subPath.endsWith('/') || subPath.size() == 0) {
|
||||
QStringList possibleIndexFiles = QStringList() << "index.html" << "index.shtml";
|
||||
|
||||
foreach (const QString& possibleIndexFilename, possibleIndexFiles) {
|
||||
if (QFileInfo(_documentRoot + subPath + possibleIndexFilename).exists()) {
|
||||
filePath = _documentRoot + subPath + possibleIndexFilename;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (QFileInfo(_documentRoot + subPath).isFile()) {
|
||||
filePath = _documentRoot + subPath;
|
||||
}
|
||||
|
||||
if (!filePath.isEmpty()) {
|
||||
static QMimeDatabase mimeDatabase;
|
||||
|
||||
qDebug() << "Serving file at" << filePath;
|
||||
|
||||
QFile localFile(filePath);
|
||||
localFile.open(QIODevice::ReadOnly);
|
||||
|
||||
connection->respond("200 OK", localFile.readAll(), qPrintable(mimeDatabase.mimeTypeForFile(filePath).name()));
|
||||
} else {
|
||||
subname = subpath.left(idx);
|
||||
subpath = subpath.mid(idx + 1);
|
||||
}
|
||||
HttpRequestHandler* handler = _subhandlers.value(subname);
|
||||
if (handler == 0 || !handler->handleRequest(connection, subname, subpath)) {
|
||||
// respond with a 404
|
||||
connection->respond("404 Not Found", "Resource not found.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HttpManager::HttpManager(quint16 port, QObject* parent) :
|
||||
QTcpServer(parent) {
|
||||
HttpManager::HttpManager(quint16 port, const QString& documentRoot, QObject* parent) :
|
||||
QTcpServer(parent),
|
||||
_documentRoot(documentRoot) {
|
||||
// start listening on the passed port
|
||||
if (!listen(QHostAddress("0.0.0.0"), port)) {
|
||||
qDebug() << "Failed to open HTTP server socket:" << errorString();
|
||||
|
@ -54,7 +73,7 @@ HttpManager::HttpManager(quint16 port, QObject* parent) :
|
|||
connect(this, SIGNAL(newConnection()), SLOT(acceptConnections()));
|
||||
}
|
||||
|
||||
void HttpManager::acceptConnections () {
|
||||
void HttpManager::acceptConnections() {
|
||||
QTcpSocket* socket;
|
||||
while ((socket = nextPendingConnection()) != 0) {
|
||||
new HttpConnection(socket, this);
|
||||
|
|
|
@ -20,48 +20,10 @@
|
|||
class HttpConnection;
|
||||
class HttpRequestHandler;
|
||||
|
||||
/**
|
||||
* Interface for HTTP request handlers.
|
||||
*/
|
||||
class HttpRequestHandler
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Handles an HTTP request.
|
||||
*/
|
||||
virtual bool handleRequest (
|
||||
HttpConnection* connection, const QString& name, const QString& path) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles requests by forwarding them to subhandlers.
|
||||
*/
|
||||
class HttpSubrequestHandler : public HttpRequestHandler
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Registers a subhandler with the given name.
|
||||
*/
|
||||
void registerSubhandler (const QString& name, HttpRequestHandler* handler);
|
||||
|
||||
/**
|
||||
* Handles an HTTP request.
|
||||
*/
|
||||
virtual bool handleRequest (
|
||||
HttpConnection* connection, const QString& name, const QString& path);
|
||||
|
||||
protected:
|
||||
|
||||
/** Subhandlers mapped by name. */
|
||||
QHash<QString, HttpRequestHandler*> _subhandlers;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles HTTP connections.
|
||||
*/
|
||||
class HttpManager : public QTcpServer, public HttpSubrequestHandler
|
||||
class HttpManager : public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -70,7 +32,13 @@ public:
|
|||
/**
|
||||
* Initializes the manager.
|
||||
*/
|
||||
HttpManager(quint16 port, QObject* parent = 0);
|
||||
HttpManager(quint16 port, const QString& documentRoot, QObject* parent = 0);
|
||||
|
||||
/**
|
||||
* Handles an HTTP request.
|
||||
*/
|
||||
virtual bool handleRequest (HttpConnection* connection, const QString& path);
|
||||
|
||||
|
||||
protected slots:
|
||||
|
||||
|
@ -78,6 +46,8 @@ protected slots:
|
|||
* Accepts all pending connections.
|
||||
*/
|
||||
void acceptConnections ();
|
||||
protected:
|
||||
QString _documentRoot;
|
||||
};
|
||||
|
||||
#endif // HTTP_MANAGER
|
||||
|
|
Loading…
Reference in a new issue