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 ASIO_SERVER_HTTP2_HANDLER_H 26 #define ASIO_SERVER_HTTP2_HANDLER_H 27 28 #include "nghttp2_config.h" 29 30 #include <map> 31 #include <functional> 32 #include <string> 33 34 #include <boost/array.hpp> 35 36 #include <nghttp2/asio_http2_server.h> 37 38 namespace nghttp2 { 39 namespace asio_http2 { 40 namespace server { 41 42 class http2_handler; 43 class stream; 44 class serve_mux; 45 46 struct callback_guard { 47 callback_guard(http2_handler &h); 48 ~callback_guard(); 49 http2_handler &handler; 50 }; 51 52 using connection_write = std::function<void(void)>; 53 54 class http2_handler : public std::enable_shared_from_this<http2_handler> { 55 public: 56 http2_handler(boost::asio::io_service &io_service, 57 boost::asio::ip::tcp::endpoint ep, connection_write writefun, 58 serve_mux &mux); 59 60 ~http2_handler(); 61 62 int start(); 63 64 stream *create_stream(int32_t stream_id); 65 void close_stream(int32_t stream_id); 66 stream *find_stream(int32_t stream_id); 67 68 void call_on_request(stream &s); 69 70 bool should_stop() const; 71 72 int start_response(stream &s); 73 74 int submit_trailer(stream &s, header_map h); 75 76 void stream_error(int32_t stream_id, uint32_t error_code); 77 78 void initiate_write(); 79 80 void enter_callback(); 81 void leave_callback(); 82 83 void resume(stream &s); 84 85 response *push_promise(boost::system::error_code &ec, stream &s, 86 std::string method, std::string raw_path_query, 87 header_map h); 88 89 void signal_write(); 90 91 boost::asio::io_service &io_service(); 92 93 const boost::asio::ip::tcp::endpoint &remote_endpoint(); 94 95 const std::string &http_date(); 96 97 template <size_t N> on_read(const boost::array<uint8_t,N> & buffer,std::size_t len)98 int on_read(const boost::array<uint8_t, N> &buffer, std::size_t len) { 99 callback_guard cg(*this); 100 101 int rv; 102 103 rv = nghttp2_session_mem_recv(session_, buffer.data(), len); 104 105 if (rv < 0) { 106 return -1; 107 } 108 109 return 0; 110 } 111 112 template <size_t N> on_write(boost::array<uint8_t,N> & buffer,std::size_t & len)113 int on_write(boost::array<uint8_t, N> &buffer, std::size_t &len) { 114 callback_guard cg(*this); 115 116 len = 0; 117 118 if (buf_) { 119 std::copy_n(buf_, buflen_, std::begin(buffer)); 120 121 len += buflen_; 122 123 buf_ = nullptr; 124 buflen_ = 0; 125 } 126 127 for (;;) { 128 const uint8_t *data; 129 auto nread = nghttp2_session_mem_send(session_, &data); 130 if (nread < 0) { 131 return -1; 132 } 133 134 if (nread == 0) { 135 break; 136 } 137 138 if (len + nread > buffer.size()) { 139 buf_ = data; 140 buflen_ = nread; 141 142 break; 143 } 144 145 std::copy_n(data, nread, std::begin(buffer) + len); 146 147 len += nread; 148 } 149 150 return 0; 151 } 152 153 private: 154 std::map<int32_t, std::shared_ptr<stream>> streams_; 155 connection_write writefun_; 156 serve_mux &mux_; 157 boost::asio::io_service &io_service_; 158 boost::asio::ip::tcp::endpoint remote_ep_; 159 nghttp2_session *session_; 160 const uint8_t *buf_; 161 std::size_t buflen_; 162 bool inside_callback_; 163 // true if we have pending on_write call. This avoids repeated call 164 // of io_service::post. 165 bool write_signaled_; 166 time_t tstamp_cached_; 167 std::string formatted_date_; 168 }; 169 170 } // namespace server 171 } // namespace asio_http2 172 } // namespace nghttp2 173 174 #endif // ASIO_SERVER_HTTP2_HANDLER_H 175