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