Files
GoldenCheetah/contrib/httpserver/httpresponse.cpp
Mark Liversedge e1ac00b860 Move contributed sources to contrib directory
.. Makes it easier to identify code that has been snaffled in from
   other repositories and check licensing

.. The httpserver is now no longer optional, since it is delivered
   as contributed source.
2021-05-16 10:33:09 +01:00

157 lines
4.0 KiB
C++

/**
@file
@author Stefan Frings
*/
#include "httpresponse.h"
HttpResponse::HttpResponse(QTcpSocket* socket) {
this->socket=socket;
statusCode=200;
statusText="OK";
sentHeaders=false;
sentLastPart=false;
buffersize=40960;
barry.reserve(40960);
userdata_=NULL;
}
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;
}
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) {
// Wait until the previous buffer content is written out, otherwise it could become very large
socket->waitForBytesWritten(-1);
int written=socket->write(ptr,remaining);
if (written==-1) {
return false;
}
ptr+=written;
remaining-=written;
}
return true;
}
void HttpResponse::bwrite(QByteArray data)
{
if (barry.size() && (barry.size() + data.size() > buffersize)) {
// flush buffer
write(barry);
barry = data;
} else {
barry.append(data);
}
}
void HttpResponse::flush()
{
if (barry.size()) {
write(barry, true);
barry.clear();
}
}
void HttpResponse::write(QByteArray data, bool lastPart) {
Q_ASSERT(sentLastPart==false);
if (sentHeaders==false) {
QByteArray connectionMode=headers.value("Connection");
if (!headers.contains("Content-Length") && !headers.contains("Transfer-Encoding") && connectionMode!="close" && connectionMode!="Close") {
if (!lastPart) {
headers.insert("Transfer-Encoding","chunked");
}
else {
headers.insert("Content-Length",QByteArray::number(data.size()));
}
}
writeHeaders();
}
bool chunked=headers.value("Transfer-Encoding")=="chunked" || headers.value("Transfer-Encoding")=="Chunked";
if (chunked) {
if (data.size()>0) {
QByteArray buffer=QByteArray::number(data.size(),16);
buffer.append("\r\n");
writeToSocket(buffer);
writeToSocket(data);
writeToSocket("\r\n");
}
}
else {
writeToSocket(data);
}
if (lastPart) {
if (chunked) {
writeToSocket("0\r\n\r\n");
}
else if (!headers.contains("Content-Length")) {
socket->disconnectFromHost();
}
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);
}