1 // This may look like C code, but it's really -*- C++ -*-
2 /*
3  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
4  *
5  * All rights reserved.
6  */
7 //
8 // connection.hpp
9 // ~~~~~~~~~~~~~~
10 //
11 // Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com)
12 //
13 // Distributed under the Boost Software License, Version 1.0. (See accompanying
14 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
15 //
16 
17 #ifndef HTTP_CONNECTION_HPP
18 #define HTTP_CONNECTION_HPP
19 
20 #include <Wt/AsioWrapper/asio.hpp>
21 #include <Wt/AsioWrapper/strand.hpp>
22 #include <Wt/AsioWrapper/steady_timer.hpp>
23 
24 #include "Buffer.h"
25 #include "Reply.h"
26 #include "Request.h"
27 #include "RequestHandler.h"
28 #include "RequestParser.h"
29 
30 #include "Wt/WFlags.h"
31 
32 namespace http {
33 namespace server {
34 
35 namespace asio = Wt::AsioWrapper::asio;
36 
37 class ConnectionManager;
38 class Server;
39 
40 /// Represents a single connection from a client.
41 class Connection : public std::enable_shared_from_this<Connection>
42 {
43 public:
44   /// Construct a connection with the given io_service.
45   Connection(asio::io_service& io_service, Server *server,
46 	     ConnectionManager& manager, RequestHandler& handler);
47 
48   Connection(const Connection& other) = delete;
49 
50   /// Get the socket associated with the connection.
51   virtual asio::ip::tcp::socket& socket() = 0;
52 
53   /// Start the first asynchronous operation for the connection.
54   virtual void start();
55 
56   void close();
57   bool closed() const;
58 
59   /// Like CGI's Url scheme: http or https
60   virtual const char *urlScheme() = 0;
61 
62   virtual ~Connection();
63 
server()64   Server *server() const { return server_; }
strand()65   Wt::AsioWrapper::strand& strand() { return strand_; }
66 
67   /// Stop all asynchronous operations associated with the connection.
68   void scheduleStop();
69 
70 #ifdef HTTP_WITH_SSL
registerSslHandle(SSL * ssl)71   void registerSslHandle(SSL *ssl) { request_.ssl = ssl; }
72 #endif
73 
waitingResponse()74   bool waitingResponse() const { return waitingResponse_; }
setHaveResponse()75   void setHaveResponse() { haveResponse_ = true; }
76   void startWriteResponse(ReplyPtr reply);
77 
78   void handleReadBody(ReplyPtr reply);
79   void readMore(ReplyPtr reply, int timeout);
80   bool readAvailable();
81 
82   // NOTE: detectDisconnect will only register one callback at a time,
83   //       further calls to detectDisconnect are ignored
84   void detectDisconnect(ReplyPtr reply,
85 			const std::function<void()>& callback);
86   void asyncDetectDisconnect(ReplyPtr reply,
87 			     const std::function<void()>& callback);
88 
89 protected:
90   /// Get the native handle of the socket
91 #if (defined(WT_ASIO_IS_BOOST_ASIO) && BOOST_VERSION >= 106600) || (defined(WT_ASIO_IS_STANDALONE_ASIO) && ASIO_VERSION >= 101100)
92   asio::ip::tcp::socket::native_handle_type native();
93 #else
94   asio::ip::tcp::socket::native_type native();
95 #endif
96 
97   void handleWriteResponse0(ReplyPtr reply,
98                             const Wt::AsioWrapper::error_code& e,
99 			    std::size_t bytes_transferred);
100   void handleWriteResponse(ReplyPtr reply);
101   void handleReadRequest(const Wt::AsioWrapper::error_code& e,
102 			 std::size_t bytes_transferred);
103   /// Process read buffer, reading request.
104   void handleReadRequest0();
105   void handleReadBody0(ReplyPtr reply,
106                        const Wt::AsioWrapper::error_code& e,
107 		       std::size_t bytes_transferred);
108 
109   void setReadTimeout(int seconds);
110   void setWriteTimeout(int seconds);
111 
112   /// The manager for this connection.
113   ConnectionManager& ConnectionManager_;
114 
115   Wt::AsioWrapper::strand strand_;
116 
117   void finishReply();
118 
119   enum State {
120     Idle = 0x0,
121     Reading = 0x1,
122     Writing = 0x2
123   };
124 
125   Wt::WFlags<State> state_;
126 
127   virtual void stop();
128 
129 private:
130   /*
131    * Asynchronoulsy reading a request
132    */
133   virtual void startAsyncReadRequest(Buffer& buffer, int timeout) = 0;
134 
135   /*
136    * Asynchronoulsy reading a request body
137    */
138   virtual void startAsyncReadBody(ReplyPtr reply, Buffer& buffer,
139 				  int timeout) = 0;
140 
141   /*
142    * Asynchronoulsy writing a response
143    */
144   virtual void startAsyncWriteResponse(ReplyPtr reply,
145                               const std::vector<asio::const_buffer>& buffers,
146 				       int timeout) = 0;
147 
148   /// Generic I/O error handling: closes the connection and cancels timers
149   void handleError(const Wt::AsioWrapper::error_code& e);
150 
151   void sendStockReply(Reply::status_type code);
152 
153   /// The handler used to process the incoming request.
154   RequestHandler& request_handler_;
155 
156   void cancelReadTimer();
157   void cancelWriteTimer();
158 
159   void timeout(const Wt::AsioWrapper::error_code& e);
160   void doTimeout();
161 
162   /// Timer for reading data.
163   asio::steady_timer readTimer_, writeTimer_;
164 
165   /// Current request buffer data
166   std::list<Buffer> rcv_buffers_;
167 
168   /// Size of last buffer and iterator for next request in last buffer
169   std::size_t rcv_buffer_size_;
170   char *rcv_remaining_;
171   bool rcv_body_buffer_;
172 
173   /// The incoming request.
174   Request request_;
175 
176   /// The parser for the incoming request.
177   RequestParser request_parser_;
178 
179   /// Recycled reply pointers
180   ReplyPtr lastWtReply_, lastProxyReply_, lastStaticReply_;
181 
182   /// The server that owns this connection
183   Server *server_;
184 
185   /// Indicates that we're waiting for a response while invoking a
186   /// Reply function and thus that Reply function should not start a
187   /// write response but simply indicate haveResponse_
188   bool waitingResponse_;
189 
190   /// Indicates that we can send a response
191   bool haveResponse_;
192 
193   /// Indicates that the current response is finished (after the
194   /// current write operation)
195   bool responseDone_;
196 
197   std::function<void()> disconnectCallback_;
198 };
199 
200 typedef std::shared_ptr<Connection> ConnectionPtr;
201 
202 } // namespace server
203 } // namespace http
204 
205 #endif // HTTP_CONNECTION_HPP
206