mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-04 05:30:32 -05:00 
			
		
		
		
	
		
			
	
	
		
			201 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			201 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								  @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);
							 | 
						||
| 
								 | 
							
								    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();
							 | 
						||
| 
								 | 
							
								}
							 |