tizen 2.4 release
[external/nghttp2.git] / src / asio_http2_handler.h
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2014 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #ifndef HTTP2_HANDLER_H
26 #define HTTP2_HANDLER_H
27
28 #include "nghttp2_config.h"
29
30 #include <map>
31 #include <vector>
32 #include <functional>
33 #include <string>
34 #include <boost/array.hpp>
35 #include <boost/asio.hpp>
36
37 #include <nghttp2/nghttp2.h>
38
39 #include <nghttp2/asio_http2.h>
40
41 namespace nghttp2 {
42 namespace asio_http2 {
43
44 class channel_impl {
45 public:
46   channel_impl();
47   void post(void_cb cb);
48   void strand(boost::asio::io_service::strand *strand);
49
50 private:
51   boost::asio::io_service::strand *strand_;
52 };
53
54 namespace server {
55
56 class http2_handler;
57 class http2_stream;
58
59 class request_impl {
60 public:
61   request_impl();
62
63   const std::vector<header> &headers() const;
64   const std::string &method() const;
65   const std::string &scheme() const;
66   const std::string &authority() const;
67   const std::string &host() const;
68   const std::string &path() const;
69
70   bool push(std::string method, std::string path,
71             std::vector<header> headers = {});
72
73   bool pushed() const;
74   bool closed() const;
75
76   void on_data(data_cb cb);
77   void on_end(void_cb cb);
78
79   bool run_task(thread_cb start);
80
81   void set_header(std::vector<header> headers);
82   void add_header(std::string name, std::string value);
83   void method(std::string method);
84   void scheme(std::string scheme);
85   void authority(std::string authority);
86   void host(std::string host);
87   void path(std::string path);
88   void pushed(bool f);
89   void handler(std::weak_ptr<http2_handler> h);
90   void stream(std::weak_ptr<http2_stream> s);
91   void call_on_data(const uint8_t *data, std::size_t len);
92   void call_on_end();
93
94 private:
95   std::vector<header> headers_;
96   std::string method_;
97   std::string scheme_;
98   std::string authority_;
99   std::string host_;
100   std::string path_;
101   data_cb on_data_cb_;
102   void_cb on_end_cb_;
103   std::weak_ptr<http2_handler> handler_;
104   std::weak_ptr<http2_stream> stream_;
105   bool pushed_;
106 };
107
108 class response_impl {
109 public:
110   response_impl();
111   void write_head(unsigned int status_code, std::vector<header> headers = {});
112   void end(std::string data = "");
113   void end(read_cb cb);
114   void resume();
115   bool closed() const;
116
117   unsigned int status_code() const;
118   const std::vector<header> &headers() const;
119   bool started() const;
120   void handler(std::weak_ptr<http2_handler> h);
121   void stream(std::weak_ptr<http2_stream> s);
122   read_cb::result_type call_read(uint8_t *data, std::size_t len);
123
124 private:
125   std::vector<header> headers_;
126   read_cb read_cb_;
127   std::weak_ptr<http2_handler> handler_;
128   std::weak_ptr<http2_stream> stream_;
129   unsigned int status_code_;
130   bool started_;
131 };
132
133 class http2_stream {
134 public:
135   http2_stream(int32_t stream_id);
136
137   int32_t get_stream_id() const;
138   const std::shared_ptr<request> &get_request();
139   const std::shared_ptr<response> &get_response();
140
141 private:
142   std::shared_ptr<request> request_;
143   std::shared_ptr<response> response_;
144   int32_t stream_id_;
145 };
146
147 struct callback_guard {
148   callback_guard(http2_handler &h);
149   ~callback_guard();
150   http2_handler &handler;
151 };
152
153 typedef std::function<void(void)> connection_write;
154
155 class http2_handler : public std::enable_shared_from_this<http2_handler> {
156 public:
157   http2_handler(boost::asio::io_service &io_service,
158                 boost::asio::io_service &task_io_service,
159                 connection_write writefun, request_cb cb);
160
161   ~http2_handler();
162
163   int start();
164
165   std::shared_ptr<http2_stream> create_stream(int32_t stream_id);
166   void close_stream(int32_t stream_id);
167   std::shared_ptr<http2_stream> find_stream(int32_t stream_id);
168
169   void call_on_request(http2_stream &stream);
170
171   bool should_stop() const;
172
173   int start_response(http2_stream &stream);
174
175   void stream_error(int32_t stream_id, uint32_t error_code);
176
177   void initiate_write();
178
179   void enter_callback();
180   void leave_callback();
181   bool inside_callback() const;
182
183   void resume(http2_stream &stream);
184
185   int push_promise(http2_stream &stream, std::string method, std::string path,
186                    std::vector<header> headers);
187
188   bool run_task(thread_cb start);
189
190   boost::asio::io_service &io_service();
191
192   template <size_t N>
193   int on_read(const boost::array<uint8_t, N> &buffer, std::size_t len) {
194     callback_guard cg(*this);
195
196     int rv;
197
198     rv = nghttp2_session_mem_recv(session_, buffer.data(), len);
199
200     if (rv < 0) {
201       return -1;
202     }
203
204     return 0;
205   }
206
207   template <size_t N>
208   int on_write(boost::array<uint8_t, N> &buffer, std::size_t &len) {
209     callback_guard cg(*this);
210
211     len = 0;
212
213     if (buf_) {
214       std::copy_n(buf_, buflen_, std::begin(buffer));
215
216       len += buflen_;
217
218       buf_ = nullptr;
219       buflen_ = 0;
220     }
221
222     for (;;) {
223       const uint8_t *data;
224       auto nread = nghttp2_session_mem_send(session_, &data);
225       if (nread < 0) {
226         return -1;
227       }
228
229       if (nread == 0) {
230         break;
231       }
232
233       if (len + nread > buffer.size()) {
234         buf_ = data;
235         buflen_ = nread;
236
237         break;
238       }
239
240       std::copy_n(data, nread, std::begin(buffer) + len);
241
242       len += nread;
243     }
244
245     return 0;
246   }
247
248 private:
249   std::map<int32_t, std::shared_ptr<http2_stream>> streams_;
250   connection_write writefun_;
251   request_cb request_cb_;
252   boost::asio::io_service &io_service_;
253   boost::asio::io_service &task_io_service_;
254   std::shared_ptr<boost::asio::io_service::strand> strand_;
255   nghttp2_session *session_;
256   const uint8_t *buf_;
257   std::size_t buflen_;
258   bool inside_callback_;
259 };
260
261 } // namespace server
262 } // namespace asio_http2
263 } // namespace nghttp
264
265 #endif // HTTP2_HANDLER_H