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