PageRenderTime 40ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/boost/cgi/basic_client.hpp

http://github.com/darrengarvey/cgi
C++ Header | 253 lines | 145 code | 35 blank | 73 comment | 3 complexity | 07b08bf7132bbf31796ef4b8b3878eab MD5 | raw file
  1. // -- basic_client.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_BASIC_CLIENT_HPP_INCLUDED__
  10. #define CGI_BASIC_CLIENT_HPP_INCLUDED__
  11. #include <boost/shared_ptr.hpp>
  12. ///////////////////////////////////////////////////////////
  13. #include "boost/cgi/common/map.hpp"
  14. #include "boost/cgi/common/protocol_traits.hpp"
  15. #include "boost/cgi/common/role_type.hpp"
  16. #include "boost/cgi/common/request_status.hpp"
  17. #if defined(BOOST_WINDOWS)
  18. # include "boost/cgi/fcgi/fcgi_connection.hpp"
  19. #else
  20. # include "boost/cgi/connections/tcp_socket.hpp"
  21. #endif // defined(BOOST_WINDOWS)
  22. #include "boost/cgi/detail/throw_error.hpp"
  23. #include "boost/cgi/error.hpp"
  24. #include "boost/cgi/http/status_code.hpp"
  25. BOOST_CGI_NAMESPACE_BEGIN
  26. namespace common {
  27. enum client_status
  28. {
  29. none_, // **FIXME** !
  30. constructed,
  31. params_read,
  32. stdin_read,
  33. end_request_sent,
  34. closed_, // **FIXME** !
  35. //aborted
  36. };
  37. /// A client
  38. /**
  39. * A client is for two things:
  40. * 1. To hold a full-duplex connection (or separate input and output
  41. * connections).
  42. * 2. To hold any protocol-specific data about the request. For now,
  43. * this means the internal 'request number' associated by FastCGI
  44. * with each request (ie. so incoming/outgoing packets can be wrapped
  45. * with data noting what request it relates to).
  46. * 3. Buffering. Not sure about how far this should go yet, but probably
  47. * no further than minimal buffering.
  48. * 4. Share a connection. Since a multiplexing connection is shared between
  49. * multiple clients, the client should be responsible for taking possesion
  50. * of the connection for a period of time (so it can write a complete
  51. * packet). This idea could be taken quite far into genericity by making
  52. * clients aware of how busy the connection is and size its output packets
  53. * accordingly... But I'm not doing that.
  54. */
  55. template<typename Protocol>
  56. class basic_client
  57. {
  58. public:
  59. typedef Protocol protocol_type;
  60. typedef common::map map_type;
  61. typedef protocol_traits<Protocol> traits;
  62. typedef typename traits::connection_type connection_type;
  63. typedef typename traits::mutable_buffers_type mutable_buffers_type;
  64. typedef typename traits::header_buffer_type header_buffer_type;
  65. typedef typename connection_type::pointer connection_ptr;
  66. basic_client()
  67. {
  68. }
  69. /// Construct the client by claiming a request id.
  70. /**
  71. * Before loading a request, it will usually not have a request id. This
  72. * function reads headers (and corresponding bodies if necessary) until
  73. * a BEGIN_REQUEST record is found. The calling request then claims and
  74. * serves that request.
  75. */
  76. template<typename RequestImpl>
  77. boost::system::error_code
  78. construct(RequestImpl& req, boost::system::error_code& ec)
  79. {
  80. status_ = constructed;
  81. return ec;
  82. }
  83. boost::system::error_code
  84. close(boost::uint64_t app_status, boost::system::error_code& ec)
  85. {
  86. if (!is_open())
  87. ec = error::already_closed;
  88. else
  89. {
  90. status_ = closed_;
  91. connection_->close();
  92. }
  93. return ec;
  94. }
  95. void close(boost::uint64_t app_status = 0)
  96. {
  97. boost::system::error_code ec;
  98. close(app_status, ec);
  99. detail::throw_error(ec);
  100. }
  101. /// Associate a connection with this client
  102. /**
  103. * Note: the connection must have been created using the new operator
  104. */
  105. bool set_connection(connection_type* conn)
  106. {
  107. connection_.reset(conn);
  108. return true;
  109. }
  110. //io_service& io_service() { return io_service_; }
  111. /// Associate a connection with this client
  112. /**
  113. * Note: the connection must have been created using the new operator
  114. */
  115. bool set_connection(const typename connection_type::pointer& conn)
  116. {
  117. connection_ = conn;
  118. return true;
  119. }
  120. /// Write some data to the client.
  121. template<typename ConstBufferSequence>
  122. std::size_t write_some(const ConstBufferSequence& buf
  123. , boost::system::error_code& ec)
  124. {
  125. return connection_->write_some(buf, ec);
  126. }
  127. /// Read data into the supplied buffer.
  128. /**
  129. * Reads some data that, correctly checking and stripping FastCGI headers.
  130. *
  131. * Returns the number of bytes read and sets `ec` such that `ec` evaluates
  132. * to `true` iff an error occured during the read operation.
  133. *
  134. * Notable errors:
  135. * - `fcgi::error::data_for_another_request`
  136. * - `fcgi::error::connection_locked`
  137. *
  138. * These must be dealt with by user code if they choose to read through the
  139. * client (reading through the request is recommended).
  140. */
  141. template<typename MutableBufferSequence>
  142. std::size_t read_some(const MutableBufferSequence& buf
  143. , boost::system::error_code& ec)
  144. {
  145. std::size_t bytes_read = connection_->read_some(buf, ec);
  146. bytes_left_ -= bytes_read;
  147. if (ec == boost::asio::error::eof)
  148. ec = boost::system::error_code();
  149. return bytes_left_ > 0 ? bytes_read : (bytes_read + bytes_left_);
  150. }
  151. /// Asynchronously write some data to the client.
  152. template<typename ConstBufferSequence, typename Handler>
  153. void async_write_some(const ConstBufferSequence& buf, Handler handler)
  154. {
  155. connection_->async_write_some(buf, handler);
  156. }
  157. /// Asynchronously read some data from the client.
  158. template<typename MutableBufferSequence, typename Handler>
  159. void async_read_some(const MutableBufferSequence& buf, Handler handler)
  160. {
  161. connection_->async_read_some(buf, handler);
  162. }
  163. ////// Querying the client.
  164. /// Get a shared_ptr of the connection associated with the client.
  165. connection_ptr& connection() { return connection_; }
  166. std::size_t& bytes_left() { return bytes_left_; }
  167. bool is_open()
  168. {
  169. return connection_->is_open();
  170. }
  171. /// Get the status of the client.
  172. const client_status& status() const
  173. {
  174. return status_;
  175. }
  176. /// Set the status of the client.
  177. void status(client_status status)
  178. {
  179. status_ = status;
  180. }
  181. bool keep_connection() const
  182. {
  183. return keep_connection_;
  184. }
  185. boost::uint16_t const& request_id() const
  186. {
  187. return request_id_;
  188. }
  189. private:
  190. template<typename ConstBufferSequence>
  191. void prepare_buffer(const ConstBufferSequence& buf)
  192. { /* NOOP */ }
  193. void handle_write(
  194. std::size_t bytes_transferred, boost::system::error_code& ec)
  195. { /* NOOP */ }
  196. //io_service& io_service_;
  197. connection_ptr connection_;
  198. public: // **FIXME**
  199. // we should never read more than content-length bytes.
  200. std::size_t bytes_left_;
  201. boost::uint16_t request_id_;
  202. client_status status_;
  203. boost::uint64_t total_sent_bytes_;
  204. boost::uint64_t total_sent_packets_;
  205. /// Buffer used to check the header of each packet.
  206. fcgi::spec::header header_;
  207. /// Output buffer.
  208. /**
  209. * This doesn't take ownership of the underlying memory, so the
  210. * data must remain valid until it has been completely written.
  211. */
  212. std::vector<boost::asio::const_buffer> outbuf_;
  213. bool keep_connection_;
  214. common::role_type role_;
  215. };
  216. } // namespace common
  217. BOOST_CGI_NAMESPACE_END
  218. #endif // CGI_BASIC_CLIENT_HPP_INCLUDED__