Please note that active projects have migrated to https://github.com/fawkesrobotics.

37a886a36aa7487812a3721dd68f176443f6dc8c
[fawkes.git] / src / libs / webview / reply.cpp
1
2 /***************************************************************************
3  *  reply.cpp - Web request reply
4  *
5  *  Created: Thu Oct 23 12:01:05 2008
6  *  Copyright  2006-2009  Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9
10 /*  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU Library General Public License for more details.
19  *
20  *  Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22
23 #include <webview/reply.h>
24
25 #include <core/exception.h>
26 #include <cstdlib>
27 #include <cstdarg>
28 #include <cstdio>
29
30 namespace fawkes {
31 #if 0 /* just to make Emacs auto-indent happy */
32 }
33 #endif
34
35 /** Disable caching on a reply.
36  * This is a convenience wrapper to reply->set_caching(false). It enables
37  * the following call styles:
38  * @code
39  * return no_caching(new StaticWebReply(Reply::HTTP_NOT_FOUND, "Not Found"));
40  *
41  * return no_caching(some_handler());
42  * @endcode
43  * This works on any reply without always patching a boolean flag into
44  * the ctor and without first storing the pointer, calling the function,
45  * and then returning.
46  * @param reply reply to disable caching for
47  * @return this
48  */
49 WebReply *
50 no_caching(WebReply *reply)
51 {
52         reply->set_caching(false);
53         return reply;
54 }
55
56
57 /** @class WebReply <webview/reply.h>
58  * Basic web reply.
59  * The base class for all web replies. Though the WebRequestDispatcher expects
60  * sub-classes of StaticWebReply or DynamicWebReply.
61  * @author Tim Niemueller
62  */
63
64 /// Enable caching for this reply?
65 bool WebReply::caching_default_ = true;
66
67 /** Constructor.
68  * @param code HTTP response code
69  */
70 WebReply::WebReply(Code code)
71 {
72   code_ = code;
73   request_ = NULL;
74
75   caching_ = caching_default_;
76 }
77
78
79 /** Destructor. */
80 WebReply::~WebReply()
81 {
82 }
83
84
85 /** Enable or disable caching default for replies.
86  * This static setting controls whether following replies will allow
87  * for client-side of the web pages or not by default. Disabling this
88  * allows to force clients to always reload the pages.
89  * @param caching true to enable client-side caching, false to disable
90  */
91 void
92 WebReply::set_caching_default(bool caching)
93 {
94   caching_default_ = caching;
95 }
96
97 /** Enable or disable caching for this specific reply.
98  * @param caching true to enable client-side caching, false to disable
99  */
100 void
101 WebReply::set_caching(bool caching)
102 {
103   caching_ = caching;
104 }
105
106
107 /** Get response code.
108  * @return HTTP response code
109  */
110 WebReply::Code
111 WebReply::code() const
112 {
113   return code_;
114 }
115
116 /** Set response code.
117  * @param code HTTP response code
118  */
119 void
120 WebReply::set_code(WebReply::Code code)
121 {
122         __code = code;
123 }
124
125
126 /** Set response code.
127  * @param code HTTP response code
128  */
129 void
130 WebReply::set_code(WebReply::Code code)
131 {
132         code_ = code;
133 }
134
135 /** Add a HTTP header.
136  * @param header header entry name
137  * @param content content of the header field
138  */
139 void
140 WebReply::add_header(const std::string& header, const std::string& content)
141 {
142   headers_[header] = content;
143 }
144
145
146 /** Add a HTTP header.
147  * @param header_string header string of the format "Key: Value".
148  */
149 void
150 WebReply::add_header(const std::string& header_string)
151 {
152   std::string::size_type pos;
153   if ((pos = header_string.find(":")) != std::string::npos) {
154     std::string header = header_string.substr(0, pos);
155     std::string content;
156     if (header_string[pos+1] == ' ') {
157       content = header_string.substr(pos+2);
158     } else {
159       content = header_string.substr(pos+1);
160     }
161     headers_[header] = content;
162   } else {
163     throw Exception("Invalid header '%s'", header_string.c_str());
164   }
165 }
166
167
168 /** get headers.
169  * @return map of header name/content pairs.
170  */
171 const WebReply::HeaderMap &
172 WebReply::headers() const
173 {
174   return headers_;
175 }
176
177
178 /** Get associated request.
179  * This is only valid after set_request() has been called.
180  * @return associated web request
181  */
182 WebRequest *
183 WebReply::get_request() const
184 {
185   return request_;
186 }
187
188
189 /** Set associated request.
190  * @param request associated request
191  */
192 void
193 WebReply::set_request(WebRequest *request)
194 {
195   request_ = request;
196 }
197
198 /** Called just before the reply is sent.
199  * Sets no-caching flags if caching has been disabled. 
200  */
201 void
202 WebReply::pack_caching()
203 {
204   if (! caching_) {
205     // Headers to disable caching
206     headers_["Cache-Control"] = "no-cache, no-store, must-revalidate, max-age=0";
207   }
208 }
209
210 /** @class DynamicWebReply <webview/reply.h>
211  * Dynamic web reply.
212  * A reply of this type is send out in chunks, not all as a whole. It should be
213  * used for payloads that can get very large, like file transfers.
214  * @author Tim Niemueller
215  *
216  * @fn size_t DynamicWebReply::size() = 0
217  * Total size of the web reply.
218  * Return the total size of the reply if known, or -1 if it is not known. In the
219  * latter case your next_chunk() method has to return -1 at some point to end
220  * the transfer. If possible by any means return a meaningful value, as it will
221  * improve the experience of users, especially for long transfers!
222  * @return total size of reply in bytes
223  *
224  * @fn size_t DynamicWebReply::next_chunk(size_t pos, char *buffer, size_t buf_max_size) = 0
225  * Get data of next chunk.
226  * @param pos position in the stream. Note that a certain position may be called
227  * several times.
228  * @param buffer buffer to store data in
229  * @param buf_max_size maximum size in bytes of data that can be put into buffer
230  * @return number of bytes written to buffer, or -1 to immediately stop the
231  * transfer.
232  */
233
234 /** Constructor.
235  * @param code HTTP response code
236  */
237 DynamicWebReply::DynamicWebReply(Code code)
238   : WebReply(code)
239 {
240 }
241
242
243 /** Chunksize.
244  * The size that a single chunk should have. A sub-class may override this if a
245  * specific chunk size is beneficial or even required. The default is 32kb.
246  * @return chunk size in bytes
247  */
248 size_t
249 DynamicWebReply::chunk_size()
250 {
251   // use 32k chunks by default
252   return 32 * 1024;
253 }
254
255
256 /** @class StaticWebReply <webview/reply.h>
257  * Static web reply.
258  * The static web reply is send out as a whole at once and is immediately
259  * deleted after sending. Use it for regular-sized pages and content.
260  * @author Tim Niemueller
261  */
262
263 /** Constructor.
264  * @param code HTTP response code
265  * @param body optional initial body
266  */
267 StaticWebReply::StaticWebReply(Code code, std::string body)
268   : WebReply(code)
269 {
270   _body = body;
271 }
272
273
274 /** Append to body.
275  * @param format format of the text to append. Supports the same format as
276  * printf().
277  */
278 void
279 StaticWebReply::append_body(const char *format, ...)
280 {
281   va_list args;
282   va_start(args, format);
283   char *s;
284   if ( vasprintf(&s, format, args) != -1 ) {
285     _body += s;
286     free(s);
287   }
288   va_end(args);
289 }
290
291 /** Append string to body.
292  * @param s string to add, this may contain null bytes
293  */
294 void
295 StaticWebReply::append_body(const std::string &s)
296 {
297         _body += s;
298 }
299
300
301 /** Append simple text line.
302  * @param text text to append to body
303  * @return reference to this instance
304  */
305 StaticWebReply &
306 StaticWebReply::operator+=(std::string text)
307 {
308   _body += text;
309   return *this;
310 }
311
312
313 /** Get body.
314  * @return reference to body.
315  */
316 const std::string &
317 StaticWebReply::body()
318 {
319   return _body;
320 }
321
322
323 /** Get length of body.
324  * @return body length
325  */
326 std::string::size_type
327 StaticWebReply::body_length()
328 {
329   return _body.length();
330 }
331
332
333 /** Pack the data.
334  * This method is called just before the reply is sent.
335  * You can implement this method if you need to compose your reply before
336  * body() and body_length() provide valid output.
337  */
338 void
339 StaticWebReply::pack()
340 {
341 }
342
343 } // end namespace fawkes