9 using namespace stefanfrings;
14 Q_ASSERT(settings!=
nullptr);
15 Q_ASSERT(requestHandler!=
nullptr);
16 this->settings=settings;
17 this->requestHandler=requestHandler;
18 this->sslConfiguration=sslConfiguration;
19 currentRequest=
nullptr;
23 thread =
new QThread();
25 qDebug(
"HttpConnectionHandler (%p): thread started",
static_cast<void*
>(
this));
27 readTimer.moveToThread(thread);
28 readTimer.setSingleShot(
true);
32 socket->moveToThread(thread);
35 connect(socket, SIGNAL(readyRead()), SLOT(read()));
36 connect(socket, SIGNAL(disconnected()), SLOT(disconnected()));
37 connect(&readTimer, SIGNAL(timeout()), SLOT(readTimeout()));
38 connect(thread, SIGNAL(finished()),
this, SLOT(thread_done()));
40 qDebug(
"HttpConnectionHandler (%p): constructed",
static_cast<void*
>(
this));
44 void HttpConnectionHandler::thread_done()
49 qDebug(
"HttpConnectionHandler (%p): thread stopped",
static_cast<void*
>(
this));
57 thread->deleteLater();
58 qDebug(
"HttpConnectionHandler (%p): destroyed",
static_cast<void*
>(
this));
62 void HttpConnectionHandler::createSocket()
68 QSslSocket* sslSocket=
new QSslSocket();
69 sslSocket->setSslConfiguration(*sslConfiguration);
71 qDebug(
"HttpConnectionHandler (%p): SSL is enabled",
static_cast<void*
>(
this));
76 socket=
new QTcpSocket();
82 qDebug(
"HttpConnectionHandler (%p): handle new connection",
static_cast<void*
>(
this));
84 Q_ASSERT(socket->isOpen()==
false);
88 socket->connectToHost(
"",0);
91 if (!socket->setSocketDescriptor(socketDescriptor))
93 qCritical(
"HttpConnectionHandler (%p): cannot initialize socket: %s",
94 static_cast<void*
>(
this),qPrintable(socket->errorString()));
100 if (sslConfiguration)
102 qDebug(
"HttpConnectionHandler (%p): Starting encryption",
static_cast<void*
>(
this));
103 (
static_cast<QSslSocket*
>(socket))->startServerEncryption();
108 int readTimeout=settings->value(
"readTimeout",10000).toInt();
109 readTimer.start(readTimeout);
111 delete currentRequest;
112 currentRequest=
nullptr;
127 void HttpConnectionHandler::readTimeout()
129 qDebug(
"HttpConnectionHandler (%p): read timeout occured",
static_cast<void*
>(
this));
134 while(socket->bytesToWrite()) socket->waitForBytesWritten();
135 socket->disconnectFromHost();
136 delete currentRequest;
137 currentRequest=
nullptr;
141 void HttpConnectionHandler::disconnected()
143 qDebug(
"HttpConnectionHandler (%p): disconnected",
static_cast<void*
>(
this));
149 void HttpConnectionHandler::read()
152 while (socket->bytesAvailable())
155 qDebug(
"HttpConnectionHandler (%p): read input",
static_cast<void*
>(
this));
165 while (socket->bytesAvailable() && currentRequest->
getStatus()!=HttpRequest::complete && currentRequest->
getStatus()!=HttpRequest::abort)
168 if (currentRequest->
getStatus()==HttpRequest::waitForBody)
172 int readTimeout=settings->value(
"readTimeout",10000).toInt();
173 readTimer.start(readTimeout);
178 if (currentRequest->
getStatus()==HttpRequest::abort)
180 socket->write(
"HTTP/1.1 413 entity too large\r\nConnection: close\r\n\r\n413 Entity too large\r\n");
181 while(socket->bytesToWrite()) socket->waitForBytesWritten();
182 socket->disconnectFromHost();
183 delete currentRequest;
184 currentRequest=
nullptr;
189 if (currentRequest->
getStatus()==HttpRequest::complete)
192 qDebug(
"HttpConnectionHandler (%p): received request",
static_cast<void*
>(
this));
196 bool closeConnection=QString::compare(currentRequest->
getHeader(
"Connection"),
"close",Qt::CaseInsensitive)==0;
199 response.setHeader(
"Connection",
"close");
206 bool http1_0=QString::compare(currentRequest->
getVersion(),
"HTTP/1.0",Qt::CaseInsensitive)==0;
209 closeConnection=
true;
210 response.setHeader(
"Connection",
"close");
217 requestHandler->
service(*currentRequest, response);
221 qCritical(
"HttpConnectionHandler (%p): An uncatched exception occured in the request handler",
222 static_cast<void*
>(
this));
226 if (!response.hasSentLastPart())
228 response.write(QByteArray(),
true);
231 qDebug(
"HttpConnectionHandler (%p): finished request",
static_cast<void*
>(
this));
234 if (!closeConnection)
237 bool closeResponse=QString::compare(response.getHeaders().value(
"Connection"),
"close",Qt::CaseInsensitive)==0;
238 if (closeResponse==
true)
240 closeConnection=
true;
246 bool hasContentLength=response.getHeaders().contains(
"Content-Length");
247 if (!hasContentLength)
249 bool hasChunkedMode=QString::compare(response.getHeaders().value(
"Transfer-Encoding"),
"chunked",Qt::CaseInsensitive)==0;
252 closeConnection=
true;
261 while(socket->bytesToWrite()) socket->waitForBytesWritten();
262 socket->disconnectFromHost();
267 int readTimeout=settings->value(
"readTimeout",10000).toInt();
268 readTimer.start(readTimeout);
270 delete currentRequest;
271 currentRequest=
nullptr;
bool isBusy()
Returns true, if this handler is in use.
HttpConnectionHandler(const QSettings *settings, HttpRequestHandler *requestHandler, const QSslConfiguration *sslConfiguration=nullptr)
Constructor.
void setBusy()
Mark this handler as busy.
void handleConnection(const tSocketDescriptor socketDescriptor)
Received from from the listener, when the handler shall start processing a new connection.
virtual ~HttpConnectionHandler()
Destructor.
The request handler generates a response for each HTTP request.
virtual void service(HttpRequest &request, HttpResponse &response)
Generate a response for an incoming HTTP request.
This object represents a single HTTP request.
RequestStatus getStatus() const
Get the status of this reqeust.
QByteArray getHeader(const QByteArray &name) const
Get the value of a HTTP request header.
void readFromSocket(QTcpSocket *socket)
Read the HTTP request from a socket.
QByteArray getVersion() const
Get the version of the HTPP request (e.g.
This object represents a HTTP response, used to return something to the web client.
qintptr tSocketDescriptor
Alias type definition, for compatibility to different Qt versions.