diff options
Diffstat (limited to '')
-rw-r--r-- | src/nghttp.h | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/src/nghttp.h b/src/nghttp.h new file mode 100644 index 0000000..a880414 --- /dev/null +++ b/src/nghttp.h @@ -0,0 +1,310 @@ +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2015 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGHTTP_H +#define NGHTTP_H + +#include "nghttp2_config.h" + +#include <sys/types.h> +#ifdef HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#endif // HAVE_SYS_SOCKET_H +#ifdef HAVE_NETDB_H +# include <netdb.h> +#endif // HAVE_NETDB_H + +#include <string> +#include <vector> +#include <set> +#include <chrono> +#include <memory> + +#include <openssl/ssl.h> + +#include <ev.h> + +#include <nghttp2/nghttp2.h> + +#include "llhttp.h" + +#include "memchunk.h" +#include "http2.h" +#include "nghttp2_gzip.h" +#include "template.h" + +namespace nghttp2 { + +class HtmlParser; + +struct Config { + Config(); + ~Config(); + + Headers headers; + Headers trailer; + std::vector<int32_t> weight; + std::string certfile; + std::string keyfile; + std::string datafile; + std::string harfile; + std::string scheme_override; + std::string host_override; + nghttp2_option *http2_option; + int64_t header_table_size; + int64_t min_header_table_size; + int64_t encoder_header_table_size; + size_t padding; + size_t max_concurrent_streams; + ssize_t peer_max_concurrent_streams; + int multiply; + // milliseconds + ev_tstamp timeout; + int window_bits; + int connection_window_bits; + int verbose; + uint16_t port_override; + bool null_out; + bool remote_name; + bool get_assets; + bool stat; + bool upgrade; + bool continuation; + bool no_content_length; + bool no_dep; + bool hexdump; + bool no_push; + bool expect_continue; + bool verify_peer; + bool ktls; + bool no_rfc7540_pri; +}; + +enum class RequestState { INITIAL, ON_REQUEST, ON_RESPONSE, ON_COMPLETE }; + +struct RequestTiming { + // The point in time when request is started to be sent. + // Corresponds to requestStart in Resource Timing TR. + std::chrono::steady_clock::time_point request_start_time; + // The point in time when first byte of response is received. + // Corresponds to responseStart in Resource Timing TR. + std::chrono::steady_clock::time_point response_start_time; + // The point in time when last byte of response is received. + // Corresponds to responseEnd in Resource Timing TR. + std::chrono::steady_clock::time_point response_end_time; + RequestState state; + RequestTiming() : state(RequestState::INITIAL) {} +}; + +struct Request; // forward declaration for ContinueTimer + +struct ContinueTimer { + ContinueTimer(struct ev_loop *loop, Request *req); + ~ContinueTimer(); + + void start(); + void stop(); + + // Schedules an immediate run of the continue callback on the loop, if the + // callback has not already been run + void dispatch_continue(); + + struct ev_loop *loop; + ev_timer timer; +}; + +struct Request { + // For pushed request, |uri| is empty and |u| is zero-cleared. + Request(const std::string &uri, const http_parser_url &u, + const nghttp2_data_provider *data_prd, int64_t data_length, + const nghttp2_priority_spec &pri_spec, int level = 0); + ~Request(); + + void init_inflater(); + + void init_html_parser(); + int update_html_parser(const uint8_t *data, size_t len, int fin); + + std::string make_reqpath() const; + + bool is_ipv6_literal_addr() const; + + Headers::value_type *get_res_header(int32_t token); + Headers::value_type *get_req_header(int32_t token); + + void record_request_start_time(); + void record_response_start_time(); + void record_response_end_time(); + + // Returns scheme taking into account overridden scheme. + StringRef get_real_scheme() const; + // Returns request host, without port, taking into account + // overridden host. + StringRef get_real_host() const; + // Returns request port, taking into account overridden host, port, + // and scheme. + uint16_t get_real_port() const; + + Headers res_nva; + Headers req_nva; + std::string method; + // URI without fragment + std::string uri; + http_parser_url u; + nghttp2_priority_spec pri_spec; + RequestTiming timing; + int64_t data_length; + int64_t data_offset; + // Number of bytes received from server + int64_t response_len; + nghttp2_gzip *inflater; + std::unique_ptr<HtmlParser> html_parser; + const nghttp2_data_provider *data_prd; + size_t header_buffer_size; + int32_t stream_id; + int status; + // Recursion level: 0: first entity, 1: entity linked from first entity + int level; + http2::HeaderIndex res_hdidx; + // used for incoming PUSH_PROMISE + http2::HeaderIndex req_hdidx; + bool expect_final_response; + // only assigned if this request is using Expect/Continue + std::unique_ptr<ContinueTimer> continue_timer; +}; + +struct SessionTiming { + // The point in time when operation was started. Corresponds to + // startTime in Resource Timing TR, but recorded in system clock time. + std::chrono::system_clock::time_point system_start_time; + // Same as above, but recorded in steady clock time. + std::chrono::steady_clock::time_point start_time; + // The point in time when DNS resolution was completed. Corresponds + // to domainLookupEnd in Resource Timing TR. + std::chrono::steady_clock::time_point domain_lookup_end_time; + // The point in time when connection was established or SSL/TLS + // handshake was completed. Corresponds to connectEnd in Resource + // Timing TR. + std::chrono::steady_clock::time_point connect_end_time; +}; + +enum class ClientState { IDLE, CONNECTED }; + +struct HttpClient { + HttpClient(const nghttp2_session_callbacks *callbacks, struct ev_loop *loop, + SSL_CTX *ssl_ctx); + ~HttpClient(); + + bool need_upgrade() const; + int resolve_host(const std::string &host, uint16_t port); + int initiate_connection(); + void disconnect(); + + int noop(); + int read_clear(); + int write_clear(); + int connected(); + int tls_handshake(); + int read_tls(); + int write_tls(); + + int do_read(); + int do_write(); + + int on_upgrade_connect(); + int on_upgrade_read(const uint8_t *data, size_t len); + int on_read(const uint8_t *data, size_t len); + int on_write(); + + int connection_made(); + void connect_fail(); + void request_done(Request *req); + + void signal_write(); + + bool all_requests_processed() const; + void update_hostport(); + bool add_request(const std::string &uri, + const nghttp2_data_provider *data_prd, int64_t data_length, + const nghttp2_priority_spec &pri_spec, int level = 0); + + void record_start_time(); + void record_domain_lookup_end_time(); + void record_connect_end_time(); + +#ifdef HAVE_JANSSON + void output_har(FILE *outfile); +#endif // HAVE_JANSSON + + MemchunkPool mcpool; + DefaultMemchunks wb; + std::vector<std::unique_ptr<Request>> reqvec; + // Insert path already added in reqvec to prevent multiple request + // for 1 resource. + std::set<std::string> path_cache; + std::string scheme; + std::string host; + std::string hostport; + // Used for parse the HTTP upgrade response from server + std::unique_ptr<llhttp_t> htp; + SessionTiming timing; + ev_io wev; + ev_io rev; + ev_timer wt; + ev_timer rt; + ev_timer settings_timer; + std::function<int(HttpClient &)> readfn, writefn; + std::function<int(HttpClient &, const uint8_t *, size_t)> on_readfn; + std::function<int(HttpClient &)> on_writefn; + nghttp2_session *session; + const nghttp2_session_callbacks *callbacks; + struct ev_loop *loop; + SSL_CTX *ssl_ctx; + SSL *ssl; + addrinfo *addrs; + addrinfo *next_addr; + addrinfo *cur_addr; + // The number of completed requests, including failed ones. + size_t complete; + // The number of requests that local endpoint received END_STREAM + // from peer. + size_t success; + // The length of settings_payload + size_t settings_payloadlen; + ClientState state; + // The HTTP status code of the response message of HTTP Upgrade. + unsigned int upgrade_response_status_code; + int fd; + // true if the response message of HTTP Upgrade request is fully + // received. It is not relevant the upgrade succeeds, or not. + bool upgrade_response_complete; + // SETTINGS payload sent as token68 in HTTP Upgrade + std::array<uint8_t, 128> settings_payload; + + enum { ERR_CONNECT_FAIL = -100 }; +}; + +} // namespace nghttp2 + +#endif // NGHTTP_H |