mirror of
https://github.com/YACReader/yacreader
synced 2026-03-29 00:49:44 -04:00
Update QtWebapp to 1.7.11
This commit is contained in:
@ -6,8 +6,10 @@
|
||||
#include "httpconnectionhandler.h"
|
||||
#include "httpresponse.h"
|
||||
|
||||
HttpConnectionHandler::HttpConnectionHandler(QSettings* settings, HttpRequestHandler* requestHandler, QSslConfiguration* sslConfiguration)
|
||||
: QThread()
|
||||
using namespace stefanfrings;
|
||||
|
||||
HttpConnectionHandler::HttpConnectionHandler(const QSettings *settings, HttpRequestHandler *requestHandler, const QSslConfiguration* sslConfiguration)
|
||||
: QObject()
|
||||
{
|
||||
Q_ASSERT(settings!=nullptr);
|
||||
Q_ASSERT(requestHandler!=nullptr);
|
||||
@ -17,43 +19,56 @@ HttpConnectionHandler::HttpConnectionHandler(QSettings* settings, HttpRequestHan
|
||||
currentRequest=nullptr;
|
||||
busy=false;
|
||||
|
||||
// Create TCP or SSL socket
|
||||
createSocket();
|
||||
// execute signals in a new thread
|
||||
thread = new QThread();
|
||||
thread->start();
|
||||
qDebug("HttpConnectionHandler (%p): thread started", static_cast<void*>(this));
|
||||
moveToThread(thread);
|
||||
readTimer.moveToThread(thread);
|
||||
readTimer.setSingleShot(true);
|
||||
|
||||
// execute signals in my own thread
|
||||
moveToThread(this);
|
||||
socket->moveToThread(this);
|
||||
readTimer.moveToThread(this);
|
||||
// Create TCP or SSL socket
|
||||
createSocket();
|
||||
socket->moveToThread(thread);
|
||||
|
||||
// Connect signals
|
||||
connect(socket, SIGNAL(readyRead()), SLOT(read()));
|
||||
connect(socket, SIGNAL(disconnected()), SLOT(disconnected()));
|
||||
connect(&readTimer, SIGNAL(timeout()), SLOT(readTimeout()));
|
||||
readTimer.setSingleShot(true);
|
||||
connect(thread, SIGNAL(finished()), this, SLOT(thread_done()));
|
||||
|
||||
qDebug("HttpConnectionHandler (%p): constructed", this);
|
||||
this->start();
|
||||
qDebug("HttpConnectionHandler (%p): constructed", static_cast<void*>(this));
|
||||
}
|
||||
|
||||
|
||||
void HttpConnectionHandler::thread_done()
|
||||
{
|
||||
readTimer.stop();
|
||||
socket->close();
|
||||
delete socket;
|
||||
qDebug("HttpConnectionHandler (%p): thread stopped", static_cast<void*>(this));
|
||||
}
|
||||
|
||||
|
||||
HttpConnectionHandler::~HttpConnectionHandler()
|
||||
{
|
||||
quit();
|
||||
wait();
|
||||
qDebug("HttpConnectionHandler (%p): destroyed", this);
|
||||
thread->quit();
|
||||
thread->wait();
|
||||
thread->deleteLater();
|
||||
qDebug("HttpConnectionHandler (%p): destroyed", static_cast<void*>(this));
|
||||
}
|
||||
|
||||
|
||||
void HttpConnectionHandler::createSocket()
|
||||
{
|
||||
// If SSL is supported and configured, then create an instance of QSslSocket
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#ifndef QT_NO_SSL
|
||||
if (sslConfiguration)
|
||||
{
|
||||
QSslSocket* sslSocket=new QSslSocket();
|
||||
sslSocket->setSslConfiguration(*sslConfiguration);
|
||||
socket=sslSocket;
|
||||
qDebug("HttpConnectionHandler (%p): SSL is enabled", this);
|
||||
qDebug("HttpConnectionHandler (%p): SSL is enabled", static_cast<void*>(this));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -62,27 +77,9 @@ void HttpConnectionHandler::createSocket()
|
||||
}
|
||||
|
||||
|
||||
void HttpConnectionHandler::run()
|
||||
{
|
||||
qDebug("HttpConnectionHandler (%p): thread started", this);
|
||||
try
|
||||
{
|
||||
exec();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
qCritical("HttpConnectionHandler (%p): an uncatched exception occured in the thread",this);
|
||||
}
|
||||
socket->close();
|
||||
delete socket;
|
||||
readTimer.stop();
|
||||
qDebug("HttpConnectionHandler (%p): thread stopped", this);
|
||||
}
|
||||
|
||||
|
||||
void HttpConnectionHandler::handleConnection(tSocketDescriptor socketDescriptor)
|
||||
{
|
||||
qDebug("HttpConnectionHandler (%p): handle new connection", this);
|
||||
qDebug("HttpConnectionHandler (%p): handle new connection", static_cast<void*>(this));
|
||||
busy = true;
|
||||
Q_ASSERT(socket->isOpen()==false); // if not, then the handler is already busy
|
||||
|
||||
@ -93,16 +90,17 @@ void HttpConnectionHandler::handleConnection(tSocketDescriptor socketDescriptor)
|
||||
|
||||
if (!socket->setSocketDescriptor(socketDescriptor))
|
||||
{
|
||||
qCritical("HttpConnectionHandler (%p): cannot initialize socket: %s", this,qPrintable(socket->errorString()));
|
||||
qCritical("HttpConnectionHandler (%p): cannot initialize socket: %s",
|
||||
static_cast<void*>(this),qPrintable(socket->errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#ifndef QT_NO_SSL
|
||||
// Switch on encryption, if SSL is configured
|
||||
if (sslConfiguration)
|
||||
{
|
||||
qDebug("HttpConnectionHandler (%p): Starting encryption", this);
|
||||
((QSslSocket*)socket)->startServerEncryption();
|
||||
qDebug("HttpConnectionHandler (%p): Starting encryption", static_cast<void*>(this));
|
||||
(static_cast<QSslSocket*>(socket))->startServerEncryption();
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -128,12 +126,12 @@ void HttpConnectionHandler::setBusy()
|
||||
|
||||
void HttpConnectionHandler::readTimeout()
|
||||
{
|
||||
qDebug("HttpConnectionHandler (%p): read timeout occured",this);
|
||||
qDebug("HttpConnectionHandler (%p): read timeout occured",static_cast<void*>(this));
|
||||
|
||||
//Commented out because QWebView cannot handle this.
|
||||
//socket->write("HTTP/1.1 408 request timeout\r\nConnection: close\r\n\r\n408 request timeout\r\n");
|
||||
|
||||
socket->flush();
|
||||
while(socket->bytesToWrite()) socket->waitForBytesWritten();
|
||||
socket->disconnectFromHost();
|
||||
delete currentRequest;
|
||||
currentRequest=nullptr;
|
||||
@ -142,7 +140,7 @@ void HttpConnectionHandler::readTimeout()
|
||||
|
||||
void HttpConnectionHandler::disconnected()
|
||||
{
|
||||
qDebug("HttpConnectionHandler (%p): disconnected", this);
|
||||
qDebug("HttpConnectionHandler (%p): disconnected", static_cast<void*>(this));
|
||||
socket->close();
|
||||
readTimer.stop();
|
||||
busy = false;
|
||||
@ -154,7 +152,7 @@ void HttpConnectionHandler::read()
|
||||
while (socket->bytesAvailable())
|
||||
{
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpConnectionHandler (%p): read input",this);
|
||||
qDebug("HttpConnectionHandler (%p): read input",static_cast<void*>(this));
|
||||
#endif
|
||||
|
||||
// Create new HttpRequest object if necessary
|
||||
@ -180,7 +178,7 @@ void HttpConnectionHandler::read()
|
||||
if (currentRequest->getStatus()==HttpRequest::abort)
|
||||
{
|
||||
socket->write("HTTP/1.1 413 entity too large\r\nConnection: close\r\n\r\n413 Entity too large\r\n");
|
||||
socket->flush();
|
||||
while(socket->bytesToWrite()) socket->waitForBytesWritten();
|
||||
socket->disconnectFromHost();
|
||||
delete currentRequest;
|
||||
currentRequest=nullptr;
|
||||
@ -191,7 +189,7 @@ void HttpConnectionHandler::read()
|
||||
if (currentRequest->getStatus()==HttpRequest::complete)
|
||||
{
|
||||
readTimer.stop();
|
||||
qDebug("HttpConnectionHandler (%p): received request",this);
|
||||
qDebug("HttpConnectionHandler (%p): received request",static_cast<void*>(this));
|
||||
|
||||
// Copy the Connection:close header to the response
|
||||
HttpResponse response(socket);
|
||||
@ -220,7 +218,8 @@ void HttpConnectionHandler::read()
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
qCritical("HttpConnectionHandler (%p): An uncatched exception occured in the request handler",this);
|
||||
qCritical("HttpConnectionHandler (%p): An uncatched exception occured in the request handler",
|
||||
static_cast<void*>(this));
|
||||
}
|
||||
|
||||
// Finalize sending the response if not already done
|
||||
@ -229,7 +228,7 @@ void HttpConnectionHandler::read()
|
||||
response.write(QByteArray(),true);
|
||||
}
|
||||
|
||||
qDebug("HttpConnectionHandler (%p): finished request",this);
|
||||
qDebug("HttpConnectionHandler (%p): finished request",static_cast<void*>(this));
|
||||
|
||||
// Find out whether the connection must be closed
|
||||
if (!closeConnection)
|
||||
@ -259,7 +258,7 @@ void HttpConnectionHandler::read()
|
||||
// Close the connection or prepare for the next request on the same connection.
|
||||
if (closeConnection)
|
||||
{
|
||||
socket->flush();
|
||||
while(socket->bytesToWrite()) socket->waitForBytesWritten();
|
||||
socket->disconnectFromHost();
|
||||
}
|
||||
else
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#ifndef HTTPCONNECTIONHANDLER_H
|
||||
#define HTTPCONNECTIONHANDLER_H
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#ifndef QT_NO_SSL
|
||||
#include <QSslConfiguration>
|
||||
#endif
|
||||
#include <QTcpSocket>
|
||||
@ -17,6 +17,8 @@
|
||||
#include "httprequest.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/** Alias type definition, for compatibility to different Qt versions */
|
||||
#if QT_VERSION >= 0x050000
|
||||
typedef qintptr tSocketDescriptor;
|
||||
@ -25,7 +27,7 @@
|
||||
#endif
|
||||
|
||||
/** Alias for QSslConfiguration if OpenSSL is not supported */
|
||||
#ifdef QT_NO_OPENSSL
|
||||
#ifdef QT_NO_SSL
|
||||
#define QSslConfiguration QObject
|
||||
#endif
|
||||
|
||||
@ -44,7 +46,7 @@
|
||||
The readTimeout value defines the maximum time to wait for a complete HTTP request.
|
||||
@see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize.
|
||||
*/
|
||||
class DECLSPEC HttpConnectionHandler : public QThread {
|
||||
class DECLSPEC HttpConnectionHandler : public QObject {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(HttpConnectionHandler)
|
||||
|
||||
@ -56,7 +58,8 @@ public:
|
||||
@param requestHandler Handler that will process each incoming HTTP request
|
||||
@param sslConfiguration SSL (HTTPS) will be used if not NULL
|
||||
*/
|
||||
HttpConnectionHandler(QSettings* settings, HttpRequestHandler* requestHandler, QSslConfiguration* sslConfiguration=nullptr);
|
||||
HttpConnectionHandler(const QSettings* settings, HttpRequestHandler* requestHandler,
|
||||
const QSslConfiguration* sslConfiguration=nullptr);
|
||||
|
||||
/** Destructor */
|
||||
virtual ~HttpConnectionHandler();
|
||||
@ -70,11 +73,14 @@ public:
|
||||
private:
|
||||
|
||||
/** Configuration settings */
|
||||
QSettings* settings;
|
||||
const QSettings* settings;
|
||||
|
||||
/** TCP socket of the current connection */
|
||||
QTcpSocket* socket;
|
||||
|
||||
/** The thread that processes events of this connection */
|
||||
QThread* thread;
|
||||
|
||||
/** Time for read timeout detection */
|
||||
QTimer readTimer;
|
||||
|
||||
@ -88,10 +94,7 @@ private:
|
||||
bool busy;
|
||||
|
||||
/** Configuration for SSL */
|
||||
QSslConfiguration* sslConfiguration;
|
||||
|
||||
/** Executes the threads own event loop */
|
||||
void run() override;
|
||||
const QSslConfiguration* sslConfiguration;
|
||||
|
||||
/** Create SSL or TCP socket */
|
||||
void createSocket();
|
||||
@ -102,7 +105,7 @@ public slots:
|
||||
Received from from the listener, when the handler shall start processing a new connection.
|
||||
@param socketDescriptor references the accepted connection.
|
||||
*/
|
||||
void handleConnection(tSocketDescriptor socketDescriptor);
|
||||
void handleConnection(const tSocketDescriptor socketDescriptor);
|
||||
|
||||
private slots:
|
||||
|
||||
@ -115,6 +118,10 @@ private slots:
|
||||
/** Received from the socket when a connection has been closed */
|
||||
void disconnected();
|
||||
|
||||
/** Cleanup after the thread is closed */
|
||||
void thread_done();
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // HTTPCONNECTIONHANDLER_H
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#ifndef QT_NO_SSL
|
||||
#include <QSslSocket>
|
||||
#include <QSslKey>
|
||||
#include <QSslCertificate>
|
||||
@ -7,13 +7,15 @@
|
||||
#include <QDir>
|
||||
#include "httpconnectionhandlerpool.h"
|
||||
|
||||
HttpConnectionHandlerPool::HttpConnectionHandlerPool(QSettings* settings, HttpRequestHandler* requestHandler)
|
||||
using namespace stefanfrings;
|
||||
|
||||
HttpConnectionHandlerPool::HttpConnectionHandlerPool(const QSettings *settings, HttpRequestHandler *requestHandler)
|
||||
: QObject()
|
||||
{
|
||||
Q_ASSERT(settings!=nullptr);
|
||||
Q_ASSERT(settings!=0);
|
||||
this->settings=settings;
|
||||
this->requestHandler=requestHandler;
|
||||
this->sslConfiguration=nullptr;
|
||||
this->sslConfiguration=NULL;
|
||||
loadSslConfig();
|
||||
cleanupTimer.start(settings->value("cleanupInterval",1000).toInt());
|
||||
connect(&cleanupTimer, SIGNAL(timeout()), SLOT(cleanup()));
|
||||
@ -34,7 +36,7 @@ HttpConnectionHandlerPool::~HttpConnectionHandlerPool()
|
||||
|
||||
HttpConnectionHandler* HttpConnectionHandlerPool::getConnectionHandler()
|
||||
{
|
||||
HttpConnectionHandler* freeHandler=nullptr;
|
||||
HttpConnectionHandler* freeHandler=0;
|
||||
mutex.lock();
|
||||
// find a free handler in pool
|
||||
foreach(HttpConnectionHandler* handler, pool)
|
||||
@ -91,7 +93,7 @@ void HttpConnectionHandlerPool::loadSslConfig()
|
||||
QString sslCertFileName=settings->value("sslCertFile","").toString();
|
||||
if (!sslKeyFileName.isEmpty() && !sslCertFileName.isEmpty())
|
||||
{
|
||||
#ifdef QT_NO_OPENSSL
|
||||
#ifdef QT_NO_SSL
|
||||
qWarning("HttpConnectionHandlerPool: SSL is not supported");
|
||||
#else
|
||||
// Convert relative fileNames to absolute, based on the directory of the config file.
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
#include "httpglobal.h"
|
||||
#include "httpconnectionhandler.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/**
|
||||
Pool of http connection handlers. The size of the pool grows and
|
||||
shrinks on demand.
|
||||
@ -54,7 +56,7 @@ public:
|
||||
@param requestHandler The handler that will process each received HTTP request.
|
||||
@warning The requestMapper gets deleted by the destructor of this pool
|
||||
*/
|
||||
HttpConnectionHandlerPool(QSettings* settings, HttpRequestHandler* requestHandler);
|
||||
HttpConnectionHandlerPool(const QSettings* settings, HttpRequestHandler *requestHandler);
|
||||
|
||||
/** Destructor */
|
||||
virtual ~HttpConnectionHandlerPool();
|
||||
@ -65,7 +67,7 @@ public:
|
||||
private:
|
||||
|
||||
/** Settings for this pool */
|
||||
QSettings* settings;
|
||||
const QSettings* settings;
|
||||
|
||||
/** Will be assigned to each Connectionhandler during their creation */
|
||||
HttpRequestHandler* requestHandler;
|
||||
@ -92,4 +94,6 @@ private slots:
|
||||
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // HTTPCONNECTIONHANDLERPOOL_H
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
|
||||
#include "httpcookie.h"
|
||||
|
||||
using namespace stefanfrings;
|
||||
|
||||
HttpCookie::HttpCookie()
|
||||
{
|
||||
version=1;
|
||||
|
||||
15
third_party/QtWebApp/httpserver/httpcookie.h
vendored
15
third_party/QtWebApp/httpserver/httpcookie.h
vendored
@ -10,6 +10,8 @@
|
||||
#include <QByteArray>
|
||||
#include "httpglobal.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/**
|
||||
HTTP cookie as defined in RFC 2109. This class can also parse
|
||||
RFC 2965 cookies, but skips fields that are not defined in RFC
|
||||
@ -34,7 +36,10 @@ public:
|
||||
@param secure If true, the cookie will be sent by the browser to the server only on secure connections
|
||||
@param httpOnly If true, the browser does not allow client-side scripts to access the cookie
|
||||
*/
|
||||
HttpCookie(const QByteArray name, const QByteArray value, const int maxAge, const QByteArray path="/", const QByteArray comment=QByteArray(), const QByteArray domain=QByteArray(), const bool secure=false, const bool httpOnly=false);
|
||||
HttpCookie(const QByteArray name, const QByteArray value, const int maxAge,
|
||||
const QByteArray path="/", const QByteArray comment=QByteArray(),
|
||||
const QByteArray domain=QByteArray(), const bool secure=false,
|
||||
const bool httpOnly=false);
|
||||
|
||||
/**
|
||||
Create a cookie from a string.
|
||||
@ -72,7 +77,7 @@ public:
|
||||
/** Set secure mode, so that the cookie will be sent by the browser to the server only on secure connections */
|
||||
void setSecure(const bool secure);
|
||||
|
||||
/** Set secure mode, so that he browser does not allow client-side scripts to access the cookie */
|
||||
/** Set HTTP-only mode, so that he browser does not allow client-side scripts to access the cookie */
|
||||
void setHttpOnly(const bool httpOnly);
|
||||
|
||||
/** Get the name of this cookie */
|
||||
@ -87,7 +92,7 @@ public:
|
||||
/** Get the domain of this cookie */
|
||||
QByteArray getDomain() const;
|
||||
|
||||
/** Set the maximum age of this cookie in seconds. */
|
||||
/** Get the maximum age of this cookie in seconds. */
|
||||
int getMaxAge() const;
|
||||
|
||||
/** Set the path of this cookie */
|
||||
@ -96,7 +101,7 @@ public:
|
||||
/** Get the secure flag of this cookie */
|
||||
bool getSecure() const;
|
||||
|
||||
/** Get the httpOnly of this cookie */
|
||||
/** Get the HTTP-only flag of this cookie */
|
||||
bool getHttpOnly() const;
|
||||
|
||||
/** Returns always 1 */
|
||||
@ -116,4 +121,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // HTTPCOOKIE_H
|
||||
|
||||
@ -2,6 +2,6 @@
|
||||
|
||||
const char* getQtWebAppLibVersion()
|
||||
{
|
||||
return "1.6.5";
|
||||
return "1.7.11";
|
||||
}
|
||||
|
||||
|
||||
1
third_party/QtWebApp/httpserver/httpglobal.h
vendored
1
third_party/QtWebApp/httpserver/httpglobal.h
vendored
@ -23,5 +23,6 @@
|
||||
/** Get the library version number */
|
||||
DECLSPEC const char* getQtWebAppLibVersion();
|
||||
|
||||
|
||||
#endif // HTTPGLOBAL_H
|
||||
|
||||
|
||||
27
third_party/QtWebApp/httpserver/httplistener.cpp
vendored
27
third_party/QtWebApp/httpserver/httplistener.cpp
vendored
@ -8,7 +8,9 @@
|
||||
#include "httpconnectionhandlerpool.h"
|
||||
#include <QCoreApplication>
|
||||
|
||||
HttpListener::HttpListener(QSettings* settings, HttpRequestHandler* requestHandler, QObject *parent)
|
||||
using namespace stefanfrings;
|
||||
|
||||
HttpListener::HttpListener(const QSettings* settings, HttpRequestHandler* requestHandler, QObject *parent)
|
||||
: QTcpServer(parent)
|
||||
{
|
||||
Q_ASSERT(settings!=nullptr);
|
||||
@ -37,21 +39,11 @@ void HttpListener::listen()
|
||||
pool=new HttpConnectionHandlerPool(settings,requestHandler);
|
||||
}
|
||||
QString host = settings->value("host").toString();
|
||||
int port=settings->value("port").toInt();
|
||||
quint16 port=settings->value("port").toUInt() & 0xFFFF;
|
||||
QTcpServer::listen(host.isEmpty() ? QHostAddress::Any : QHostAddress(host), port);
|
||||
|
||||
//YACReader---------------------------------------------
|
||||
//try to listen even if the default port is no available
|
||||
int i = 0;
|
||||
while (!isListening() && i < 1000) {
|
||||
QTcpServer::listen(QHostAddress::Any, (rand() % 45535)+20000);
|
||||
i++;
|
||||
}
|
||||
//------------------------------------------------------
|
||||
|
||||
if (!isListening())
|
||||
{
|
||||
qDebug("HttpListener: Cannot bind on port %i: %s",port,qPrintable(errorString()));
|
||||
qCritical("HttpListener: Cannot bind on port %i: %s",port,qPrintable(errorString()));
|
||||
}
|
||||
else {
|
||||
qDebug("HttpListener: Listening on port %i",port);
|
||||
@ -82,17 +74,14 @@ void HttpListener::incomingConnection(tSocketDescriptor socketDescriptor) {
|
||||
// Let the handler process the new connection.
|
||||
if (freeHandler)
|
||||
{
|
||||
// The descriptor is passed via signal/slot because the handler lives in another
|
||||
// thread and cannot open the socket when directly called by another thread.
|
||||
connect(this,SIGNAL(handleConnection(tSocketDescriptor)),freeHandler,SLOT(handleConnection(tSocketDescriptor)));
|
||||
emit handleConnection(socketDescriptor);
|
||||
disconnect(this,SIGNAL(handleConnection(tSocketDescriptor)),freeHandler,SLOT(handleConnection(tSocketDescriptor)));
|
||||
// The descriptor is passed via event queue because the handler lives in another thread
|
||||
QMetaObject::invokeMethod(freeHandler, "handleConnection", Qt::QueuedConnection, Q_ARG(tSocketDescriptor, socketDescriptor));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reject the connection
|
||||
qDebug("HttpListener: Too many incoming connections");
|
||||
auto* socket=new QTcpSocket(this);
|
||||
QTcpSocket* socket=new QTcpSocket(this);
|
||||
socket->setSocketDescriptor(socketDescriptor);
|
||||
connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
|
||||
socket->write("HTTP/1.1 503 too many connections\r\nConnection: close\r\n\r\nToo many connections\r\n");
|
||||
|
||||
17
third_party/QtWebApp/httpserver/httplistener.h
vendored
17
third_party/QtWebApp/httpserver/httplistener.h
vendored
@ -14,6 +14,8 @@
|
||||
#include "httpconnectionhandlerpool.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/**
|
||||
Listens for incoming TCP connections and and passes all incoming HTTP requests to your implementation of HttpRequestHandler,
|
||||
which processes the request and generates the response (usually a HTML document).
|
||||
@ -47,12 +49,17 @@ public:
|
||||
/**
|
||||
Constructor.
|
||||
Creates a connection pool and starts listening on the configured host and port.
|
||||
@param settings Configuration settings for the HTTP server. Must not be 0.
|
||||
@param settings Configuration settings, usually stored in an INI file. Must not be 0.
|
||||
Settings are read from the current group, so the caller must have called settings->beginGroup().
|
||||
Because the group must not change during runtime, it is recommended to provide a
|
||||
separate QSettings instance that is not used by other parts of the program.
|
||||
The HttpListener does not take over ownership of the QSettings instance, so the
|
||||
caller should destroy it during shutdown.
|
||||
@param requestHandler Processes each received HTTP request, usually by dispatching to controller classes.
|
||||
@param parent Parent object.
|
||||
@warning Ensure to close or delete the listener before deleting the request handler.
|
||||
*/
|
||||
HttpListener(QSettings* settings, HttpRequestHandler* requestHandler, QObject* parent = nullptr);
|
||||
HttpListener(const QSettings* settings, HttpRequestHandler* requestHandler, QObject* parent=nullptr);
|
||||
|
||||
/** Destructor */
|
||||
virtual ~HttpListener();
|
||||
@ -71,12 +78,12 @@ public:
|
||||
protected:
|
||||
|
||||
/** Serves new incoming connection requests */
|
||||
void incomingConnection(tSocketDescriptor socketDescriptor) override;
|
||||
void incomingConnection(tSocketDescriptor socketDescriptor);
|
||||
|
||||
private:
|
||||
|
||||
/** Configuration settings for the HTTP server */
|
||||
QSettings* settings;
|
||||
const QSettings* settings;
|
||||
|
||||
/** Point to the reuqest handler which processes all HTTP requests */
|
||||
HttpRequestHandler* requestHandler;
|
||||
@ -95,4 +102,6 @@ signals:
|
||||
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // HTTPLISTENER_H
|
||||
|
||||
85
third_party/QtWebApp/httpserver/httprequest.cpp
vendored
85
third_party/QtWebApp/httpserver/httprequest.cpp
vendored
@ -8,24 +8,29 @@
|
||||
#include <QDir>
|
||||
#include "httpcookie.h"
|
||||
|
||||
HttpRequest::HttpRequest(QSettings* settings)
|
||||
using namespace stefanfrings;
|
||||
|
||||
HttpRequest::HttpRequest(const QSettings* settings)
|
||||
{
|
||||
status=waitForRequest;
|
||||
currentSize=0;
|
||||
expectedBodySize=0;
|
||||
maxSize=settings->value("maxRequestSize","16000").toInt();
|
||||
maxMultiPartSize=settings->value("maxMultiPartSize","1000000").toInt();
|
||||
tempFile=nullptr;
|
||||
}
|
||||
|
||||
|
||||
void HttpRequest::readRequest(QTcpSocket* socket)
|
||||
{
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: read request");
|
||||
#endif
|
||||
int toRead=maxSize-currentSize+1; // allow one byte more to be able to detect overflow
|
||||
lineBuffer.append(socket->readLine(toRead));
|
||||
currentSize+=lineBuffer.size();
|
||||
if (!lineBuffer.contains('\r') && !lineBuffer.contains('\n'))
|
||||
QByteArray dataRead = socket->readLine(toRead);
|
||||
currentSize += dataRead.size();
|
||||
lineBuffer.append(dataRead);
|
||||
if (!lineBuffer.contains("\r\n"))
|
||||
{
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: collecting more parts until line break");
|
||||
@ -36,13 +41,15 @@ void HttpRequest::readRequest(QTcpSocket* socket)
|
||||
lineBuffer.clear();
|
||||
if (!newData.isEmpty())
|
||||
{
|
||||
qDebug("HttpRequest: from %s: %s",qPrintable(socket->peerAddress().toString()),newData.data());
|
||||
QList<QByteArray> list=newData.split(' ');
|
||||
if (list.count()!=3 || !list.at(2).contains("HTTP"))
|
||||
{
|
||||
qWarning("HttpRequest: received broken HTTP request, invalid first line");
|
||||
status=abort;
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
method=list.at(0).trimmed();
|
||||
path=list.at(1);
|
||||
version=list.at(2);
|
||||
@ -54,13 +61,11 @@ void HttpRequest::readRequest(QTcpSocket* socket)
|
||||
|
||||
void HttpRequest::readHeader(QTcpSocket* socket)
|
||||
{
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: read header");
|
||||
#endif
|
||||
int toRead=maxSize-currentSize+1; // allow one byte more to be able to detect overflow
|
||||
lineBuffer.append(socket->readLine(toRead));
|
||||
currentSize+=lineBuffer.size();
|
||||
if (!lineBuffer.contains('\r') && !lineBuffer.contains('\n'))
|
||||
QByteArray dataRead = socket->readLine(toRead);
|
||||
currentSize += dataRead.size();
|
||||
lineBuffer.append(dataRead);
|
||||
if (!lineBuffer.contains("\r\n"))
|
||||
{
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: collecting more parts until line break");
|
||||
@ -166,18 +171,23 @@ void HttpRequest::readBody(QTcpSocket* socket)
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: receiving multipart body");
|
||||
#endif
|
||||
if (!tempFile.isOpen())
|
||||
// Create an object for the temporary file, if not already present
|
||||
if (tempFile == nullptr)
|
||||
{
|
||||
tempFile.open();
|
||||
tempFile = new QTemporaryFile;
|
||||
}
|
||||
if (!tempFile->isOpen())
|
||||
{
|
||||
tempFile->open();
|
||||
}
|
||||
// Transfer data in 64kb blocks
|
||||
int fileSize=tempFile.size();
|
||||
int toRead=expectedBodySize-fileSize;
|
||||
qint64 fileSize=tempFile->size();
|
||||
qint64 toRead=expectedBodySize-fileSize;
|
||||
if (toRead>65536)
|
||||
{
|
||||
toRead=65536;
|
||||
}
|
||||
fileSize+=tempFile.write(socket->read(toRead));
|
||||
fileSize+=tempFile->write(socket->read(toRead));
|
||||
if (fileSize>=maxMultiPartSize)
|
||||
{
|
||||
qWarning("HttpRequest: received too many multipart bytes");
|
||||
@ -188,13 +198,13 @@ void HttpRequest::readBody(QTcpSocket* socket)
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: received whole multipart body");
|
||||
#endif
|
||||
tempFile.flush();
|
||||
if (tempFile.error())
|
||||
tempFile->flush();
|
||||
if (tempFile->error())
|
||||
{
|
||||
qCritical("HttpRequest: Error writing temp file for multipart body");
|
||||
}
|
||||
parseMultiPartFile();
|
||||
tempFile.close();
|
||||
tempFile->close();
|
||||
status=complete;
|
||||
}
|
||||
}
|
||||
@ -381,10 +391,11 @@ QByteArray HttpRequest::urlDecode(const QByteArray source)
|
||||
while (percentChar>=0)
|
||||
{
|
||||
bool ok;
|
||||
char byte=buffer.mid(percentChar+1,2).toInt(&ok,16);
|
||||
int hexCode=buffer.mid(percentChar+1,2).toInt(&ok,16);
|
||||
if (ok)
|
||||
{
|
||||
buffer.replace(percentChar,3,(char*)&byte,1);
|
||||
char c=char(hexCode);
|
||||
buffer.replace(percentChar,3,&c,1);
|
||||
}
|
||||
percentChar=buffer.indexOf('%',percentChar+1);
|
||||
}
|
||||
@ -395,18 +406,18 @@ QByteArray HttpRequest::urlDecode(const QByteArray source)
|
||||
void HttpRequest::parseMultiPartFile()
|
||||
{
|
||||
qDebug("HttpRequest: parsing multipart temp file");
|
||||
tempFile.seek(0);
|
||||
tempFile->seek(0);
|
||||
bool finished=false;
|
||||
while (!tempFile.atEnd() && !finished && !tempFile.error())
|
||||
while (!tempFile->atEnd() && !finished && !tempFile->error())
|
||||
{
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: reading multpart headers");
|
||||
#endif
|
||||
QByteArray fieldName;
|
||||
QByteArray fileName;
|
||||
while (!tempFile.atEnd() && !finished && !tempFile.error())
|
||||
while (!tempFile->atEnd() && !finished && !tempFile->error())
|
||||
{
|
||||
QByteArray line=tempFile.readLine(65536).trimmed();
|
||||
QByteArray line=tempFile->readLine(65536).trimmed();
|
||||
if (line.startsWith("Content-Disposition:"))
|
||||
{
|
||||
if (line.contains("form-data"))
|
||||
@ -443,9 +454,9 @@ void HttpRequest::parseMultiPartFile()
|
||||
#endif
|
||||
QTemporaryFile* uploadedFile=nullptr;
|
||||
QByteArray fieldValue;
|
||||
while (!tempFile.atEnd() && !finished && !tempFile.error())
|
||||
while (!tempFile->atEnd() && !finished && !tempFile->error())
|
||||
{
|
||||
QByteArray line=tempFile.readLine(65536);
|
||||
QByteArray line=tempFile->readLine(65536);
|
||||
if (line.startsWith("--"+boundary))
|
||||
{
|
||||
// Boundary found. Until now we have collected 2 bytes too much,
|
||||
@ -471,7 +482,7 @@ void HttpRequest::parseMultiPartFile()
|
||||
parameters.insert(fieldName,fileName);
|
||||
qDebug("HttpRequest: set parameter %s=%s",fieldName.data(),fileName.data());
|
||||
uploadedFiles.insert(fieldName,uploadedFile);
|
||||
qDebug("HttpRequest: uploaded file size is %i",(int) uploadedFile->size());
|
||||
qDebug("HttpRequest: uploaded file size is %lli",uploadedFile->size());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -509,9 +520,9 @@ void HttpRequest::parseMultiPartFile()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tempFile.error())
|
||||
if (tempFile->error())
|
||||
{
|
||||
qCritical("HttpRequest: cannot read temp file, %s",qPrintable(tempFile.errorString()));
|
||||
qCritical("HttpRequest: cannot read temp file, %s",qPrintable(tempFile->errorString()));
|
||||
}
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpRequest: finished parsing multipart temp file");
|
||||
@ -523,9 +534,20 @@ HttpRequest::~HttpRequest()
|
||||
foreach(QByteArray key, uploadedFiles.keys())
|
||||
{
|
||||
QTemporaryFile* file=uploadedFiles.value(key);
|
||||
file->close();
|
||||
if (file->isOpen())
|
||||
{
|
||||
file->close();
|
||||
}
|
||||
delete file;
|
||||
}
|
||||
if (tempFile != nullptr)
|
||||
{
|
||||
if (tempFile->isOpen())
|
||||
{
|
||||
tempFile->close();
|
||||
}
|
||||
delete tempFile;
|
||||
}
|
||||
}
|
||||
|
||||
QTemporaryFile* HttpRequest::getUploadedFile(const QByteArray fieldName) const
|
||||
@ -553,3 +575,4 @@ QHostAddress HttpRequest::getPeerAddress() const
|
||||
{
|
||||
return peerAddress;
|
||||
}
|
||||
|
||||
|
||||
12
third_party/QtWebApp/httpserver/httprequest.h
vendored
12
third_party/QtWebApp/httpserver/httprequest.h
vendored
@ -16,6 +16,8 @@
|
||||
#include <QUuid>
|
||||
#include "httpglobal.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/**
|
||||
This object represents a single HTTP request. It reads the request
|
||||
from a TCP socket and provides getters for the individual parts
|
||||
@ -46,7 +48,7 @@ public:
|
||||
Constructor.
|
||||
@param settings Configuration settings
|
||||
*/
|
||||
HttpRequest(QSettings* settings);
|
||||
HttpRequest(const QSettings* settings);
|
||||
|
||||
/**
|
||||
Destructor.
|
||||
@ -59,7 +61,7 @@ public:
|
||||
until the status is RequestStatus::complete or RequestStatus::abort.
|
||||
@param socket Source of the data
|
||||
*/
|
||||
void readFromSocket(QTcpSocket* socket);
|
||||
void readFromSocket(QTcpSocket *socket);
|
||||
|
||||
/**
|
||||
Get the status of this reqeust.
|
||||
@ -207,9 +209,9 @@ private:
|
||||
QByteArray boundary;
|
||||
|
||||
/** Temp file, that is used to store the multipart/form-data body */
|
||||
QTemporaryFile tempFile;
|
||||
QTemporaryFile* tempFile;
|
||||
|
||||
/** Parset he multipart body, that has been stored in the temp file. */
|
||||
/** Parse the multipart body, that has been stored in the temp file. */
|
||||
void parseMultiPartFile();
|
||||
|
||||
/** Sub-procedure of readFromSocket(), read the first line of a request. */
|
||||
@ -232,4 +234,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // HTTPREQUEST_H
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
using namespace stefanfrings;
|
||||
|
||||
HttpRequestHandler::HttpRequestHandler(QObject* parent)
|
||||
: QObject(parent)
|
||||
{}
|
||||
|
||||
@ -10,6 +10,8 @@
|
||||
#include "httprequest.h"
|
||||
#include "httpresponse.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/**
|
||||
The request handler generates a response for each HTTP request. Web Applications
|
||||
usually have one central request handler that maps incoming requests to several
|
||||
@ -46,4 +48,6 @@ public:
|
||||
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // HTTPREQUESTHANDLER_H
|
||||
|
||||
@ -5,7 +5,9 @@
|
||||
|
||||
#include "httpresponse.h"
|
||||
|
||||
HttpResponse::HttpResponse(QTcpSocket* socket)
|
||||
using namespace stefanfrings;
|
||||
|
||||
HttpResponse::HttpResponse(QTcpSocket *socket)
|
||||
{
|
||||
this->socket=socket;
|
||||
statusCode=200;
|
||||
@ -67,6 +69,7 @@ void HttpResponse::writeHeaders()
|
||||
}
|
||||
buffer.append("\r\n");
|
||||
writeToSocket(buffer);
|
||||
socket->flush();
|
||||
sentHeaders=true;
|
||||
}
|
||||
|
||||
@ -82,7 +85,7 @@ bool HttpResponse::writeToSocket(QByteArray data)
|
||||
socket->waitForBytesWritten(-1);
|
||||
}
|
||||
|
||||
int written=socket->write(ptr,remaining);
|
||||
qint64 written=socket->write(ptr,remaining);
|
||||
if (written==-1)
|
||||
{
|
||||
return false;
|
||||
|
||||
14
third_party/QtWebApp/httpserver/httpresponse.h
vendored
14
third_party/QtWebApp/httpserver/httpresponse.h
vendored
@ -12,6 +12,8 @@
|
||||
#include "httpglobal.h"
|
||||
#include "httpcookie.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/**
|
||||
This object represents a HTTP response, used to return something to the web client.
|
||||
<p>
|
||||
@ -39,7 +41,7 @@ public:
|
||||
Constructor.
|
||||
@param socket used to write the response
|
||||
*/
|
||||
HttpResponse(QTcpSocket* socket);
|
||||
HttpResponse(QTcpSocket *socket);
|
||||
|
||||
/**
|
||||
Set a HTTP response header.
|
||||
@ -47,7 +49,7 @@ public:
|
||||
@param name name of the header
|
||||
@param value value of the header
|
||||
*/
|
||||
void setHeader(QByteArray name, QByteArray value);
|
||||
void setHeader(const QByteArray name, const QByteArray value);
|
||||
|
||||
/**
|
||||
Set a HTTP response header.
|
||||
@ -55,7 +57,7 @@ public:
|
||||
@param name name of the header
|
||||
@param value value of the header
|
||||
*/
|
||||
void setHeader(QByteArray name, int value);
|
||||
void setHeader(const QByteArray name, const int value);
|
||||
|
||||
/** Get the map of HTTP response headers */
|
||||
QMap<QByteArray,QByteArray>& getHeaders();
|
||||
@ -67,7 +69,7 @@ public:
|
||||
Set status code and description. The default is 200,OK.
|
||||
You must call this method before the first write().
|
||||
*/
|
||||
void setStatus(int statusCode, QByteArray description=QByteArray());
|
||||
void setStatus(const int statusCode, const QByteArray description=QByteArray());
|
||||
|
||||
/** Return the status code. */
|
||||
int getStatusCode() const;
|
||||
@ -85,7 +87,7 @@ public:
|
||||
@param data Data bytes of the body
|
||||
@param lastPart Indicates that this is the last chunk of data and flushes the output buffer.
|
||||
*/
|
||||
void write(QByteArray data, bool lastPart=false);
|
||||
void write(const QByteArray data, const bool lastPart=false);
|
||||
|
||||
/**
|
||||
Indicates whether the body has been sent completely (write() has been called with lastPart=true).
|
||||
@ -156,4 +158,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // HTTPRESPONSE_H
|
||||
|
||||
20
third_party/QtWebApp/httpserver/httpsession.cpp
vendored
20
third_party/QtWebApp/httpserver/httpsession.cpp
vendored
@ -7,6 +7,7 @@
|
||||
#include <QDateTime>
|
||||
#include <QUuid>
|
||||
|
||||
using namespace stefanfrings;
|
||||
|
||||
HttpSession::HttpSession(bool canStore)
|
||||
{
|
||||
@ -17,7 +18,7 @@ HttpSession::HttpSession(bool canStore)
|
||||
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
|
||||
dataPtr->id=QUuid::createUuid().toString().toLocal8Bit();
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpSession: created new session data with id %s",dataPtr->id.data());
|
||||
qDebug("HttpSession: (constructor) new session %s with refCount=1",dataPtr->id.constData());
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -34,7 +35,7 @@ HttpSession::HttpSession(const HttpSession& other)
|
||||
dataPtr->lock.lockForWrite();
|
||||
dataPtr->refCount++;
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount);
|
||||
qDebug("HttpSession: (constructor) copy session %s refCount=%i",dataPtr->id.constData(),dataPtr->refCount);
|
||||
#endif
|
||||
dataPtr->lock.unlock();
|
||||
}
|
||||
@ -49,7 +50,7 @@ HttpSession& HttpSession::operator= (const HttpSession& other)
|
||||
dataPtr->lock.lockForWrite();
|
||||
dataPtr->refCount++;
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount);
|
||||
qDebug("HttpSession: (operator=) session %s refCount=%i",dataPtr->id.constData(),dataPtr->refCount);
|
||||
#endif
|
||||
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
|
||||
dataPtr->lock.unlock();
|
||||
@ -57,14 +58,15 @@ HttpSession& HttpSession::operator= (const HttpSession& other)
|
||||
if (oldPtr)
|
||||
{
|
||||
int refCount;
|
||||
oldPtr->lock.lockForRead();
|
||||
refCount=oldPtr->refCount--;
|
||||
oldPtr->lock.lockForWrite();
|
||||
refCount=--oldPtr->refCount;
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpSession: refCount of %s is %i",oldPtr->id.data(),oldPtr->refCount);
|
||||
qDebug("HttpSession: (operator=) session %s refCount=%i",oldPtr->id.constData(),oldPtr->refCount);
|
||||
#endif
|
||||
oldPtr->lock.unlock();
|
||||
if (refCount==0)
|
||||
{
|
||||
qDebug("HttpSession: deleting old data");
|
||||
delete oldPtr;
|
||||
}
|
||||
}
|
||||
@ -75,10 +77,10 @@ HttpSession::~HttpSession()
|
||||
{
|
||||
if (dataPtr) {
|
||||
int refCount;
|
||||
dataPtr->lock.lockForRead();
|
||||
dataPtr->lock.lockForWrite();
|
||||
refCount=--dataPtr->refCount;
|
||||
#ifdef SUPERVERBOSE
|
||||
qDebug("HttpSession: refCount of %s is %i",dataPtr->id.data(),dataPtr->refCount);
|
||||
qDebug("HttpSession: (destructor) session %s refCount=%i",dataPtr->id.constData(),dataPtr->refCount);
|
||||
#endif
|
||||
dataPtr->lock.unlock();
|
||||
if (refCount==0)
|
||||
@ -179,7 +181,7 @@ void HttpSession::setLastAccess()
|
||||
{
|
||||
if (dataPtr)
|
||||
{
|
||||
dataPtr->lock.lockForRead();
|
||||
dataPtr->lock.lockForWrite();
|
||||
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
|
||||
dataPtr->lock.unlock();
|
||||
}
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
#include <QReadWriteLock>
|
||||
#include "httpglobal.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/**
|
||||
This class stores data for a single HTTP session.
|
||||
A session can store any number of key/value pairs. This class uses implicit
|
||||
@ -27,7 +29,7 @@ public:
|
||||
@param canStore The session can store data, if this parameter is true.
|
||||
Otherwise all calls to set() and remove() do not have any effect.
|
||||
*/
|
||||
HttpSession(bool canStore=false);
|
||||
HttpSession(const bool canStore=false);
|
||||
|
||||
/**
|
||||
Copy constructor. Creates another HttpSession object that shares the
|
||||
@ -115,4 +117,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // HTTPSESSION_H
|
||||
|
||||
@ -7,7 +7,9 @@
|
||||
#include <QDateTime>
|
||||
#include <QUuid>
|
||||
|
||||
HttpSessionStore::HttpSessionStore(QSettings* settings, QObject* parent)
|
||||
using namespace stefanfrings;
|
||||
|
||||
HttpSessionStore::HttpSessionStore(const QSettings *settings, QObject* parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
this->settings=settings;
|
||||
|
||||
@ -15,6 +15,8 @@
|
||||
#include "httpresponse.h"
|
||||
#include "httprequest.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/**
|
||||
Stores HTTP sessions and deletes them when they have expired.
|
||||
The following configuration settings are required in the config file:
|
||||
@ -35,8 +37,17 @@ class DECLSPEC HttpSessionStore : public QObject {
|
||||
Q_DISABLE_COPY(HttpSessionStore)
|
||||
public:
|
||||
|
||||
/** Constructor. */
|
||||
HttpSessionStore(QSettings* settings, QObject* parent=nullptr);
|
||||
/**
|
||||
Constructor.
|
||||
@param settings Configuration settings, usually stored in an INI file. Must not be 0.
|
||||
Settings are read from the current group, so the caller must have called settings->beginGroup().
|
||||
Because the group must not change during runtime, it is recommended to provide a
|
||||
separate QSettings instance that is not used by other parts of the program.
|
||||
The HttpSessionStore does not take over ownership of the QSettings instance, so the
|
||||
caller should destroy it during shutdown.
|
||||
@param parent Parent object
|
||||
*/
|
||||
HttpSessionStore(const QSettings* settings, QObject* parent=nullptr);
|
||||
|
||||
/** Destructor */
|
||||
virtual ~HttpSessionStore();
|
||||
@ -62,7 +73,7 @@ public:
|
||||
@return If autoCreate is disabled, the function returns a null session if there is no session.
|
||||
@see HttpSession::isNull()
|
||||
*/
|
||||
HttpSession getSession(HttpRequest& request, HttpResponse& response, bool allowCreate=true);
|
||||
HttpSession getSession(HttpRequest& request, HttpResponse& response, const bool allowCreate=true);
|
||||
|
||||
/**
|
||||
Get a HTTP session by it's ID number.
|
||||
@ -74,7 +85,7 @@ public:
|
||||
HttpSession getSession(const QByteArray id);
|
||||
|
||||
/** Delete a session */
|
||||
void removeSession(HttpSession session);
|
||||
void removeSession(const HttpSession session);
|
||||
|
||||
protected:
|
||||
/** Storage for the sessions */
|
||||
@ -83,7 +94,7 @@ protected:
|
||||
private:
|
||||
|
||||
/** Configuration settings */
|
||||
QSettings* settings;
|
||||
const QSettings* settings;
|
||||
|
||||
/** Timer to remove expired sessions */
|
||||
QTimer cleanupTimer;
|
||||
@ -103,4 +114,6 @@ private slots:
|
||||
void sessionTimerEvent();
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // HTTPSESSIONSTORE_H
|
||||
|
||||
@ -8,13 +8,9 @@
|
||||
#include <QDir>
|
||||
#include <QDateTime>
|
||||
|
||||
//YACReader-----
|
||||
#include "httpsession.h"
|
||||
#include "yacreader_http_session.h"
|
||||
#include "static.h"
|
||||
//--
|
||||
using namespace stefanfrings;
|
||||
|
||||
StaticFileController::StaticFileController(QSettings* settings, QObject* parent)
|
||||
StaticFileController::StaticFileController(const QSettings *settings, QObject* parent)
|
||||
:HttpRequestHandler(parent)
|
||||
{
|
||||
maxAge=settings->value("maxAge","60000").toInt();
|
||||
@ -41,7 +37,7 @@ StaticFileController::StaticFileController(QSettings* settings, QObject* parent)
|
||||
}
|
||||
|
||||
|
||||
void StaticFileController::service(HttpRequest& request, HttpResponse& response)
|
||||
void StaticFileController::service(HttpRequest &request, HttpResponse &response)
|
||||
{
|
||||
QByteArray path=request.getPath();
|
||||
// Check if we have the file in cache
|
||||
@ -61,32 +57,6 @@ void StaticFileController::service(HttpRequest& request, HttpResponse& response)
|
||||
else
|
||||
{
|
||||
mutex.unlock();
|
||||
|
||||
//TODO(DONE) carga sensible al dispositivo y a la localización
|
||||
QString stringPath = path;
|
||||
QStringList paths = QString(path).split('/');
|
||||
QString fileName = paths.last();
|
||||
stringPath.remove(fileName);
|
||||
HttpSession session=Static::sessionStore->getSession(request,response,false);
|
||||
YACReaderHttpSession *ySession = Static::yacreaderSessionStore->getYACReaderSessionHttpSession(session.getId());
|
||||
QString device = "ipad";
|
||||
QString display = "@2x";
|
||||
if (ySession != nullptr) {
|
||||
device = ySession->getDeviceType();
|
||||
display = ySession->getDisplayType();
|
||||
}
|
||||
|
||||
if(fileName.endsWith(".png"))
|
||||
fileName = getDeviceAwareFileName(fileName, device, display, request.getHeader("Accept-Language"), stringPath);
|
||||
else
|
||||
fileName = getDeviceAwareFileName(fileName, device, request.getHeader("Accept-Language"), stringPath);
|
||||
QString newPath = stringPath.append(fileName);
|
||||
path = newPath.toLocal8Bit();
|
||||
|
||||
//CAMBIADO
|
||||
//response.setHeader("Connection","close");
|
||||
//END_TODO
|
||||
|
||||
// The file is not in cache.
|
||||
qDebug("StaticFileController: Cache miss for %s",path.data());
|
||||
// Forbid access to files outside the docroot directory
|
||||
@ -151,7 +121,7 @@ void StaticFileController::service(HttpRequest& request, HttpResponse& response)
|
||||
}
|
||||
}
|
||||
|
||||
void StaticFileController::setContentType(QString fileName, HttpResponse& response) const
|
||||
void StaticFileController::setContentType(const QString fileName, HttpResponse &response) const
|
||||
{
|
||||
if (fileName.endsWith(".png"))
|
||||
{
|
||||
@ -209,85 +179,17 @@ void StaticFileController::setContentType(QString fileName, HttpResponse& respon
|
||||
{
|
||||
response.setHeader("Content-Type", "application/font-otf");
|
||||
}
|
||||
else if (fileName.endsWith(".json"))
|
||||
{
|
||||
response.setHeader("Content-Type", "application/json");
|
||||
}
|
||||
else if (fileName.endsWith(".xml"))
|
||||
{
|
||||
response.setHeader("Content-Type", "text/xml");
|
||||
}
|
||||
// Todo: add all of your content types
|
||||
else
|
||||
{
|
||||
qDebug("StaticFileController: unknown MIME type for filename '%s'", qPrintable(fileName));
|
||||
}
|
||||
}
|
||||
|
||||
//YACReader------------------------------------------------------------------------
|
||||
|
||||
bool StaticFileController::exists(QString localizedName, QString path) const
|
||||
{
|
||||
QString fileName=docroot+"/"+path + localizedName;
|
||||
QFile file(fileName);
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
//retorna fileName si no se encontró alternativa traducida ó fileName-locale.extensión si se encontró
|
||||
QString StaticFileController::getLocalizedFileName(QString fileName, QString locales, QString path) const
|
||||
{
|
||||
QSet<QString> tried; // used to suppress duplicate attempts
|
||||
QStringList locs=locales.split(',',QString::SkipEmptyParts);
|
||||
QStringList fileNameParts = fileName.split('.');
|
||||
QString file = fileNameParts.first();
|
||||
QString extension = fileNameParts.last();
|
||||
// Search for exact match
|
||||
foreach (QString loc,locs) {
|
||||
loc.replace(QRegExp(";.*"),"");
|
||||
loc.replace('-','_');
|
||||
QString localizedName=file+"-"+loc.trimmed()+"."+extension;
|
||||
if (!tried.contains(localizedName)) {
|
||||
if(exists(localizedName, path))
|
||||
return localizedName;
|
||||
tried.insert(localizedName);
|
||||
}
|
||||
}
|
||||
|
||||
// Search for correct language but any country
|
||||
foreach (QString loc,locs) {
|
||||
loc.replace(QRegExp("[;_-].*"),"");
|
||||
QString localizedName=file+"-"+loc.trimmed()+"."+extension;
|
||||
if (!tried.contains(localizedName)) {
|
||||
if(exists(localizedName, path))
|
||||
return localizedName;
|
||||
tried.insert(localizedName);
|
||||
}
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
QString StaticFileController::getDeviceAwareFileName(QString fileName, QString device, QString locales, QString path) const
|
||||
{
|
||||
QFileInfo fi(fileName);
|
||||
QString baseName = fi.baseName();
|
||||
QString extension = fi.completeSuffix();
|
||||
|
||||
QString completeFileName = getLocalizedFileName(baseName+"_"+device+"."+extension,locales,path);
|
||||
|
||||
if(QFile(docroot+"/"+path+completeFileName).exists())
|
||||
return completeFileName; //existe un archivo específico para este dispositivo y locales
|
||||
else
|
||||
return getLocalizedFileName(fileName,locales,path); //no hay archivo específico para el dispositivo, pero puede haberlo para estas locales
|
||||
}
|
||||
|
||||
QString StaticFileController::getDeviceAwareFileName(QString fileName, QString device, QString display, QString /* locales */, QString path) const
|
||||
{
|
||||
QFileInfo fi(fileName);
|
||||
QString baseName = fi.baseName();
|
||||
QString extension = fi.completeSuffix();
|
||||
|
||||
QString completeFileName = baseName+display+"."+extension;
|
||||
if(QFile(docroot+"/"+path+completeFileName).exists())
|
||||
return completeFileName;
|
||||
else
|
||||
{
|
||||
completeFileName = baseName+"_"+device+display+"."+extension;
|
||||
if((QFile(docroot+"/"+path+completeFileName).exists()))
|
||||
return completeFileName;
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
#include "httpresponse.h"
|
||||
#include "httprequesthandler.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/**
|
||||
Delivers static files. It is usually called by the applications main request handler when
|
||||
the caller requests a path that is mapped to static files.
|
||||
@ -45,11 +47,20 @@ class DECLSPEC StaticFileController : public HttpRequestHandler {
|
||||
Q_DISABLE_COPY(StaticFileController)
|
||||
public:
|
||||
|
||||
/** Constructor */
|
||||
StaticFileController(QSettings* settings, QObject* parent = nullptr);
|
||||
/**
|
||||
Constructor.
|
||||
@param settings Configuration settings, usually stored in an INI file. Must not be 0.
|
||||
Settings are read from the current group, so the caller must have called settings->beginGroup().
|
||||
Because the group must not change during runtime, it is recommended to provide a
|
||||
separate QSettings instance that is not used by other parts of the program.
|
||||
The StaticFileController does not take over ownership of the QSettings instance, so the
|
||||
caller should destroy it during shutdown.
|
||||
@param parent Parent object
|
||||
*/
|
||||
StaticFileController(const QSettings* settings, QObject* parent = nullptr);
|
||||
|
||||
/** Generates the response */
|
||||
void service(HttpRequest& request, HttpResponse& response) override;
|
||||
void service(HttpRequest& request, HttpResponse& response);
|
||||
|
||||
private:
|
||||
|
||||
@ -81,14 +92,9 @@ private:
|
||||
QMutex mutex;
|
||||
|
||||
/** Set a content-type header in the response depending on the ending of the filename */
|
||||
void setContentType(QString file, HttpResponse& response) const;
|
||||
|
||||
//YACReader------------------------------------------------------------------------
|
||||
QString getLocalizedFileName(QString fileName, QString locales, QString path) const;
|
||||
QString getDeviceAwareFileName(QString fileName, QString device, QString locales, QString path) const;
|
||||
QString getDeviceAwareFileName(QString fileName, QString device, QString display, QString locales, QString path) const;
|
||||
|
||||
bool exists(QString localizedName, QString path) const;
|
||||
void setContentType(const QString file, HttpResponse &response) const;
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // STATICFILECONTROLLER_H
|
||||
|
||||
Reference in New Issue
Block a user