1 /* 2 * nghttp2 - HTTP/2 C Library 3 * 4 * Copyright (c) 2015 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 NGHTTP_H 26 #define NGHTTP_H 27 28 #include "nghttp2_config.h" 29 30 #include <sys/types.h> 31 #ifdef HAVE_SYS_SOCKET_H 32 # include <sys/socket.h> 33 #endif // HAVE_SYS_SOCKET_H 34 #ifdef HAVE_NETDB_H 35 # include <netdb.h> 36 #endif // HAVE_NETDB_H 37 38 #include <string> 39 #include <vector> 40 #include <set> 41 #include <chrono> 42 #include <memory> 43 44 #include "ssl_compat.h" 45 46 #ifdef NGHTTP2_OPENSSL_IS_WOLFSSL 47 # include <wolfssl/options.h> 48 # include <wolfssl/openssl/ssl.h> 49 #else // !NGHTTP2_OPENSSL_IS_WOLFSSL 50 # include <openssl/ssl.h> 51 #endif // !NGHTTP2_OPENSSL_IS_WOLFSSL 52 53 #include <ev.h> 54 55 #define NGHTTP2_NO_SSIZE_T 56 #include <nghttp2/nghttp2.h> 57 58 #include "llhttp.h" 59 60 #include "memchunk.h" 61 #include "http2.h" 62 #include "nghttp2_gzip.h" 63 #include "template.h" 64 65 namespace nghttp2 { 66 67 class HtmlParser; 68 69 struct Config { 70 Config(); 71 ~Config(); 72 73 Headers headers; 74 Headers trailer; 75 std::vector<int32_t> weight; 76 std::string certfile; 77 std::string keyfile; 78 std::string datafile; 79 std::string harfile; 80 std::string scheme_override; 81 std::string host_override; 82 nghttp2_option *http2_option; 83 int64_t header_table_size; 84 int64_t min_header_table_size; 85 int64_t encoder_header_table_size; 86 size_t padding; 87 size_t max_concurrent_streams; 88 size_t peer_max_concurrent_streams; 89 int multiply; 90 // milliseconds 91 ev_tstamp timeout; 92 int window_bits; 93 int connection_window_bits; 94 int verbose; 95 uint16_t port_override; 96 bool null_out; 97 bool remote_name; 98 bool get_assets; 99 bool stat; 100 bool upgrade; 101 bool continuation; 102 bool no_content_length; 103 bool no_dep; 104 bool hexdump; 105 bool no_push; 106 bool expect_continue; 107 bool verify_peer; 108 bool ktls; 109 bool no_rfc7540_pri; 110 }; 111 112 enum class RequestState { INITIAL, ON_REQUEST, ON_RESPONSE, ON_COMPLETE }; 113 114 struct RequestTiming { 115 // The point in time when request is started to be sent. 116 // Corresponds to requestStart in Resource Timing TR. 117 std::chrono::steady_clock::time_point request_start_time; 118 // The point in time when first byte of response is received. 119 // Corresponds to responseStart in Resource Timing TR. 120 std::chrono::steady_clock::time_point response_start_time; 121 // The point in time when last byte of response is received. 122 // Corresponds to responseEnd in Resource Timing TR. 123 std::chrono::steady_clock::time_point response_end_time; 124 RequestState state; RequestTimingRequestTiming125 RequestTiming() : state(RequestState::INITIAL) {} 126 }; 127 128 struct Request; // forward declaration for ContinueTimer 129 130 struct ContinueTimer { 131 ContinueTimer(struct ev_loop *loop, Request *req); 132 ~ContinueTimer(); 133 134 void start(); 135 void stop(); 136 137 // Schedules an immediate run of the continue callback on the loop, if the 138 // callback has not already been run 139 void dispatch_continue(); 140 141 struct ev_loop *loop; 142 ev_timer timer; 143 }; 144 145 struct Request { 146 // For pushed request, |uri| is empty and |u| is zero-cleared. 147 Request(const std::string &uri, const http_parser_url &u, 148 const nghttp2_data_provider2 *data_prd, int64_t data_length, 149 const nghttp2_priority_spec &pri_spec, int level = 0); 150 ~Request(); 151 152 void init_inflater(); 153 154 void init_html_parser(); 155 int update_html_parser(const uint8_t *data, size_t len, int fin); 156 157 std::string make_reqpath() const; 158 159 bool is_ipv6_literal_addr() const; 160 161 Headers::value_type *get_res_header(int32_t token); 162 Headers::value_type *get_req_header(int32_t token); 163 164 void record_request_start_time(); 165 void record_response_start_time(); 166 void record_response_end_time(); 167 168 // Returns scheme taking into account overridden scheme. 169 StringRef get_real_scheme() const; 170 // Returns request host, without port, taking into account 171 // overridden host. 172 StringRef get_real_host() const; 173 // Returns request port, taking into account overridden host, port, 174 // and scheme. 175 uint16_t get_real_port() const; 176 177 Headers res_nva; 178 Headers req_nva; 179 std::string method; 180 // URI without fragment 181 std::string uri; 182 http_parser_url u; 183 nghttp2_priority_spec pri_spec; 184 RequestTiming timing; 185 int64_t data_length; 186 int64_t data_offset; 187 // Number of bytes received from server 188 int64_t response_len; 189 nghttp2_gzip *inflater; 190 std::unique_ptr<HtmlParser> html_parser; 191 const nghttp2_data_provider2 *data_prd; 192 size_t header_buffer_size; 193 int32_t stream_id; 194 int status; 195 // Recursion level: 0: first entity, 1: entity linked from first entity 196 int level; 197 http2::HeaderIndex res_hdidx; 198 // used for incoming PUSH_PROMISE 199 http2::HeaderIndex req_hdidx; 200 bool expect_final_response; 201 // only assigned if this request is using Expect/Continue 202 std::unique_ptr<ContinueTimer> continue_timer; 203 }; 204 205 struct SessionTiming { 206 // The point in time when operation was started. Corresponds to 207 // startTime in Resource Timing TR, but recorded in system clock time. 208 std::chrono::system_clock::time_point system_start_time; 209 // Same as above, but recorded in steady clock time. 210 std::chrono::steady_clock::time_point start_time; 211 // The point in time when DNS resolution was completed. Corresponds 212 // to domainLookupEnd in Resource Timing TR. 213 std::chrono::steady_clock::time_point domain_lookup_end_time; 214 // The point in time when connection was established or SSL/TLS 215 // handshake was completed. Corresponds to connectEnd in Resource 216 // Timing TR. 217 std::chrono::steady_clock::time_point connect_end_time; 218 }; 219 220 enum class ClientState { IDLE, CONNECTED }; 221 222 struct HttpClient { 223 HttpClient(const nghttp2_session_callbacks *callbacks, struct ev_loop *loop, 224 SSL_CTX *ssl_ctx); 225 ~HttpClient(); 226 227 bool need_upgrade() const; 228 int resolve_host(const std::string &host, uint16_t port); 229 int initiate_connection(); 230 void disconnect(); 231 232 int noop(); 233 int read_clear(); 234 int write_clear(); 235 int connected(); 236 int tls_handshake(); 237 int read_tls(); 238 int write_tls(); 239 240 int do_read(); 241 int do_write(); 242 243 int on_upgrade_connect(); 244 int on_upgrade_read(const uint8_t *data, size_t len); 245 int on_read(const uint8_t *data, size_t len); 246 int on_write(); 247 248 int connection_made(); 249 void connect_fail(); 250 void request_done(Request *req); 251 252 void signal_write(); 253 254 bool all_requests_processed() const; 255 void update_hostport(); 256 bool add_request(const std::string &uri, 257 const nghttp2_data_provider2 *data_prd, int64_t data_length, 258 const nghttp2_priority_spec &pri_spec, int level = 0); 259 260 void record_start_time(); 261 void record_domain_lookup_end_time(); 262 void record_connect_end_time(); 263 264 #ifdef HAVE_JANSSON 265 void output_har(FILE *outfile); 266 #endif // HAVE_JANSSON 267 268 MemchunkPool mcpool; 269 DefaultMemchunks wb; 270 std::vector<std::unique_ptr<Request>> reqvec; 271 // Insert path already added in reqvec to prevent multiple request 272 // for 1 resource. 273 std::set<std::string> path_cache; 274 std::string scheme; 275 std::string host; 276 std::string hostport; 277 // Used for parse the HTTP upgrade response from server 278 std::unique_ptr<llhttp_t> htp; 279 SessionTiming timing; 280 ev_io wev; 281 ev_io rev; 282 ev_timer wt; 283 ev_timer rt; 284 ev_timer settings_timer; 285 std::function<int(HttpClient &)> readfn, writefn; 286 std::function<int(HttpClient &, const uint8_t *, size_t)> on_readfn; 287 std::function<int(HttpClient &)> on_writefn; 288 nghttp2_session *session; 289 const nghttp2_session_callbacks *callbacks; 290 struct ev_loop *loop; 291 SSL_CTX *ssl_ctx; 292 SSL *ssl; 293 addrinfo *addrs; 294 addrinfo *next_addr; 295 addrinfo *cur_addr; 296 // The number of completed requests, including failed ones. 297 size_t complete; 298 // The number of requests that local endpoint received END_STREAM 299 // from peer. 300 size_t success; 301 // The length of settings_payload 302 size_t settings_payloadlen; 303 ClientState state; 304 // The HTTP status code of the response message of HTTP Upgrade. 305 unsigned int upgrade_response_status_code; 306 int fd; 307 // true if the response message of HTTP Upgrade request is fully 308 // received. It is not relevant the upgrade succeeds, or not. 309 bool upgrade_response_complete; 310 // SETTINGS payload sent as token68 in HTTP Upgrade 311 std::array<uint8_t, 128> settings_payload; 312 313 enum { ERR_CONNECT_FAIL = -100 }; 314 }; 315 316 } // namespace nghttp2 317 318 #endif // NGHTTP_H 319