QtWebApp
httpresponse.cpp
Go to the documentation of this file.
1 
6 #include "httpresponse.h"
7 
8 using namespace stefanfrings;
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 
48 void HttpResponse::writeHeaders()
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  socket->flush();
73  sentHeaders=true;
74 }
75 
76 bool HttpResponse::writeToSocket(QByteArray data)
77 {
78  int remaining=data.size();
79  char* ptr=data.data();
80  while (socket->isOpen() && remaining>0)
81  {
82  // If the output buffer has become large, then wait until it has been sent.
83  if (socket->bytesToWrite()>16384)
84  {
85  socket->waitForBytesWritten(-1);
86  }
87 
88  qint64 written=socket->write(ptr,remaining);
89  if (written==-1)
90  {
91  return false;
92  }
93  ptr+=written;
94  remaining-=written;
95  }
96  return true;
97 }
98 
99 void HttpResponse::write(QByteArray data, bool lastPart)
100 {
101  Q_ASSERT(sentLastPart==false);
102 
103  // Send HTTP headers, if not already done (that happens only on the first call to write())
104  if (sentHeaders==false)
105  {
106  // If the whole response is generated with a single call to write(), then we know the total
107  // size of the response and therefore can set the Content-Length header automatically.
108  if (lastPart)
109  {
110  // Automatically set the Content-Length header
111  headers.insert("Content-Length",QByteArray::number(data.size()));
112  }
113 
114  // else if we will not close the connection at the end, them we must use the chunked mode.
115  else
116  {
117  QByteArray connectionValue=headers.value("Connection",headers.value("connection"));
118  bool connectionClose=QString::compare(connectionValue,"close",Qt::CaseInsensitive)==0;
119  if (!connectionClose)
120  {
121  headers.insert("Transfer-Encoding","chunked");
122  chunkedMode=true;
123  }
124  }
125 
126  writeHeaders();
127  }
128 
129  // Send data
130  if (data.size()>0)
131  {
132  if (chunkedMode)
133  {
134  if (data.size()>0)
135  {
136  QByteArray size=QByteArray::number(data.size(),16);
137  writeToSocket(size);
138  writeToSocket("\r\n");
139  writeToSocket(data);
140  writeToSocket("\r\n");
141  }
142  }
143  else
144  {
145  writeToSocket(data);
146  }
147  }
148 
149  // Only for the last chunk, send the terminating marker and flush the buffer.
150  if (lastPart)
151  {
152  if (chunkedMode)
153  {
154  writeToSocket("0\r\n\r\n");
155  }
156  socket->flush();
157  sentLastPart=true;
158  }
159 }
160 
161 
163 {
164  return sentLastPart;
165 }
166 
167 
169 {
170  Q_ASSERT(sentHeaders==false);
171  if (!cookie.getName().isEmpty())
172  {
173  cookies.insert(cookie.getName(),cookie);
174  }
175 }
176 
177 
178 QMap<QByteArray,HttpCookie>& HttpResponse::getCookies()
179 {
180  return cookies;
181 }
182 
183 
184 void HttpResponse::redirect(const QByteArray& url)
185 {
186  setStatus(303,"See Other");
187  setHeader("Location",url);
188  write("Redirect",true);
189 }
190 
191 
193 {
194  socket->flush();
195 }
196 
197 
199 {
200  return socket->isOpen();
201 }
HTTP cookie as defined in RFC 2109.
Definition: httpcookie.h:21
QByteArray getName() const
Get the name of this cookie.
Definition: httpcookie.cpp:190
QByteArray toByteArray() const
Convert this cookie to a string that may be used in a Set-Cookie header.
Definition: httpcookie.cpp:105
bool hasSentLastPart() const
Indicates whether the body has been sent completely (write() has been called with lastPart=true).
void flush()
Flush the output buffer (of the underlying socket).
bool isConnected() const
May be used to check whether the connection to the web client has been lost.
void setHeader(const QByteArray name, const QByteArray value)
Set a HTTP response header.
QMap< QByteArray, HttpCookie > & getCookies()
Get the map of cookies.
int getStatusCode() const
Return the status code.
void setStatus(const int statusCode, const QByteArray description=QByteArray())
Set status code and description.
HttpResponse(QTcpSocket *socket)
Constructor.
void write(const QByteArray data, const bool lastPart=false)
Write body data to the socket.
QMap< QByteArray, QByteArray > & getHeaders()
Get the map of HTTP response headers.
void setCookie(const HttpCookie &cookie)
Set a cookie.
void redirect(const QByteArray &url)
Send a redirect response to the browser.