13 #include <QStringList> 20 HttpResponse::~HttpResponse() {
25 m_connection = connection;
26 m_socket = m_connection->
socket();
30 m_sentHeaders =
false;
32 m_dataBodyPointer = 0;
33 m_dataHeadersPointer = 0;
34 m_canWriteToSocket =
false;
35 m_closeAfterFlush =
false;
36 m_deleteAfterFlush =
false;
37 m_writerTimer =
new QTimer(
this);
38 m_writerTimer->setInterval(1000);
39 m_writerTimer->setSingleShot(
true);
40 connect (m_writerTimer, SIGNAL(timeout()),
41 this, SLOT(slotWrite()));
42 connect (m_socket, SIGNAL(bytesWritten(qint64)),
43 this, SLOT(slotWrite()));
44 connect (m_socket, SIGNAL(disconnected()),
45 this, SLOT(socketDisconnected()));
47 connect (m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
48 this, SLOT(socketError(QAbstractSocket::SocketError)));
52 void HttpResponse::socketError(QAbstractSocket::SocketError error) {
53 qDebug() <<
"socketError" << error;
58 return m_connection->isConnected();
62 void HttpResponse::socketDisconnected() {
67 if (m_sentHeaders) {
return; }
68 m_headers[name] = value;
73 if (m_sentHeaders) {
return; }
74 m_headers[name] = QString(
"%1").arg(value);
89 Q_ASSERT(m_sentHeaders ==
false);
90 m_statusCode = statusCode;
91 m_statusText = statusText;
96 if (m_chunked) {
return true; }
97 if (m_headers.value(
"Transfer-Encoding").toLower() ==
"chunked") {
105 void HttpResponse::writeHeaders() {
106 Q_ASSERT(m_sentHeaders ==
false);
107 if (m_sentHeaders) {
return; }
109 QString contentType = m_headers.value(
"Content-Type").toLower();
110 bool cancompress = (m_connection->settings()->gzip() && !
chunked() && (
111 contentType.startsWith(
"text/") ||
112 contentType.startsWith(
"application/json") ||
113 contentType.startsWith(
"application/javascript"))
117 m_connection->request() != NULL &&
118 m_connection->request()->header(
"Accept-Encoding").contains(
"gzip")
121 bool c200 = (m_statusCode == 200);
123 if (cancompress && requestGzip && !
chunked() && c200) {
128 m_headers.remove(
"Content-Length");
132 if (m_headers.value(
"Content-Encoding").toLower() ==
"gzip" ) {
133 m_dataBody = HttpGZipCompression::compressData(m_dataBody);
137 m_headers[
"Content-Length"] = QString(
"%1").arg(m_dataBody.size());
147 m_dataHeaders +=
"HTTP/1.1 ";
148 m_dataHeaders += QByteArray::number(m_statusCode);
149 m_dataHeaders +=
" ";
150 m_dataHeaders += m_statusText;
151 m_dataHeaders +=
"\r\n";
153 QStringList keys = m_headers.keys();
154 for (
int i=0; i<keys.size(); i++) {
155 m_dataHeaders += keys[i].toUtf8();
156 m_dataHeaders +=
": ";
157 m_dataHeaders += m_headers[keys[i]].toUtf8();
158 m_dataHeaders +=
"\r\n";
161 keys = m_cookies.keys();
162 for (
int i=0; i<keys.size(); i++) {
163 m_dataHeaders +=
"Set-Cookie: ";
164 m_dataHeaders += m_cookies[keys[i]].toByteArray();
165 m_dataHeaders +=
"\r\n";
168 m_dataHeaders +=
"\r\n";
169 m_sentHeaders =
true;
191 m_socket->write(
"0\r\n\r\n");
195 m_socket->waitForBytesWritten(10000);
196 m_socket->disconnectFromHost();
202 if (
chunked() && data.size() > 0) {
203 if (!m_sentHeaders) {
206 m_canWriteToSocket =
true;
207 m_closeAfterFlush =
false;
209 m_dataBodyPointer = 0;
210 m_dataBody += QByteArray::number(data.size(),16) ;
211 m_dataBody +=
"\r\n";
213 m_dataBody +=
"\r\n";
214 while (
isConnected() && m_dataBody.size() > m_dataBodyPointer) {
225 qDebug() <<
"You could not write to HttpRespose when the response is flushed. Data written are ignored.";
228 m_closeAfterFlush =
true;
238 m_canWriteToSocket =
true;
239 m_writerTimer->setInterval(0);
240 m_writerTimer->start();
244 void HttpResponse::flushAndClose() {
245 m_closeAfterFlush =
true;
250 void HttpResponse::flushAndDelete() {
251 m_deleteAfterFlush =
true;
256 void HttpResponse::slotWrite(
bool startTimer) {
257 if (!m_sentHeaders) {
258 m_canWriteToSocket =
true;
261 if (!m_canWriteToSocket) {
goto konec; }
262 if (m_socket->bytesToWrite() > 0) {
goto konec; }
264 if (m_socket->isOpen() !=
true) {
goto konec; }
265 if (m_socket->isWritable() !=
true) {
goto konec; }
266 if (m_dataHeaders.size() > m_dataHeadersPointer) {
267 m_dataHeadersPointer += m_socket->write(m_dataHeaders.mid(m_dataHeadersPointer));
268 if (m_dataHeaders.size() > m_dataHeadersPointer) {
goto konec; }
271 if (m_dataBody.size() > m_dataBodyPointer) {
272 m_dataBodyPointer += m_socket->write(m_dataBody.mid(m_dataBodyPointer));
273 if (m_dataBody.size() > m_dataBodyPointer) {
goto konec; }
276 if (m_dataHeaders.size() <= m_dataHeadersPointer &&
277 m_dataBody.size() <= m_dataBodyPointer &&
280 m_writerTimer->stop();
285 if (m_dataHeaders.size() <= m_dataHeadersPointer &&
286 m_dataBody.size() <= m_dataBodyPointer &&
287 m_deleteAfterFlush) {
289 m_writerTimer->stop();
296 m_writerTimer->setInterval(100);
297 m_writerTimer->start();
QTcpSocket * socket() const
Returns the socket.
HttpResponse(HttpConnection *)
Constructor sets default values for headers (status 200, OK)
HttpCookie cookie(const QString &name)
Returns cookie.
QString name() const
Returns the name of cookie.
One cookie of HTTP protocol.
void flush()
Writes last part of the response and closes the socket when possible.
void flushSocket()
Flushed sockets data to network.
void write(const QByteArray &data)
Writes data to response body.
void setCookie(const HttpCookie &cookie)
Sets a cookie.
bool isConnected() const
Returns true if the http connection is in connected state.
void setStatus(int code, const QString &description=QString())
Set the status code and the description of the response.
void close()
Closes socket and destroys connection. Should by called only when "chunked" transport is choosen...
bool chunked()
Returns true if the trasport mode is chunked.
void setHeader(const QString &name, const QString &value)
Sets or rewrite one header.
void clearHeaders()
Clears all headers set.
Namespace of HTTP server.
QMap< QString, QString > & headers()
Returns headers of the response in QMap.
One single connection to http server.