mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 04:50:29 -04: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();
 | |
| }
 |