integrada la nueva versi?n de qtwebapp

This commit is contained in:
Luis Ángel San Martín 2012-09-09 15:41:34 +02:00
parent a39cc616f6
commit d123df4f53
15 changed files with 89 additions and 74 deletions

View File

@ -16,7 +16,7 @@ HttpConnectionHandler::HttpConnectionHandler(QSettings* settings, HttpRequestHan
this->settings=settings;
this->requestHandler=requestHandler;
currentRequest=0;
busy = false; // pdiener: it is not busy if it is new
busy = false;
// execute signals in my own thread
moveToThread(this);
socket.moveToThread(this);
@ -60,13 +60,14 @@ void HttpConnectionHandler::handleConnection(int socketDescriptor) {
// Start timer for read timeout
int readTimeout=settings->value("readTimeout",10000).toInt();
readTimer.start(readTimeout);
// delete previous request
delete currentRequest;
currentRequest=0;
}
bool HttpConnectionHandler::isBusy() {
//return socket.isOpen();
return busy; // pdiener: changed this from socket readout to bool variable
return busy;
}
void HttpConnectionHandler::setBusy() {
@ -76,7 +77,10 @@ void HttpConnectionHandler::setBusy() {
void HttpConnectionHandler::readTimeout() {
qDebug("HttpConnectionHandler (%p): read timeout occured",this);
socket.write("HTTP/1.1 408 request timeout\r\nConnection: close\r\n\r\n408 request timeout\r\n");
//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.disconnectFromHost();
delete currentRequest;
currentRequest=0;
@ -86,15 +90,13 @@ void HttpConnectionHandler::readTimeout() {
void HttpConnectionHandler::disconnected() {
qDebug("HttpConnectionHandler (%p): disconnected", this);
socket.close();
delete currentRequest;
currentRequest=0;
readTimer.stop();
busy = false; // pdiener: now we have finished
busy = false;
}
void HttpConnectionHandler::read() {
#ifdef SUPERVERBOSE
qDebug("HttpConnectionHandler (%x): read input",(unsigned int) this);
qDebug("HttpConnectionHandler (%p): read input",this);
#endif
// Create new HttpRequest object if necessary

View File

@ -44,15 +44,12 @@ public:
/** Destructor */
virtual ~HttpConnectionHandler();
/** Returns true, if this handler is busy */
/** Returns true, if this handler is in use. */
bool isBusy();
/** Mark this handler as busy */
void setBusy();
/** This shows the busy-state from a very early time */
bool busy;
private:
/** Configuration settings */
@ -70,6 +67,9 @@ private:
/** Dispatches received requests to services */
HttpRequestHandler* requestHandler;
/** This shows the busy-state from a very early time */
bool busy;
/** Executes the htreads own event loop */
void run();

View File

@ -13,27 +13,33 @@ HttpConnectionHandlerPool::HttpConnectionHandlerPool(QSettings* settings, HttpRe
HttpConnectionHandlerPool::~HttpConnectionHandlerPool() {
foreach(HttpConnectionHandler* handler, pool) {
delete handler;
connect(handler,SIGNAL(finished()),handler,SLOT(deleteLater()));
handler->quit();
}
}
HttpConnectionHandler* HttpConnectionHandlerPool::getConnectionHandler() {
HttpConnectionHandler* HttpConnectionHandlerPool::getConnectionHandler() {
HttpConnectionHandler* freeHandler=0;
mutex.lock();
// find a free handler in pool
foreach(HttpConnectionHandler* handler, pool) {
if (!handler->isBusy()) {
freeHandler=handler;
freeHandler->setBusy();
break;
}
}
// create a new handler, if necessary
if (!freeHandler) {
//CAMBIADO
int maxConnectionHandlers= 100;//settings->value("maxThreads",10).toInt();
int maxConnectionHandlers=settings->value("maxThreads",100).toInt();
if (pool.count()<maxConnectionHandlers) {
freeHandler=new HttpConnectionHandler(settings,requestHandler);
freeHandler->setBusy();
pool.append(freeHandler);
}
}
if (freeHandler) freeHandler->busy = true; // pdiener: set it to busy-state immediately
mutex.unlock();
return freeHandler;
}
@ -42,6 +48,7 @@ HttpConnectionHandler* HttpConnectionHandlerPool::getConnectionHandler() {
void HttpConnectionHandlerPool::cleanup() {
int maxIdleHandlers=settings->value("minThreads",1).toInt();
int idleCounter=0;
mutex.lock();
foreach(HttpConnectionHandler* handler, pool) {
if (!handler->isBusy()) {
if (++idleCounter > maxIdleHandlers) {
@ -53,4 +60,5 @@ void HttpConnectionHandlerPool::cleanup() {
}
}
}
mutex.unlock();
}

View File

@ -4,6 +4,7 @@
#include <QList>
#include <QTimer>
#include <QObject>
#include <QMutex>
#include "httpconnectionhandler.h"
/**
@ -13,14 +14,14 @@
Example for the required configuration settings:
<code><pre>
minThreads=1
maxThreads=10
maxThreads=100
cleanupInterval=1000
maxRequestSize=16000
maxMultiPartSize=1000000
</pre></code>
The pool is empty initially and grows with the number of concurrent
connections. A timer removes one idle connection handler at each
interval, but a it leaves some spare handlers in memory to improve
interval, but it leaves some spare handlers in memory to improve
performance.
@see HttpConnectionHandler for description of config settings readTimeout
@see HttpRequest for description of config settings maxRequestSize and maxMultiPartSize
@ -59,6 +60,9 @@ private:
/** Timer to clean-up unused connection handler */
QTimer cleanupTimer;
/** Used to synchronize threads */
QMutex mutex;
private slots:
/** Received from the clean-up timer. */

View File

@ -50,7 +50,6 @@ void HttpListener::incomingConnection(int socketDescriptor) {
QTcpSocket* socket=new QTcpSocket(this);
socket->setSocketDescriptor(socketDescriptor);
connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
//CAMBIADO 503 por 429
socket->write("HTTP/1.1 503 too many connections\r\nConnection: close\r\n\r\nToo many connections\r\n");
socket->disconnectFromHost();
}

View File

@ -14,17 +14,6 @@ HttpRequest::HttpRequest(QSettings* settings) {
expectedBodySize=0;
maxSize=settings->value("maxRequestSize","16000").toInt();
maxMultiPartSize=settings->value("maxMultiPartSize","1000000").toInt();
// Convert relative path to absolute, based on the directory of the config file.
#ifdef Q_OS_WIN32
if (QDir::isRelativePath(tempDir) && settings->format()!=QSettings::NativeFormat)
#else
if (QDir::isRelativePath(tempDir))
#endif
{
QFileInfo configFile(settings->fileName());
tempDir=QFileInfo(configFile.absolutePath(),tempDir).absoluteFilePath();
}
}
void HttpRequest::readRequest(QTcpSocket& socket) {
@ -170,15 +159,22 @@ void HttpRequest::decodeRequestParams() {
#ifdef SUPERVERBOSE
qDebug("HttpRequest: extract and decode request parameters");
#endif
// Get URL parameters
QByteArray rawParameters;
if (headers.value("Content-Type")=="application/x-www-form-urlencoded") {
rawParameters=bodyData;
int questionMark=path.indexOf('?');
if (questionMark>=0) {
rawParameters=path.mid(questionMark+1);
path=path.left(questionMark);
}
else {
int questionMark=path.indexOf('?');
if (questionMark>=0) {
rawParameters=path.mid(questionMark+1);
path=path.left(questionMark);
// Get request body parameters
QByteArray contentType=headers.value("Content-Type");
if (!bodyData.isEmpty() && (contentType.isEmpty() || contentType.startsWith("application/x-www-form-urlencoded"))) {
if (rawParameters.isEmpty()) {
rawParameters.append('&');
rawParameters.append(bodyData);
}
else {
rawParameters=bodyData;
}
}
// Split the parameters into pairs of value and name

View File

@ -111,8 +111,9 @@ public:
/**
Decode an URL parameter.
E.g. replace "%23" by '#' and replace '+' by ' '
@param source The url encoded string
E.g. replace "%23" by '#' and replace '+' by ' '.
@param source The url encoded strings
@see QUrl::toPercentEncoding for the reverse direction
*/
static QByteArray urlDecode(const QByteArray source);
@ -173,9 +174,6 @@ private:
/** Maximum allowed size of multipart forms in bytes. */
int maxMultiPartSize;
/** Directory for temp files */
QString tempDir;
/** Current size */
int currentSize;

View File

@ -109,7 +109,6 @@ void HttpResponse::writeText(QString text, bool lastPart)
write(text.toAscii(),lastPart);
}
bool HttpResponse::hasSentLastPart() const {
return sentLastPart;
}

View File

@ -7,15 +7,14 @@
#include <QDateTime>
#include <QUuid>
#include "comic.h"
HttpSession::HttpSession(bool canStore) {
if (canStore) {
dataPtr=new HttpSessionData();
dataPtr->yacreaderSessionData.comic = 0;
dataPtr->refCount=1;
dataPtr->lastAccess=QDateTime::currentMSecsSinceEpoch();
dataPtr->id=QUuid::createUuid().toString().toAscii();
dataPtr->yacreaderSessionData.comic = 0;
#ifdef SUPERVERBOSE
qDebug("HttpSession: created new session data with id %s",dataPtr->id.data());
#endif
@ -159,7 +158,6 @@ void HttpSession::setLastAccess() {
}
}
//AÑADIDO
bool HttpSession::isComicOnDevice(const QString & hash)
{

View File

@ -13,6 +13,7 @@
#include <QSet>
#include <QString>
class Comic;
/**
This class stores data for a single HTTP session.
A session can store any number of key/value pairs. This class uses implicit
@ -114,26 +115,26 @@ private:
Comic * comic;
};
struct HttpSessionData {
struct HttpSessionData {
/** Unique ID */
QByteArray id;
/** Unique ID */
QByteArray id;
/** Timestamp of last access, set by the HttpSessionStore */
qint64 lastAccess;
/** Timestamp of last access, set by the HttpSessionStore */
qint64 lastAccess;
/** Reference counter */
int refCount;
/** Reference counter */
int refCount;
/** Used to synchronize threads */
QReadWriteLock lock;
/** Used to synchronize threads */
QReadWriteLock lock;
/** Storage for the key/value pairs; */
QMap<QByteArray,QVariant> values;
/** Storage for the key/value pairs; */
QMap<QByteArray,QVariant> values;
YACReaderSessionData yacreaderSessionData;
};
};
/** Pointer to the shared data. */
HttpSessionData* dataPtr;

View File

@ -31,7 +31,7 @@
class HttpSessionStore : public QObject {
Q_OBJECT
Q_DISABLE_COPY(HttpSessionStore);
Q_DISABLE_COPY(HttpSessionStore)
public:
/** Constructor. */

View File

@ -42,14 +42,18 @@ void StaticFileController::service(HttpRequest& request, HttpResponse& response)
}
// Check if we have the file in cache
qint64 now=QDateTime::currentMSecsSinceEpoch();
mutex.lock();
CacheEntry* entry=cache.object(path);
if (entry && (cacheTimeout==0 || entry->created>now-cacheTimeout)) {
if (entry && (cacheTimeout==0 || entry->created>now-cacheTimeout)) {
QByteArray document=entry->document; //copy the cached document, because other threads may destroy the cached entry immediately after mutex unlock.
mutex.unlock();
qDebug("StaticFileController: Cache hit for %s",path.data());
setContentType(path,response);
response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000));
response.write(entry->document);
response.write(document);
}
else {
mutex.unlock();
qDebug("StaticFileController: Cache miss for %s",path.data());
// The file is not in cache.
// If the filename is a directory, append index.html.
@ -65,11 +69,11 @@ void StaticFileController::service(HttpRequest& request, HttpResponse& response)
fileName = getLocalizedFileName(fileName, request.getHeader("Accept-Language"), stringPath);
QString newPath = stringPath.append(fileName);
//END_TODO
QFile file(docroot+newPath);
QFile file(docroot+path);
if (file.exists()) {
qDebug("StaticFileController: Open file %s",qPrintable(file.fileName()));
if (file.open(QIODevice::ReadOnly)) {
setContentType(newPath,response);
setContentType(path,response);
response.setHeader("Cache-Control","max-age="+QByteArray::number(maxAge/1000));
if (file.size()<=maxCachedFileSize) {
// Return the file content and store it also in the cache
@ -80,7 +84,9 @@ void StaticFileController::service(HttpRequest& request, HttpResponse& response)
entry->document.append(buffer);
}
entry->created=now;
mutex.lock();
cache.insert(request.getPath(),entry,entry->document.size());
mutex.unlock();
}
else {
// Return the file content, do not store in cache
@ -113,22 +119,23 @@ void StaticFileController::setContentType(QString fileName, HttpResponse& respon
else if (fileName.endsWith(".gif")) {
response.setHeader("Content-Type", "image/gif");
}
else if (fileName.endsWith(".pdf")) {
response.setHeader("Content-Type", "application/pdf");
}
else if (fileName.endsWith(".txt")) {
response.setHeader("Content-Type", qPrintable("text/plain; charset="+encoding));
}
else if (fileName.endsWith(".html") || fileName.endsWith(".htm")) {
response.setHeader("Content-Type", qPrintable("text/html; charset=charset="+encoding));
response.setHeader("Content-Type", qPrintable("text/html; charset="+encoding));
}
else if (fileName.endsWith(".js"))
response.setHeader("Content-Type", qPrintable("text/javascript; charset=charset="+encoding));
// Todo: add all of your content types
}
bool StaticFileController::exists(QString localizedName, QString path) const
{
QString fileName=docroot+"/"+path + localizedName;
QFile file(fileName);
return file.exists();
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ó
@ -164,4 +171,3 @@ QString StaticFileController::getLocalizedFileName(QString fileName, QString loc
return fileName;
}

View File

@ -10,6 +10,7 @@
#include "httpresponse.h"
#include "httprequesthandler.h"
#include <QCache>
#include <QMutex>
/**
Delivers static files. It is usually called by the applications main request handler when
@ -74,10 +75,13 @@ private:
/** Cache storage */
QCache<QString,CacheEntry> cache;
/** Used to synchronize cache access for threads */
QMutex mutex;
/** Set a content-type header in the response depending on the ending of the filename */
void setContentType(QString file, HttpResponse& response) const;
QString getLocalizedFileName(QString fileName, QString locales, QString path) const;
QString StaticFileController::getLocalizedFileName(QString fileName, QString locales, QString path) const;
bool exists(QString localizedName, QString path) const;
};

View File

@ -49,7 +49,7 @@ QString LogMessage::toString(const QString& msgFormat, const QString& timestampF
}
QString threadId;
threadId.setNum((qint64)QThread::currentThreadId());
threadId.setNum((unsigned int)QThread::currentThreadId());
decorated.replace("{thread}",threadId);
// Fill in variables

View File

@ -33,7 +33,7 @@ int Template::setVariable(QString name, QString value) {
while (start>=0) {
replace(start, variable.length(), value);
count++;
start=indexOf(variable,start+variable.length());
start=indexOf(variable,start+value.length());
}
if (count==0 && warnings) {
qWarning("Template: missing variable %s in %s",qPrintable(variable),qPrintable(sourceName));