PageRenderTime 137ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/boost/cgi/common/response.hpp

http://github.com/darrengarvey/cgi
C++ Header | 339 lines | 148 code | 62 blank | 129 comment | 6 complexity | d2f35c23809665a76b7b72dfbf2423c2 MD5 | raw file
  1. // -- response.hpp --
  2. //
  3. // Copyright (c) Darren Garvey 2007.
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. ////////////////////////////////////////////////////////////////
  9. #ifndef CGI_RESPONSE_HPP_INCLUDED__
  10. #define CGI_RESPONSE_HPP_INCLUDED__
  11. #include "boost/cgi/detail/push_options.hpp"
  12. #include <string>
  13. ///////////////////////////////////////////////////////////
  14. #include <boost/bind.hpp>
  15. #include <boost/foreach.hpp>
  16. #include <boost/shared_ptr.hpp>
  17. ///////////////////////////////////////////////////////////
  18. #include "boost/cgi/common/cookie.hpp"
  19. #include "boost/cgi/common/header.hpp"
  20. #include "boost/cgi/http/status_code.hpp"
  21. #include "boost/cgi/import/streambuf.hpp"
  22. #include "boost/cgi/detail/throw_error.hpp"
  23. #include "boost/cgi/fwd/basic_request_fwd.hpp"
  24. #include "boost/cgi/config.hpp"
  25. BOOST_CGI_NAMESPACE_BEGIN
  26. namespace common {
  27. /// The response class: a helper for responding to requests.
  28. /**
  29. * This class has no knowledge of requests or protocols. It is a lightweight
  30. * wrapper over a std::ostream that separates response headers from the
  31. * response body.
  32. *
  33. * One response can be reused for several requests (though not
  34. * simultaneously) and multiple responses can be combined.
  35. *
  36. * Note that std::endl is not supported for this class. std::endl usually
  37. * flushes an std::ostream, which is not possible with this class as it
  38. * is request-agnostic.
  39. *
  40. * When a response has been constructed, you can send it to any
  41. * SyncWriteStream by calling send() or flush().
  42. */
  43. template<typename CharT>
  44. class basic_response
  45. {
  46. public:
  47. typedef basic_response<CharT> self_type;
  48. typedef CharT char_type;
  49. typedef typename std::basic_string<CharT> string_type;
  50. typedef typename std::basic_ostream<CharT> ostream_type;
  51. basic_response(common::http::status_code sc = common::http::ok);
  52. /// Construct with a particular buffer
  53. /**
  54. * Takes the buffer and uses it internally, does nothing with it on
  55. * destruction.
  56. */
  57. basic_response(::BOOST_CGI_NAMESPACE::common::streambuf* buf,
  58. common::http::status_code sc = common::http::ok);
  59. ~basic_response();
  60. /// Clear the response buffer.
  61. void clear(bool clear_headers = true);
  62. /// Return the response to the 'just constructed' state.
  63. void reset();
  64. /// Write characters to the response body.
  65. std::size_t write(const char_type* str, std::size_t len);
  66. /// Write a string to the response body.
  67. std::size_t write(string_type const& str);
  68. template<typename ConstBufferSequence>
  69. std::size_t write(const ConstBufferSequence& buf);
  70. /// Synchronously flush the data to the supplied SyncWriteStream.
  71. /**
  72. * This call uses throwing semantics. ie. an exception will be thrown on
  73. * any failure.
  74. * If there is no error, the buffer is cleared.
  75. */
  76. template<typename SyncWriteStream>
  77. void flush(SyncWriteStream& sws);
  78. /// Put a character into the stream.
  79. self_type& put (char_type c);
  80. /// Synchronously flush the data via the supplied SyncWriteStream.
  81. /**
  82. * This call uses error_code semantics. ie. ec is set if an error occurs.
  83. * If there is no error, the buffer is cleared.
  84. */
  85. template<typename SyncWriteStream>
  86. boost::system::error_code
  87. flush(SyncWriteStream& sws, boost::system::error_code& ec);
  88. /// Synchronously send the data via the supplied request.
  89. /**
  90. * This call uses throwing semantics. ie. an exception will be thrown on
  91. * any failure.
  92. * Note: The data in the stream isn't cleared after this call.
  93. */
  94. template<typename SyncWriteStream>
  95. void send(SyncWriteStream& sws);
  96. /// Synchronously send the data via the supplied request.
  97. /**
  98. * This call will not throw, but will set `ec` such that `ec == true` if
  99. * an error occurs. Details of the error are held in the `error_code`
  100. * object.
  101. */
  102. template<typename SyncWriteStream>
  103. boost::system::error_code
  104. send(SyncWriteStream& sws, boost::system::error_code& ec);
  105. /// Resend headers + content regardless of value of `headers_terminated_`.
  106. template<typename SyncWriteStream>
  107. void resend(SyncWriteStream& sws);
  108. /// Asynchronously send the data through the supplied AsyncWriteStream.
  109. /**
  110. * Note: This is quite crude at the moment and not as asynchronous as
  111. * it could/should be. The data in the stream isn't cleared after
  112. * this call.
  113. */
  114. template<typename AsyncWriteStream, typename Handler>
  115. void async_send(AsyncWriteStream& aws, Handler handler);
  116. template<typename AsyncWriteStream, typename Handler>
  117. void do_async_send(AsyncWriteStream& aws, Handler handler);
  118. /// Get the buffer associated with the stream
  119. common::streambuf*
  120. rdbuf();
  121. /// Set the status code associated with the response.
  122. basic_response<char_type>&
  123. status(const http::status_code& num);
  124. /// Get the status code associated with the response.
  125. http::status_code status() const;
  126. /// Allow more headers to be added (WARNING: avoid using this).
  127. void unterminate_headers();
  128. /// Get the length of the body of the response (ie. not including the headers).
  129. std::size_t content_length();
  130. /// Add a header after appending the CRLF sequence.
  131. basic_response<char_type>&
  132. set(basic_header<char_type> const& hdr)
  133. {
  134. if (hdr.content.empty())
  135. end_headers();
  136. else
  137. set_header(hdr.content);
  138. return *this;
  139. }
  140. /// Add a cookie to the response.
  141. basic_response<char_type>&
  142. set(const basic_cookie<char_type>& ck)
  143. {
  144. set_header("Set-Cookie", ck.to_string());
  145. return *this;
  146. }
  147. /// Set a header give a string of the form "name=value".
  148. basic_response<char_type>&
  149. set_header(const string_type& value);
  150. /// Format and add a header given name and value, appending CRLF.
  151. basic_response<char_type>&
  152. set_header(string_type const& name, string_type const& value);
  153. /// Get the contents of the response as a string.
  154. /**
  155. * This copies the contents of the response into a string.
  156. * Headers aren't included unless `include_header` is true.
  157. */
  158. string_type str(bool include_header = false) const;
  159. /// Get the value of a header in this response with the name `name`.
  160. string_type header_value(string_type const& name);
  161. /// Returns true for existing header names.
  162. bool has_header_value(string_type const& name);
  163. /// Clear all of the response headers.
  164. void clear_headers();
  165. void reset_headers();
  166. /// Get the charset.
  167. string_type& charset() const { return charset_; }
  168. /// Set the charset.
  169. void charset(string_type const& cs) { charset_ = cs; }
  170. /// Check if more response headers may be added.
  171. bool headers_terminated() const;
  172. // Is this really necessary?
  173. void end_headers();
  174. /// Get the ostream containing the response body.
  175. ostream_type& ostream();
  176. /// Get the response headers.
  177. std::vector<string_type>& headers();
  178. /// Stream any type to the response.
  179. template<typename T>
  180. self_type& operator<<(T t)
  181. {
  182. ostream_<< t;
  183. return *this;
  184. }
  185. /// Change the charset of the response.
  186. self_type& operator<< (charset_header<char_type> const& hdr)
  187. {
  188. charset(hdr.content);
  189. return *this;
  190. }
  191. /// Add a header to the response.
  192. self_type& operator<< (basic_header<char_type> const& hdr)
  193. {
  194. return set(hdr);
  195. }
  196. /// Add a cookie to the response.
  197. self_type& operator<< (basic_cookie<char_type> const& ck)
  198. {
  199. return set(ck);
  200. }
  201. /// Set the HTTP status of the response.
  202. self_type& operator<< (http::status_code stat)
  203. {
  204. status(stat);
  205. return *this;
  206. }
  207. /// Copy another response into this response.
  208. /**
  209. * The body of the other response is appended to the body of this
  210. * response. The headers of the other response are added to this
  211. * response, except for the "Content-type" header. The content-type
  212. * of this response is assumed to be authoritative.
  213. */
  214. self_type& operator<< (self_type& other)
  215. {
  216. if (!headers_terminated())
  217. {
  218. typedef std::vector<std::string>::const_iterator iter_t;
  219. for(iter_t iter (other.headers().begin()), end (other.headers().end());
  220. iter != end;
  221. ++iter
  222. )
  223. {
  224. if (iter->substr(0,13) != "Content-type:") // Don't overwrite the content-type.
  225. headers_.push_back(*iter);
  226. }
  227. }
  228. ostream_<< other.ostream().rdbuf();
  229. return *this;
  230. }
  231. protected:
  232. // Vector of all the headers, each followed by a CRLF
  233. std::vector<string_type> headers_;
  234. // The buffer is a shared_ptr, so you can keep it cached elsewhere.
  235. boost::shared_ptr<common::streambuf> buffer_;
  236. ostream_type ostream_;
  237. http::status_code http_status_;
  238. // True if no more headers can be appended.
  239. bool headers_terminated_;
  240. string_type charset_;
  241. private:
  242. // Send the response headers and mark that they've been sent.
  243. template<typename ConstBufferSequence>
  244. void prepare_headers(ConstBufferSequence& headers);
  245. };
  246. /// Typedefs for typical usage.
  247. typedef basic_response<char> response;
  248. } // namespace common
  249. BOOST_CGI_NAMESPACE_END
  250. /// Generic ostream template
  251. /*
  252. template<typename CharT, typename T>
  253. BOOST_CGI_NAMESPACE::common::basic_response<CharT>&
  254. operator<< (BOOST_CGI_NAMESPACE::common::basic_response<CharT>& resp, T t);
  255. */
  256. /// You can stream a BOOST_CGI_NAMESPACE::cookie into a response.
  257. /**
  258. * This is just a shorthand way of setting a header that will set a
  259. * client-side cookie.
  260. *
  261. * You cannot stream a cookie to a response after the headers have been
  262. * terminated. In this case, an alternative could be to use the HTML tag:
  263. * <meta http-equiv="Set-cookie" ...> (see http://tinyurl.com/3bxftv or
  264. * http://tinyurl.com/33znkj), but this is outside the scope of this
  265. * library.
  266. */
  267. /*
  268. template<typename charT>
  269. BOOST_CGI_NAMESPACE::common::basic_response<charT>&
  270. operator<< (BOOST_CGI_NAMESPACE::common::basic_response<charT>&
  271. , BOOST_CGI_NAMESPACE::common::basic_cookie<charT>);
  272. */
  273. #include "boost/cgi/detail/pop_options.hpp"
  274. #if !defined(BOOST_CGI_BUILD_LIB)
  275. # include "boost/cgi/impl/response.ipp"
  276. #endif
  277. #endif // CGI_RESPONSE_HPP_INCLUDED__