/* * nghttp2 - HTTP/2 C Library * * Copyright (c) 2012 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 SHRPX_HTTP2_SESSION_H #define SHRPX_HTTP2_SESSION_H #include "shrpx.h" #include #include #include #include #include #include "llhttp.h" #include "shrpx_connection.h" #include "buffer.h" #include "template.h" using namespace nghttp2; namespace shrpx { class Http2DownstreamConnection; class Worker; class Downstream; struct DownstreamAddrGroup; struct DownstreamAddr; struct DNSQuery; struct StreamData { StreamData *dlnext, *dlprev; Http2DownstreamConnection *dconn; }; enum class FreelistZone { // Http2Session object is not linked in any freelist. NONE, // Http2Session object is linked in address scope // http2_extra_freelist. EXTRA, // Http2Session object is about to be deleted, and it does not // belong to any linked list. GONE }; enum class Http2SessionState { // Disconnected DISCONNECTED, // Connecting proxy and making CONNECT request PROXY_CONNECTING, // Tunnel is established with proxy PROXY_CONNECTED, // Establishing tunnel is failed PROXY_FAILED, // Connecting to downstream and/or performing SSL/TLS handshake CONNECTING, // Connected to downstream CONNECTED, // Connection is started to fail CONNECT_FAILING, // Resolving host name RESOLVING_NAME, }; enum class ConnectionCheck { // Connection checking is not required NONE, // Connection checking is required REQUIRED, // Connection checking has been started STARTED, }; class Http2Session { public: Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx, Worker *worker, const std::shared_ptr &group, DownstreamAddr *addr); ~Http2Session(); // If hard is true, all pending requests are abandoned and // associated ClientHandlers will be deleted. int disconnect(bool hard = false); int initiate_connection(); int resolve_name(); void add_downstream_connection(Http2DownstreamConnection *dconn); void remove_downstream_connection(Http2DownstreamConnection *dconn); void remove_stream_data(StreamData *sd); int submit_request(Http2DownstreamConnection *dconn, const nghttp2_nv *nva, size_t nvlen, const nghttp2_data_provider *data_prd); int submit_rst_stream(int32_t stream_id, uint32_t error_code); int terminate_session(uint32_t error_code); nghttp2_session *get_session() const; int resume_data(Http2DownstreamConnection *dconn); int connection_made(); int do_read(); int do_write(); int on_read(const uint8_t *data, size_t datalen); int on_write(); int connected(); int read_clear(); int write_clear(); int tls_handshake(); int read_tls(); int write_tls(); // This is a special write function which just stop write event // watcher. int write_void(); int downstream_read_proxy(const uint8_t *data, size_t datalen); int downstream_connect_proxy(); int downstream_read(const uint8_t *data, size_t datalen); int downstream_write(); int noop(); int read_noop(const uint8_t *data, size_t datalen); int write_noop(); void signal_write(); struct ev_loop *get_loop() const; ev_io *get_wev(); Http2SessionState get_state() const; void set_state(Http2SessionState state); void start_settings_timer(); void stop_settings_timer(); SSL *get_ssl() const; int consume(int32_t stream_id, size_t len); // Returns true if request can be issued on downstream connection. bool can_push_request(const Downstream *downstream) const; // Initiates the connection checking if downstream connection has // been established and connection checking is required. void start_checking_connection(); // Resets connection check timer to timeout |t|. After timeout, we // require connection checking. If connection checking is already // enabled, this timeout is for PING ACK timeout. void reset_connection_check_timer(ev_tstamp t); void reset_connection_check_timer_if_not_checking(); // Signals that connection is alive. Internally // reset_connection_check_timer() is called. void connection_alive(); // Change connection check state. void set_connection_check_state(ConnectionCheck state); ConnectionCheck get_connection_check_state() const; bool should_hard_fail() const; void submit_pending_requests(); DownstreamAddr *get_addr() const; const std::shared_ptr &get_downstream_addr_group() const; int handle_downstream_push_promise(Downstream *downstream, int32_t promised_stream_id); int handle_downstream_push_promise_complete(Downstream *downstream, Downstream *promised_downstream); // Returns number of downstream connections, including pushed // streams. size_t get_num_dconns() const; // Adds to group scope http2_avail_freelist. void add_to_avail_freelist(); // Adds to address scope http2_extra_freelist. void add_to_extra_freelist(); // Removes this object from any freelist. If this object is not // linked from any freelist, this function does nothing. void remove_from_freelist(); // Removes this object form any freelist, and marks this object as // not schedulable. void exclude_from_scheduling(); // Returns true if the maximum concurrency is reached. In other // words, the number of currently participated streams in this // session is equal or greater than the max concurrent streams limit // advertised by server. If |extra| is nonzero, it is added to the // number of current concurrent streams when comparing against // server initiated concurrency limit. bool max_concurrency_reached(size_t extra = 0) const; DefaultMemchunks *get_request_buf(); void on_timeout(); // This is called periodically using ev_prepare watcher, and if // group_ is retired (backend has been replaced), send GOAWAY to // shutdown the connection. void check_retire(); // Returns address used to connect to backend. Could be nullptr. const Address *get_raddr() const; // This is called when SETTINGS frame without ACK flag set is // received. void on_settings_received(const nghttp2_frame *frame); bool get_allow_connect_proto() const; using ReadBuf = Buffer<8_k>; Http2Session *dlnext, *dlprev; private: Connection conn_; DefaultMemchunks wb_; ev_timer settings_timer_; // This timer has 2 purpose: when it first timeout, set // connection_check_state_ = ConnectionCheck::REQUIRED. After // connection check has started, this timer is started again and // traps PING ACK timeout. ev_timer connchk_timer_; // timer to initiate connection. usually, this fires immediately. ev_timer initiate_connection_timer_; ev_prepare prep_; DList dconns_; DList streams_; std::function read_, write_; std::function on_read_; std::function on_write_; // Used to parse the response from HTTP proxy std::unique_ptr proxy_htp_; Worker *worker_; // NULL if no TLS is configured SSL_CTX *ssl_ctx_; std::shared_ptr group_; // Address of remote endpoint DownstreamAddr *addr_; nghttp2_session *session_; // Actual remote address used to contact backend. This is initially // nullptr, and may point to either &addr_->addr, // resolved_addr_.get(), or HTTP proxy's address structure. const Address *raddr_; // Resolved IP address if dns parameter is used std::unique_ptr
resolved_addr_; std::unique_ptr dns_query_; Http2SessionState state_; ConnectionCheck connection_check_state_; FreelistZone freelist_zone_; // true if SETTINGS without ACK is received from peer. bool settings_recved_; // true if peer enables RFC 8441 CONNECT protocol. bool allow_connect_proto_; }; nghttp2_session_callbacks *create_http2_downstream_callbacks(); } // namespace shrpx #endif // SHRPX_HTTP2_SESSION_H