#ifndef NGHTTP_H
#define NGHTTP_H
#include "nghttp2_config.h"
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif #ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
#include <string>
#include <vector>
#include <unordered_set>
#include <chrono>
#include <memory>
#include "ssl_compat.h"
#ifdef NGHTTP2_OPENSSL_IS_WOLFSSL
# include <wolfssl/options.h>
# include <wolfssl/openssl/ssl.h>
#else
# include <openssl/ssl.h>
#endif
#include <ev.h>
#define NGHTTP2_NO_SSIZE_T
#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<nghttp2_extpri> extpris;
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;
size_t peer_max_concurrent_streams;
int multiply;
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 hexdump;
bool no_push;
bool expect_continue;
bool verify_peer;
bool ktls;
};
enum class RequestState { INITIAL, ON_REQUEST, ON_RESPONSE, ON_COMPLETE };
struct RequestTiming {
std::chrono::steady_clock::time_point request_start_time;
std::chrono::steady_clock::time_point response_start_time;
std::chrono::steady_clock::time_point response_end_time;
RequestState state;
RequestTiming() : state(RequestState::INITIAL) {}
};
struct Request;
struct ContinueTimer {
ContinueTimer(struct ev_loop *loop, Request *req);
~ContinueTimer();
void start();
void stop();
void dispatch_continue();
struct ev_loop *loop;
ev_timer timer;
};
struct Request {
Request(const std::string &uri, const urlparse_url &u,
const nghttp2_data_provider2 *data_prd, int64_t data_length,
const nghttp2_extpri &extpri, 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();
std::string_view get_real_scheme() const;
std::string_view get_real_host() const;
uint16_t get_real_port() const;
Headers res_nva;
Headers req_nva;
std::string method;
std::string uri;
urlparse_url u;
nghttp2_extpri extpri;
RequestTiming timing;
int64_t data_length;
int64_t data_offset;
int64_t response_len;
nghttp2_gzip *inflater;
std::unique_ptr<HtmlParser> html_parser;
const nghttp2_data_provider2 *data_prd;
size_t header_buffer_size;
int32_t stream_id;
int status;
int level;
http2::HeaderIndex res_hdidx;
http2::HeaderIndex req_hdidx;
bool expect_final_response;
std::unique_ptr<ContinueTimer> continue_timer;
};
struct SessionTiming {
std::chrono::system_clock::time_point system_start_time;
std::chrono::steady_clock::time_point start_time;
std::chrono::steady_clock::time_point domain_lookup_end_time;
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_provider2 *data_prd, int64_t data_length,
const nghttp2_extpri &extpri, 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
MemchunkPool mcpool;
DefaultMemchunks wb;
std::vector<std::unique_ptr<Request>> reqvec;
std::unordered_set<std::string> path_cache;
std::string scheme;
std::string host;
std::string hostport;
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;
size_t complete;
size_t success;
size_t settings_payloadlen;
ClientState state;
unsigned int upgrade_response_status_code;
int fd;
bool upgrade_response_complete;
std::array<uint8_t, 128> settings_payload;
enum { ERR_CONNECT_FAIL = -100 };
};
}
#endif