mirror of
https://github.com/YACReader/yacreader
synced 2025-07-17 20:44:32 -04:00
Update QtWebapp to 1.7.11
This commit is contained in:
290
third_party/QtWebApp/CHANGELOG.txt
vendored
Normal file
290
third_party/QtWebApp/CHANGELOG.txt
vendored
Normal file
@ -0,0 +1,290 @@
|
||||
Dont forget to update the release number also in
|
||||
QtWebApp.pro and httpserver/httpglobal.cpp.
|
||||
|
||||
1.7.11
|
||||
28.12.2019
|
||||
Fix Http Headers are not properly received if the two characters of
|
||||
a line-break (\r\n) were not received together in the same ethernet
|
||||
package.
|
||||
|
||||
1.7.10
|
||||
04.12.2019
|
||||
Add support for other SSL implementations than OpenSSL (as far Qt supports it).
|
||||
Fix log bufffer was triggered only by severities above minLevel (should be "at least" minLevel).
|
||||
|
||||
1.7.9
|
||||
20.06.2019
|
||||
INFO messages do not trigger writing out buffered log messages anymore when
|
||||
bufferSize>0 and minLevel>0.
|
||||
|
||||
1.7.8
|
||||
05.02.2019
|
||||
HttpConnectionHandler closes the socket now in the thread of the socket.
|
||||
Headers and Body sent to the browser are now separated into individual ethernet packets.
|
||||
|
||||
1.7.7
|
||||
04.02.2019
|
||||
HttpConnectionHandler creates a new Qthread instead of being itself a QThread.
|
||||
Improved formatting of thread ID in logger.
|
||||
|
||||
1.7.6
|
||||
18.01.2019
|
||||
Code cleanup with const keywords and type conversions.
|
||||
Update Documentation.
|
||||
|
||||
1.7.5
|
||||
17.01.2019
|
||||
Added content-types for *.xml and *.json to the StaticFileController.
|
||||
Fixed locking and memory leak in HttpSession.
|
||||
|
||||
1.7.4
|
||||
24.05.2018
|
||||
Fixed two possible null-pointer references in case of broken HTTP requests.
|
||||
|
||||
1.7.3
|
||||
25.04.2017
|
||||
Wait until all data are sent before closing connections.
|
||||
|
||||
1.7.2
|
||||
17.01.2017
|
||||
Fixed compile error with MSVC.
|
||||
|
||||
1.7.1
|
||||
10.11.2016
|
||||
Fixed a possible memory leak in case of broken Multipart HTTP Requests.
|
||||
|
||||
1.7.0
|
||||
08.11.2016
|
||||
Introduced namespace "stefanfrings".
|
||||
Improved performance a little.
|
||||
|
||||
1.6.7
|
||||
10.10.2016
|
||||
Fix type of socketDescriptor in qtservice library.
|
||||
Add support for INFO log messages (new since QT 5.5).
|
||||
Improve indentation of log messages.
|
||||
|
||||
1.6.6
|
||||
25.07.2016
|
||||
Removed useless mutex from TemplateLoader.
|
||||
Add mutex to TemplateCache (which is now needed).
|
||||
|
||||
1.6.5
|
||||
10.06.2016
|
||||
Incoming HTTP request headers are now processed case-insensitive.
|
||||
Add support for the HttpOnly flag of cookies.
|
||||
|
||||
1.6.4
|
||||
27.03.2016
|
||||
Fixed constructor of Template class did not load the source file properly.
|
||||
Template loader and cache were not affected.
|
||||
|
||||
1.6.3
|
||||
11.03.2016
|
||||
Fixed compilation error.
|
||||
Added missing implementation of HttpRequest::getPeerAddress().
|
||||
|
||||
1.6.2
|
||||
06.03.2016
|
||||
Added mime types for some file extensions.
|
||||
|
||||
1.6.1
|
||||
25.01.2016
|
||||
Fixed parser of boundary value in multi-part request, which caused that
|
||||
QHttpMultipart did not work on client side.
|
||||
|
||||
1.6.0
|
||||
29.12.2015
|
||||
Much better output buffering, reduces the number of small IP packages.
|
||||
|
||||
1.5.13
|
||||
29.12.2015
|
||||
Improved performance a little.
|
||||
Add support for old HTTP 1.0 clients.
|
||||
Add HttpResposne::flush() and HttpResponse::isConnected() which are helpful to support
|
||||
SSE from HTML 5 specification.
|
||||
|
||||
1.5.12
|
||||
11.12.2015
|
||||
Fix program crash when using SSL with a variable sized thread pool on Windows.
|
||||
Changed name of HttpSessionStore::timerEvent() to fix compiler warnings since Qt 5.0.
|
||||
Add HttpRequest::getRawPath().
|
||||
HttpSessionStore::sessions is now protected.
|
||||
|
||||
1.5.11
|
||||
21.11.2015
|
||||
Fix project file for Mac OS.
|
||||
Add HttpRequest::getPeerAddress() and HttpResponse::getStatusCode().
|
||||
|
||||
1.5.10
|
||||
01.09.2015
|
||||
Modified StaticFileController to support ressource files (path starting with ":/" or "qrc://").
|
||||
|
||||
1.5.9
|
||||
06.08.2015
|
||||
New HttpListener::listen() method, to restart listening after close.
|
||||
Add missing include for QObject in logger.h.
|
||||
Add a call to flush() before closing connections, which solves an issue with nginx.
|
||||
|
||||
1.5.8
|
||||
26.07.2015
|
||||
Fixed segmentation fault error when closing the application while a HTTP request is in progress.
|
||||
New HttpListener::close() method to simplifly proper shutdown.
|
||||
|
||||
1.5.7
|
||||
20.07.2015
|
||||
Fix Qt 5.5 compatibility issue.
|
||||
|
||||
1.5.6
|
||||
22.06.2015
|
||||
Fixed compilation failes if QT does not support SSL.
|
||||
|
||||
1.5.5
|
||||
16.06.2015
|
||||
Improved performance of SSL connections.
|
||||
|
||||
1.5.4
|
||||
15.06.2015
|
||||
Support for Qt versions without OpenSsl.
|
||||
|
||||
1.5.3
|
||||
22.05.2015
|
||||
Fixed Windows issue: QsslSocket cannot be closed from other threads than it was created in.
|
||||
|
||||
1.5.2
|
||||
12.05.2015
|
||||
Fixed Windows issue: QSslSocket cannot send signals to another thread than it was created in.
|
||||
|
||||
1.5.1
|
||||
14.04.2015
|
||||
Add support for pipelining.
|
||||
|
||||
1.5.0
|
||||
03.04.2015
|
||||
Add support for HTTPS.
|
||||
|
||||
1.4.2
|
||||
03.04.2015
|
||||
Fixed HTTP request did not work if it was split into multipe IP packages.
|
||||
|
||||
1.4.1
|
||||
20.03.2015
|
||||
Fixed session cookie expires while the user is active, expiration time was not prolonged on each request.
|
||||
|
||||
1.4.0
|
||||
14.03.2015
|
||||
This release has a new directory structure and new project files to support the creation of a shared library (*.dll or *.so).
|
||||
|
||||
1.3.8
|
||||
12.03.2015
|
||||
Improved shutdown procedure.
|
||||
New config setting "host" which binds the listener to a specific network interface.
|
||||
|
||||
1.3.7
|
||||
14.01.2015
|
||||
Fixed setting maxMultiPartSize worked only with file-uploads but not with form-data.
|
||||
|
||||
1.3.6
|
||||
16.09.2014
|
||||
Fixed DualFileLogger produces no output.
|
||||
|
||||
1.3.5
|
||||
11.06.2014
|
||||
Fixed a multi-threading issue with race condition in StaticFileController.
|
||||
|
||||
1.3.4
|
||||
04.06.2014
|
||||
Fixed wrong content type when the StaticFileController returns a cached index.html.
|
||||
|
||||
1.3.3
|
||||
17.03.2014
|
||||
Improved security of StaticFileController by denying "/.." in any position of the request path.
|
||||
Improved performance of StaticFileController a little.
|
||||
New convenience method HttpResponse::redirect(url).
|
||||
Fixed a missing return statement in StaticFileController.
|
||||
|
||||
1.3.2
|
||||
08.01.2014
|
||||
Fixed HTTP Server ignoring URL parameters when the request contains POST parameters.
|
||||
|
||||
1.3.1
|
||||
15.08.2013
|
||||
Fixed HTTP server not accepting connections on 64bit OS with QT 5.
|
||||
|
||||
1.3.0
|
||||
20.04.2013
|
||||
Updated for compatibility QT 5. You may still use QT 4.7 or 4.8, if you like.
|
||||
Also added support for logging source file name, line number and function name.
|
||||
|
||||
1.2.13
|
||||
03.03.2013
|
||||
Fixed Logger writing wrong timestamp for buffered messages.
|
||||
Improved shutdown procedure. The webserver now processes all final signals before the destructor finishes.
|
||||
|
||||
1.2.12
|
||||
01.03.2013
|
||||
Fixed HttpResponse sending first part of data repeatedly when the amount of data is larger than the available memory for I/O buffer.
|
||||
|
||||
1.2.11
|
||||
06.01.2013
|
||||
Added clearing the write buffer when accepting a new connection, so that it does not send remaining data from an aborted previous connection (which is possibly a bug in QT).
|
||||
|
||||
1.2.10
|
||||
18.12.2012
|
||||
Reduced memory usage of HttpResponse in case of large response.
|
||||
|
||||
1.2.9
|
||||
29.07.2012
|
||||
Added a mutex to HttpConnectionHandlerPool to fix a concurrency issue when a pooled object gets taken from the cache while it times out.
|
||||
Modified HttpConnectionHandler so that it does not throw an exception anymore when a connection gets closed by the peer in the middle of a read.
|
||||
|
||||
1.2.8
|
||||
22.07.2012
|
||||
Fixed a possible concurrency issue when the file cache is so small that it stores less files than the number of threads.
|
||||
|
||||
1.2.7
|
||||
18.07.2012
|
||||
Fixed HttpRequest ignores additional URL parameters of POST requests.
|
||||
Fixed HttpRequest ignores POST parameters of body if there is no Content-Type header.
|
||||
Removed unused tempdir variable from HttpRequest.
|
||||
Added mutex to cache of StaticFileController to prevent concurrency problems.
|
||||
Removed HTTP response with status 408 after read timeout. Connection gets simply closed now.
|
||||
|
||||
1.2.6
|
||||
29.06.2012
|
||||
Fixed a compilation error on 64 bit if super verbose debugging is enabled.
|
||||
Fixed a typo in static file controller related to the document type header.
|
||||
|
||||
1.2.5
|
||||
27.06.2012
|
||||
Fixed error message "QThread: Destroyed while thread is still running" during program termination.
|
||||
|
||||
1.2.4
|
||||
02.06.2012
|
||||
Fixed template engine skipping variable tokens when a value is shorter than the token.
|
||||
|
||||
1.2.3
|
||||
26.12.2011
|
||||
Fixed null pointer error when the HTTP server aborts a request that is too large.
|
||||
|
||||
1.2.2
|
||||
06.11.2011
|
||||
Fixed compilation error on 64 bit platforms.
|
||||
|
||||
1.2.1
|
||||
22.10.2011
|
||||
Fixed a multi-threading bug in HttpConnectionHandler.
|
||||
|
||||
1.2.0
|
||||
05.12.2010
|
||||
Added a controller that serves static files, with cacheing.
|
||||
|
||||
|
||||
1.1.0
|
||||
19.10.2010
|
||||
Added support for sessions.
|
||||
Separated the base classes into individual libraries.
|
||||
|
||||
1.0.0
|
||||
17.10.2010
|
||||
First release
|
165
third_party/QtWebApp/LICENSE.txt
vendored
Normal file
165
third_party/QtWebApp/LICENSE.txt
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
25
third_party/QtWebApp/README.txt
vendored
Normal file
25
third_party/QtWebApp/README.txt
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
QtWebAppLib is a library to develop server-side web applications in C++.
|
||||
It requires the Qt SDK version 4.7.0 or newer.
|
||||
|
||||
License: LGPL v3.
|
||||
|
||||
Project homepage: http://stefanfrings.de/qtwebapp/index.html
|
||||
Tutorial: http://stefanfrings.de/qtwebapp/tutorial/index.html
|
||||
API doc: http://stefanfrings.de/qtwebapp/api/index.html
|
||||
|
||||
There are three demo applications that demonstrate how to use the library.
|
||||
|
||||
Demo1 shows how to use the library by including the source code into your
|
||||
project. This does not depend on the shared library.
|
||||
|
||||
Demo2 shows how to link against the shared library.
|
||||
Build the project QtWebApp to generate the shared library.
|
||||
|
||||
Demo3 shows how to use the qtservice component to start the application
|
||||
as a Windows Service or Unix daemon. Start it with option -h to get help.
|
||||
|
||||
I recommend to include the library by source as shown in Demo1 and 3.
|
||||
|
||||
Stefan Frings
|
||||
http://stefanfrings.de
|
||||
|
@ -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;
|
||||
|
||||
// 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);
|
||||
|
||||
// Create TCP or SSL socket
|
||||
createSocket();
|
||||
|
||||
// execute signals in my own thread
|
||||
moveToThread(this);
|
||||
socket->moveToThread(this);
|
||||
readTimer.moveToThread(this);
|
||||
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
|
||||
|
83
third_party/QtWebApp/httpserver/httprequest.cpp
vendored
83
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
@ -207,7 +209,7 @@ private:
|
||||
QByteArray boundary;
|
||||
|
||||
/** Temp file, that is used to store the multipart/form-data body */
|
||||
QTemporaryFile tempFile;
|
||||
QTemporaryFile* tempFile;
|
||||
|
||||
/** Parse the multipart body, that has been stored in the temp file. */
|
||||
void parseMultiPartFile();
|
||||
@ -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,6 +5,8 @@
|
||||
|
||||
#include "httpresponse.h"
|
||||
|
||||
using namespace stefanfrings;
|
||||
|
||||
HttpResponse::HttpResponse(QTcpSocket *socket)
|
||||
{
|
||||
this->socket=socket;
|
||||
@ -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;
|
||||
|
12
third_party/QtWebApp/httpserver/httpresponse.h
vendored
12
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>
|
||||
@ -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();
|
||||
@ -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
|
||||
|
14
third_party/QtWebApp/templateengine/template.cpp
vendored
14
third_party/QtWebApp/templateengine/template.cpp
vendored
@ -6,14 +6,16 @@
|
||||
#include "template.h"
|
||||
#include <QFileInfo>
|
||||
|
||||
Template::Template(QString source, QString sourceName)
|
||||
using namespace stefanfrings;
|
||||
|
||||
Template::Template(const QString source, const QString sourceName)
|
||||
: QString(source)
|
||||
{
|
||||
this->sourceName=sourceName;
|
||||
this->warnings=false;
|
||||
}
|
||||
|
||||
Template::Template(QFile& file, QTextCodec* textCodec)
|
||||
Template::Template(QFile& file, const QTextCodec* textCodec)
|
||||
{
|
||||
this->warnings=false;
|
||||
sourceName=QFileInfo(file.fileName()).baseName();
|
||||
@ -34,7 +36,7 @@ Template::Template(QFile& file, QTextCodec* textCodec)
|
||||
}
|
||||
|
||||
|
||||
int Template::setVariable(QString name, QString value)
|
||||
int Template::setVariable(const QString name, const QString value)
|
||||
{
|
||||
int count=0;
|
||||
QString variable="{"+name+"}";
|
||||
@ -52,7 +54,7 @@ int Template::setVariable(QString name, QString value)
|
||||
return count;
|
||||
}
|
||||
|
||||
int Template::setCondition(QString name, bool value)
|
||||
int Template::setCondition(const QString name, const bool value)
|
||||
{
|
||||
int count=0;
|
||||
QString startTag=QString("{if %1}").arg(name);
|
||||
@ -150,7 +152,7 @@ int Template::setCondition(QString name, bool value)
|
||||
return count;
|
||||
}
|
||||
|
||||
int Template::loop(QString name, int repetitions)
|
||||
int Template::loop(const QString name, const int repetitions)
|
||||
{
|
||||
Q_ASSERT(repetitions>=0);
|
||||
int count=0;
|
||||
@ -234,7 +236,7 @@ int Template::loop(QString name, int repetitions)
|
||||
return count;
|
||||
}
|
||||
|
||||
void Template::enableWarnings(bool enable)
|
||||
void Template::enableWarnings(const bool enable)
|
||||
{
|
||||
warnings=enable;
|
||||
}
|
||||
|
24
third_party/QtWebApp/templateengine/template.h
vendored
24
third_party/QtWebApp/templateengine/template.h
vendored
@ -14,6 +14,8 @@
|
||||
#include <QString>
|
||||
#include "templateglobal.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/**
|
||||
Enhanced version of QString for template processing. Templates
|
||||
are usually loaded from files, but may also be loaded from
|
||||
@ -41,10 +43,10 @@
|
||||
t.setVariable("username", "Stefan");
|
||||
t.setCondition("locked",false);
|
||||
t.loop("user",2);
|
||||
t.setVariable("user0.name,"Markus");
|
||||
t.setVariable("user0.time,"8:30");
|
||||
t.setVariable("user1.name,"Roland");
|
||||
t.setVariable("user1.time,"8:45");
|
||||
t.setVariable("user0.name","Markus");
|
||||
t.setVariable("user0.time","8:30");
|
||||
t.setVariable("user1.name","Roland");
|
||||
t.setVariable("user1.time","8:45");
|
||||
</pre></code></p>
|
||||
<p>
|
||||
The code example above shows how variable within loops are numbered.
|
||||
@ -95,7 +97,7 @@ public:
|
||||
@param source The template source text
|
||||
@param sourceName Name of the source file, used for logging
|
||||
*/
|
||||
Template(QString source, QString sourceName);
|
||||
Template(const QString source, const QString sourceName);
|
||||
|
||||
/**
|
||||
Constructor that reads the template from a file. Note that this class does not
|
||||
@ -106,7 +108,7 @@ public:
|
||||
@see TemplateLoader
|
||||
@see TemplateCache
|
||||
*/
|
||||
Template(QFile& file, QTextCodec* textCodec);
|
||||
Template(QFile &file, const QTextCodec* textCodec);
|
||||
|
||||
/**
|
||||
Replace a variable by the given value.
|
||||
@ -121,7 +123,7 @@ public:
|
||||
@param value new value
|
||||
@return The count of variables that have been processed
|
||||
*/
|
||||
int setVariable(QString name, QString value);
|
||||
int setVariable(const QString name, const QString value);
|
||||
|
||||
/**
|
||||
Set a condition. This affects tags with the syntax
|
||||
@ -135,7 +137,7 @@ public:
|
||||
@param value Value of the condition
|
||||
@return The count of conditions that have been processed
|
||||
*/
|
||||
int setCondition(QString name, bool value);
|
||||
int setCondition(const QString name, bool value);
|
||||
|
||||
/**
|
||||
Set number of repetitions of a loop.
|
||||
@ -148,13 +150,13 @@ public:
|
||||
@param repetitions The number of repetitions
|
||||
@return The number of loops that have been processed
|
||||
*/
|
||||
int loop(QString name, int repetitions);
|
||||
int loop(QString name, const int repetitions);
|
||||
|
||||
/**
|
||||
Enable warnings for missing tags
|
||||
@param enable Warnings are enabled, if true
|
||||
*/
|
||||
void enableWarnings(bool enable=true);
|
||||
void enableWarnings(const bool enable=true);
|
||||
|
||||
private:
|
||||
|
||||
@ -165,4 +167,6 @@ private:
|
||||
bool warnings;
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // TEMPLATE_H
|
||||
|
@ -3,7 +3,9 @@
|
||||
#include <QStringList>
|
||||
#include <QSet>
|
||||
|
||||
TemplateCache::TemplateCache(QSettings* settings, QObject* parent)
|
||||
using namespace stefanfrings;
|
||||
|
||||
TemplateCache::TemplateCache(const QSettings* settings, QObject* parent)
|
||||
:TemplateLoader(settings,parent)
|
||||
{
|
||||
cache.setMaxCost(settings->value("cacheSize","1000000").toInt());
|
||||
@ -11,14 +13,16 @@ TemplateCache::TemplateCache(QSettings* settings, QObject* parent)
|
||||
qDebug("TemplateCache: timeout=%i, size=%i",cacheTimeout,cache.maxCost());
|
||||
}
|
||||
|
||||
QString TemplateCache::tryFile(QString localizedName)
|
||||
QString TemplateCache::tryFile(const QString localizedName)
|
||||
{
|
||||
qint64 now=QDateTime::currentMSecsSinceEpoch();
|
||||
mutex.lock();
|
||||
// search in cache
|
||||
qDebug("TemplateCache: trying cached %s",qPrintable(localizedName));
|
||||
CacheEntry* entry=cache.object(localizedName);
|
||||
if (entry && (cacheTimeout==0 || entry->created>now-cacheTimeout))
|
||||
{
|
||||
mutex.unlock();
|
||||
return entry->document;
|
||||
}
|
||||
// search on filesystem
|
||||
@ -27,6 +31,7 @@ QString TemplateCache::tryFile(QString localizedName)
|
||||
entry->document=TemplateLoader::tryFile(localizedName);
|
||||
// Store in cache even when the file did not exist, to remember that there is no such file
|
||||
cache.insert(localizedName,entry,entry->document.size());
|
||||
mutex.unlock();
|
||||
return entry->document;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include "templateglobal.h"
|
||||
#include "templateloader.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/**
|
||||
Caching template loader, reduces the amount of I/O and improves performance
|
||||
on remote file systems. The cache has a limited size, it prefers to keep
|
||||
@ -46,10 +48,15 @@ public:
|
||||
|
||||
/**
|
||||
Constructor.
|
||||
@param settings configurations settings
|
||||
@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 TemplateCache does not take over ownership of the QSettings instance, so the caller
|
||||
should destroy it during shutdown.
|
||||
@param parent Parent object
|
||||
*/
|
||||
TemplateCache(QSettings* settings, QObject* parent=nullptr);
|
||||
TemplateCache(const QSettings* settings, QObject* parent=nullptr);
|
||||
|
||||
protected:
|
||||
|
||||
@ -58,7 +65,7 @@ protected:
|
||||
@param localizedName Name of the template with locale to find
|
||||
@return The template document, or empty string if not found
|
||||
*/
|
||||
virtual QString tryFile(QString localizedName);
|
||||
virtual QString tryFile(const QString localizedName);
|
||||
|
||||
private:
|
||||
|
||||
@ -73,6 +80,10 @@ private:
|
||||
/** Cache storage */
|
||||
QCache<QString,CacheEntry> cache;
|
||||
|
||||
/** Used to synchronize threads */
|
||||
QMutex mutex;
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // TEMPLATECACHE_H
|
||||
|
@ -10,7 +10,9 @@
|
||||
#include <QDir>
|
||||
#include <QSet>
|
||||
|
||||
TemplateLoader::TemplateLoader(QSettings* settings, QObject* parent)
|
||||
using namespace stefanfrings;
|
||||
|
||||
TemplateLoader::TemplateLoader(const QSettings *settings, QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
templatePath=settings->value("path",".").toString();
|
||||
@ -64,7 +66,6 @@ QString TemplateLoader::tryFile(QString localizedName)
|
||||
|
||||
Template TemplateLoader::getTemplate(QString templateName, QString locales)
|
||||
{
|
||||
mutex.lock();
|
||||
QSet<QString> tried; // used to suppress duplicate attempts
|
||||
QStringList locs=locales.split(',',QString::SkipEmptyParts);
|
||||
|
||||
@ -78,7 +79,6 @@ Template TemplateLoader::getTemplate(QString templateName, QString locales)
|
||||
{
|
||||
QString document=tryFile(localizedName);
|
||||
if (!document.isEmpty()) {
|
||||
mutex.unlock();
|
||||
return Template(document,localizedName);
|
||||
}
|
||||
tried.insert(localizedName);
|
||||
@ -95,7 +95,6 @@ Template TemplateLoader::getTemplate(QString templateName, QString locales)
|
||||
QString document=tryFile(localizedName);
|
||||
if (!document.isEmpty())
|
||||
{
|
||||
mutex.unlock();
|
||||
return Template(document,localizedName);
|
||||
}
|
||||
tried.insert(localizedName);
|
||||
@ -106,11 +105,9 @@ Template TemplateLoader::getTemplate(QString templateName, QString locales)
|
||||
QString document=tryFile(templateName);
|
||||
if (!document.isEmpty())
|
||||
{
|
||||
mutex.unlock();
|
||||
return Template(document,templateName);
|
||||
}
|
||||
|
||||
qCritical("TemplateCache: cannot find template %s",qPrintable(templateName));
|
||||
mutex.unlock();
|
||||
return Template("",templateName);
|
||||
}
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "templateglobal.h"
|
||||
#include "template.h"
|
||||
|
||||
namespace stefanfrings {
|
||||
|
||||
/**
|
||||
Loads localized versions of template files. If the caller requests a file with the
|
||||
name "index" and the suffix is ".tpl" and the requested locale is "de_DE, de, en-US",
|
||||
@ -45,7 +47,7 @@ public:
|
||||
@param settings configurations settings
|
||||
@param parent parent object
|
||||
*/
|
||||
TemplateLoader(QSettings* settings, QObject* parent=nullptr);
|
||||
TemplateLoader(const QSettings* settings, QObject* parent=nullptr);
|
||||
|
||||
/** Destructor */
|
||||
virtual ~TemplateLoader();
|
||||
@ -59,7 +61,7 @@ public:
|
||||
ignored.
|
||||
@return If the template cannot be loaded, an error message is logged and an empty template is returned.
|
||||
*/
|
||||
Template getTemplate(QString templateName, QString locales=QString());
|
||||
Template getTemplate(const QString templateName, const QString locales=QString());
|
||||
|
||||
protected:
|
||||
|
||||
@ -68,7 +70,7 @@ protected:
|
||||
@param localizedName Name of the template with locale to find
|
||||
@return The template document, or empty string if not found
|
||||
*/
|
||||
virtual QString tryFile(QString localizedName);
|
||||
virtual QString tryFile(const QString localizedName);
|
||||
|
||||
/** Directory where the templates are searched */
|
||||
QString templatePath;
|
||||
@ -78,9 +80,8 @@ protected:
|
||||
|
||||
/** Codec for decoding the files */
|
||||
QTextCodec* textCodec;
|
||||
|
||||
/** Used to synchronize threads */
|
||||
QMutex mutex;
|
||||
};
|
||||
|
||||
} // end of namespace
|
||||
|
||||
#endif // TEMPLATELOADER_H
|
||||
|
Reference in New Issue
Block a user