summaryrefslogtreecommitdiffstats
path: root/src/shrpx_http2_session.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/shrpx_http2_session.h')
-rw-r--r--src/shrpx_http2_session.h296
1 files changed, 296 insertions, 0 deletions
diff --git a/src/shrpx_http2_session.h b/src/shrpx_http2_session.h
new file mode 100644
index 0000000..31b2545
--- /dev/null
+++ b/src/shrpx_http2_session.h
@@ -0,0 +1,296 @@
+/*
+ * 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 <unordered_set>
+#include <memory>
+
+#include <openssl/ssl.h>
+
+#include <ev.h>
+
+#include <nghttp2/nghttp2.h>
+
+#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<DownstreamAddrGroup> &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<DownstreamAddrGroup> &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<Http2DownstreamConnection> dconns_;
+ DList<StreamData> streams_;
+ std::function<int(Http2Session &)> read_, write_;
+ std::function<int(Http2Session &, const uint8_t *, size_t)> on_read_;
+ std::function<int(Http2Session &)> on_write_;
+ // Used to parse the response from HTTP proxy
+ std::unique_ptr<llhttp_t> proxy_htp_;
+ Worker *worker_;
+ // NULL if no TLS is configured
+ SSL_CTX *ssl_ctx_;
+ std::shared_ptr<DownstreamAddrGroup> 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<Address> resolved_addr_;
+ std::unique_ptr<DNSQuery> 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