• 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 "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