| 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();}
 |