9using namespace stefanfrings;
11HttpConnectionHandler::HttpConnectionHandler(
const QSettings *settings,
HttpRequestHandler *requestHandler,
const QSslConfiguration* sslConfiguration)
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));
44void 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));
62void 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;
127void HttpConnectionHandler::readTimeout()
129 qDebug(
"HttpConnectionHandler (%p): read timeout occured",
static_cast<void*
>(
this));
134 if(socket->bytesToWrite())
136 socket->waitForBytesWritten(1000);
138 socket->disconnectFromHost();
139 delete currentRequest;
140 currentRequest=
nullptr;
144void HttpConnectionHandler::disconnected()
146 qDebug(
"HttpConnectionHandler (%p): disconnected",
static_cast<void*
>(
this));
152void HttpConnectionHandler::read()
155 while (socket->bytesAvailable())
158 qDebug(
"HttpConnectionHandler (%p): read input",
static_cast<void*
>(
this));
168 while (socket->bytesAvailable() &&
169 currentRequest->
getStatus()!=HttpRequest::complete &&
170 currentRequest->
getStatus()!=HttpRequest::abort_size &&
171 currentRequest->
getStatus()!=HttpRequest::abort_broken)
174 if (currentRequest->
getStatus()==HttpRequest::waitForBody)
178 int readTimeout=settings->value(
"readTimeout",10000).toInt();
179 readTimer.start(readTimeout);
184 if (currentRequest->
getStatus()==HttpRequest::abort_size)
186 socket->write(
"HTTP/1.1 413 entity too large\r\nConnection: close\r\n\r\n413 Entity too large\r\n");
187 if(socket->bytesToWrite())
189 socket->waitForBytesWritten(1000);
191 socket->disconnectFromHost();
192 delete currentRequest;
193 currentRequest=
nullptr;
198 else if (currentRequest->
getStatus()==HttpRequest::abort_broken)
200 socket->write(
"HTTP/1.1 400 bad request\r\nConnection: close\r\n\r\n400 Bad request\r\n");
201 if(socket->bytesToWrite())
203 socket->waitForBytesWritten(1000);
205 socket->disconnectFromHost();
206 delete currentRequest;
207 currentRequest=
nullptr;
212 else if (currentRequest->
getStatus()==HttpRequest::complete)
215 qDebug(
"HttpConnectionHandler (%p): received request",
static_cast<void*
>(
this));
219 bool closeConnection=QString::compare(currentRequest->
getHeader(
"Connection"),
"close",Qt::CaseInsensitive)==0;
222 response.setHeader(
"Connection",
"close");
229 bool http1_0=QString::compare(currentRequest->
getVersion(),
"HTTP/1.0",Qt::CaseInsensitive)==0;
232 closeConnection=
true;
233 response.setHeader(
"Connection",
"close");
240 requestHandler->
service(*currentRequest, response);
244 qCritical(
"HttpConnectionHandler (%p): An uncatched exception occured in the request handler",
245 static_cast<void*
>(
this));
249 if (!response.hasSentLastPart())
251 response.write(QByteArray(),
true);
254 qDebug(
"HttpConnectionHandler (%p): finished request",
static_cast<void*
>(
this));
257 if (!closeConnection)
260 bool closeResponse=QString::compare(response.getHeaders().value(
"Connection"),
"close",Qt::CaseInsensitive)==0;
261 if (closeResponse==
true)
263 closeConnection=
true;
269 bool hasContentLength=response.getHeaders().contains(
"Content-Length");
270 if (!hasContentLength)
272 bool hasChunkedMode=QString::compare(response.getHeaders().value(
"Transfer-Encoding"),
"chunked",Qt::CaseInsensitive)==0;
275 closeConnection=
true;
284 if(socket->bytesToWrite())
286 socket->waitForBytesWritten(1000);
288 socket->disconnectFromHost();
293 int readTimeout=settings->value(
"readTimeout",10000).toInt();
294 readTimer.start(readTimeout);
296 delete currentRequest;
297 currentRequest=
nullptr;
bool isBusy()
Returns true, if this handler is in use.
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.
const 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.