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