mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-03 13:11:20 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			201 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/**
 | 
						|
  @file
 | 
						|
  @author Stefan Frings
 | 
						|
*/
 | 
						|
 | 
						|
#include "httpresponse.h"
 | 
						|
 | 
						|
using namespace qtwebapp;
 | 
						|
 | 
						|
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);
 | 
						|
    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);
 | 
						|
        }
 | 
						|
 | 
						|
        int 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, them 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.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();
 | 
						|
}
 |