| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- /**
- @file
- @author Stefan Frings
- */
- #include "httpresponse.h"
- using namespace stefanfrings;
- HttpResponse::HttpResponse(QTcpSocket *socket)
- {
- this->socket=socket;
- statusCode=200;
- statusText="OK";
- sentHeaders=false;
- sentLastPart=false;
- chunkedMode=false;
- }
- void HttpResponse::setHeader(QByteArray name, QByteArray value)
- {
- Q_ASSERT(sentHeaders==false);
- headers.insert(name,value);
- }
- void HttpResponse::setHeader(QByteArray name, int value)
- {
- Q_ASSERT(sentHeaders==false);
- headers.insert(name,QByteArray::number(value));
- }
- QMap<QByteArray,QByteArray>& HttpResponse::getHeaders()
- {
- return headers;
- }
- void HttpResponse::setStatus(int statusCode, QByteArray description)
- {
- this->statusCode=statusCode;
- statusText=description;
- }
- int HttpResponse::getStatusCode() const
- {
- return this->statusCode;
- }
- void HttpResponse::writeHeaders()
- {
- Q_ASSERT(sentHeaders==false);
- QByteArray buffer;
- buffer.append("HTTP/1.1 ");
- buffer.append(QByteArray::number(statusCode));
- buffer.append(' ');
- buffer.append(statusText);
- buffer.append("\r\n");
- foreach(QByteArray name, headers.keys())
- {
- buffer.append(name);
- buffer.append(": ");
- buffer.append(headers.value(name));
- buffer.append("\r\n");
- }
- foreach(HttpCookie cookie,cookies.values())
- {
- buffer.append("Set-Cookie: ");
- buffer.append(cookie.toByteArray());
- buffer.append("\r\n");
- }
- buffer.append("\r\n");
- writeToSocket(buffer);
- socket->flush();
- sentHeaders=true;
- }
- bool HttpResponse::writeToSocket(QByteArray data)
- {
- int remaining=data.size();
- char* ptr=data.data();
- while (socket->isOpen() && remaining>0)
- {
- // If the output buffer has become large, then wait until it has been sent.
- if (socket->bytesToWrite()>16384)
- {
- socket->waitForBytesWritten(-1);
- }
- qint64 written=socket->write(ptr,remaining);
- if (written==-1)
- {
- return false;
- }
- ptr+=written;
- remaining-=written;
- }
- return true;
- }
- void HttpResponse::write(QByteArray data, bool lastPart)
- {
- Q_ASSERT(sentLastPart==false);
- // Send HTTP headers, if not already done (that happens only on the first call to write())
- if (sentHeaders==false)
- {
- // If the whole response is generated with a single call to write(), then we know the total
- // size of the response and therefore can set the Content-Length header automatically.
- if (lastPart)
- {
- // Automatically set the Content-Length header
- headers.insert("Content-Length",QByteArray::number(data.size()));
- }
- // else if we will not close the connection at the end and there is no Content-Length header,
- // then we must use the chunked mode.
- else
- {
- QByteArray connectionValue=headers.value("Connection",headers.value("connection"));
- bool connectionClose=QString::compare(connectionValue,"close",Qt::CaseInsensitive)==0;
- if (!connectionClose && !headers.contains("Content-Length"))
- {
- headers.insert("Transfer-Encoding","chunked");
- chunkedMode=true;
- }
- }
- writeHeaders();
- }
- // Send data
- if (data.size()>0)
- {
- if (chunkedMode)
- {
- if (data.size()>0)
- {
- QByteArray size=QByteArray::number(data.size(),16);
- writeToSocket(size);
- writeToSocket("\r\n");
- writeToSocket(data);
- writeToSocket("\r\n");
- }
- }
- else
- {
- writeToSocket(data);
- }
- }
- // Only for the last chunk, send the terminating marker and flush the buffer.
- if (lastPart)
- {
- if (chunkedMode)
- {
- writeToSocket("0\r\n\r\n");
- }
- socket->flush();
- sentLastPart=true;
- }
- }
- bool HttpResponse::hasSentLastPart() const
- {
- return sentLastPart;
- }
- void HttpResponse::setCookie(const HttpCookie& cookie)
- {
- Q_ASSERT(sentHeaders==false);
- if (!cookie.getName().isEmpty())
- {
- cookies.insert(cookie.getName(),cookie);
- }
- }
- QMap<QByteArray,HttpCookie>& HttpResponse::getCookies()
- {
- return cookies;
- }
- void HttpResponse::redirect(const QByteArray& url)
- {
- setStatus(303,"See Other");
- setHeader("Location",url);
- write("Redirect",true);
- }
- void HttpResponse::flush()
- {
- socket->flush();
- }
- bool HttpResponse::isConnected() const
- {
- return socket->isOpen();
- }
|