• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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