SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
httpresponse.cpp
Go to the documentation of this file.
1 
6 #include "httpresponse.h"
7 
8 using namespace qtwebapp;
9 
10 HttpResponse::HttpResponse(QTcpSocket* socket)
11 {
12  this->socket=socket;
13  statusCode=200;
14  statusText="OK";
15  sentHeaders=false;
16  sentLastPart=false;
17  chunkedMode=false;
18 }
19 
20 void HttpResponse::setHeader(QByteArray name, QByteArray value)
21 {
22  Q_ASSERT(sentHeaders==false);
23  headers.insert(name,value);
24 }
25 
26 void HttpResponse::setHeader(QByteArray name, int value)
27 {
28  Q_ASSERT(sentHeaders==false);
29  headers.insert(name,QByteArray::number(value));
30 }
31 
32 QMap<QByteArray,QByteArray>& HttpResponse::getHeaders()
33 {
34  return headers;
35 }
36 
37 void HttpResponse::setStatus(int statusCode, QByteArray description)
38 {
39  this->statusCode=statusCode;
40  statusText=description;
41 }
42 
44 {
45  return this->statusCode;
46 }
47 
49 {
50  Q_ASSERT(sentHeaders==false);
51  QByteArray buffer;
52  buffer.append("HTTP/1.1 ");
53  buffer.append(QByteArray::number(statusCode));
54  buffer.append(' ');
55  buffer.append(statusText);
56  buffer.append("\r\n");
57  foreach(QByteArray name, headers.keys())
58  {
59  buffer.append(name);
60  buffer.append(": ");
61  buffer.append(headers.value(name));
62  buffer.append("\r\n");
63  }
64  foreach(HttpCookie cookie,cookies.values())
65  {
66  buffer.append("Set-Cookie: ");
67  buffer.append(cookie.toByteArray());
68  buffer.append("\r\n");
69  }
70  buffer.append("\r\n");
71  writeToSocket(buffer);
72  sentHeaders=true;
73 }
74 
75 bool HttpResponse::writeToSocket(QByteArray data)
76 {
77  int remaining=data.size();
78  char* ptr=data.data();
79  while (socket->isOpen() && remaining>0)
80  {
81  // If the output buffer has become large, then wait until it has been sent.
82  if (socket->bytesToWrite()>16384)
83  {
84  socket->waitForBytesWritten(-1);
85  }
86 
87  int written=socket->write(ptr,remaining);
88  if (written==-1)
89  {
90  return false;
91  }
92  ptr+=written;
93  remaining-=written;
94  }
95  return true;
96 }
97 
98 void HttpResponse::write(QByteArray data, bool lastPart)
99 {
100  Q_ASSERT(sentLastPart==false);
101 
102  // Send HTTP headers, if not already done (that happens only on the first call to write())
103  if (sentHeaders==false)
104  {
105  // If the whole response is generated with a single call to write(), then we know the total
106  // size of the response and therefore can set the Content-Length header automatically.
107  if (lastPart)
108  {
109  // Automatically set the Content-Length header
110  headers.insert("Content-Length",QByteArray::number(data.size()));
111  }
112 
113  // else if we will not close the connection at the end, them we must use the chunked mode.
114  else
115  {
116  QByteArray connectionValue=headers.value("Connection",headers.value("connection"));
117  bool connectionClose=QString::compare(connectionValue,"close",Qt::CaseInsensitive)==0;
118  if (!connectionClose)
119  {
120  headers.insert("Transfer-Encoding","chunked");
121  chunkedMode=true;
122  }
123  }
124 
125  writeHeaders();
126  }
127 
128  // Send data
129  if (data.size()>0)
130  {
131  if (chunkedMode)
132  {
133  if (data.size()>0)
134  {
135  QByteArray size=QByteArray::number(data.size(),16);
136  writeToSocket(size);
137  writeToSocket("\r\n");
138  writeToSocket(data);
139  writeToSocket("\r\n");
140  }
141  }
142  else
143  {
144  writeToSocket(data);
145  }
146  }
147 
148  // Only for the last chunk, send the terminating marker and flush the buffer.
149  if (lastPart)
150  {
151  if (chunkedMode)
152  {
153  writeToSocket("0\r\n\r\n");
154  }
155  socket->flush();
156  sentLastPart=true;
157  }
158 }
159 
160 
162 {
163  return sentLastPart;
164 }
165 
166 
168 {
169  Q_ASSERT(sentHeaders==false);
170  if (!cookie.getName().isEmpty())
171  {
172  cookies.insert(cookie.getName(),cookie);
173  }
174 }
175 
176 
177 QMap<QByteArray,HttpCookie>& HttpResponse::getCookies()
178 {
179  return cookies;
180 }
181 
182 
183 void HttpResponse::redirect(const QByteArray& url)
184 {
185  setStatus(303,"See Other");
186  setHeader("Location",url);
187  write("Redirect",true);
188 }
189 
190 
192 {
193  socket->flush();
194 }
195 
196 
198 {
199  return socket->isOpen();
200 }
QMap< QByteArray, QByteArray > headers
Definition: httpresponse.h:128
QByteArray toByteArray() const
Definition: httpcookie.cpp:98
QMap< QByteArray, HttpCookie > & getCookies()
void redirect(const QByteArray &url)
void setCookie(const HttpCookie &cookie)
void setHeader(QByteArray name, QByteArray value)
QMap< QByteArray, QByteArray > & getHeaders()
HttpResponse(QTcpSocket *socket)
QByteArray getName() const
Definition: httpcookie.cpp:174
bool hasSentLastPart() const
QMap< QByteArray, HttpCookie > cookies
Definition: httpresponse.h:149
void write(QByteArray data, bool lastPart=false)
void setStatus(int statusCode, QByteArray description=QByteArray())
bool writeToSocket(QByteArray data)