2012-11-20 17:29:39 +01:00
|
|
|
/*
|
2014-03-30 12:09:21 +02:00
|
|
|
* nghttp2 - HTTP/2 C Library
|
2012-11-20 17:29:39 +01:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2013-11-04 09:53:57 +01:00
|
|
|
#ifndef SHRPX_HTTP2_SESSION_H
|
|
|
|
#define SHRPX_HTTP2_SESSION_H
|
2012-11-20 17:29:39 +01:00
|
|
|
|
|
|
|
#include "shrpx.h"
|
|
|
|
|
2015-03-10 16:42:18 +01:00
|
|
|
#include <unordered_set>
|
2013-09-23 17:19:53 +02:00
|
|
|
#include <memory>
|
2012-11-20 17:29:39 +01:00
|
|
|
|
|
|
|
#include <openssl/ssl.h>
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
#include <ev.h>
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2013-07-12 17:19:03 +02:00
|
|
|
#include <nghttp2/nghttp2.h>
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2018-11-23 12:44:36 +01:00
|
|
|
#include "llhttp.h"
|
2013-02-09 08:42:01 +01:00
|
|
|
|
2015-02-04 13:15:58 +01:00
|
|
|
#include "shrpx_connection.h"
|
|
|
|
#include "buffer.h"
|
2015-03-11 13:35:47 +01:00
|
|
|
#include "template.h"
|
2014-12-27 18:59:06 +01:00
|
|
|
|
|
|
|
using namespace nghttp2;
|
|
|
|
|
2012-11-20 17:29:39 +01:00
|
|
|
namespace shrpx {
|
|
|
|
|
2013-11-04 09:53:57 +01:00
|
|
|
class Http2DownstreamConnection;
|
2015-03-10 13:54:29 +01:00
|
|
|
class Worker;
|
2017-02-16 14:46:22 +01:00
|
|
|
class Downstream;
|
2016-02-27 15:24:14 +01:00
|
|
|
struct DownstreamAddrGroup;
|
|
|
|
struct DownstreamAddr;
|
2016-12-04 15:43:41 +01:00
|
|
|
struct DNSQuery;
|
2012-11-20 17:29:39 +01:00
|
|
|
|
|
|
|
struct StreamData {
|
2015-03-11 13:35:47 +01:00
|
|
|
StreamData *dlnext, *dlprev;
|
2013-11-04 09:53:57 +01:00
|
|
|
Http2DownstreamConnection *dconn;
|
2012-11-20 17:29:39 +01:00
|
|
|
};
|
|
|
|
|
2018-10-17 03:15:50 +02:00
|
|
|
enum class FreelistZone {
|
2016-04-02 16:11:03 +02:00
|
|
|
// Http2Session object is not linked in any freelist.
|
2018-10-17 03:15:50 +02:00
|
|
|
NONE,
|
2016-04-02 16:11:03 +02:00
|
|
|
// Http2Session object is linked in address scope
|
|
|
|
// http2_extra_freelist.
|
2018-10-17 03:15:50 +02:00
|
|
|
EXTRA,
|
2016-04-12 16:30:52 +02:00
|
|
|
// Http2Session object is about to be deleted, and it does not
|
|
|
|
// belong to any linked list.
|
2018-10-17 03:15:50 +02:00
|
|
|
GONE
|
2016-04-02 16:11:03 +02:00
|
|
|
};
|
|
|
|
|
2018-10-17 04:03:49 +02:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2018-10-17 04:08:56 +02:00
|
|
|
enum class ConnectionCheck {
|
|
|
|
// Connection checking is not required
|
|
|
|
NONE,
|
|
|
|
// Connection checking is required
|
|
|
|
REQUIRED,
|
|
|
|
// Connection checking has been started
|
|
|
|
STARTED,
|
|
|
|
};
|
|
|
|
|
2013-11-04 09:53:57 +01:00
|
|
|
class Http2Session {
|
2012-11-20 17:29:39 +01:00
|
|
|
public:
|
2016-02-21 06:53:06 +01:00
|
|
|
Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx, Worker *worker,
|
2016-06-02 18:20:49 +02:00
|
|
|
const std::shared_ptr<DownstreamAddrGroup> &group,
|
|
|
|
DownstreamAddr *addr);
|
2014-12-27 18:59:06 +01:00
|
|
|
~Http2Session();
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2014-12-15 15:34:00 +01:00
|
|
|
// If hard is true, all pending requests are abandoned and
|
|
|
|
// associated ClientHandlers will be deleted.
|
|
|
|
int disconnect(bool hard = false);
|
2012-11-20 17:29:39 +01:00
|
|
|
int initiate_connection();
|
2016-12-04 15:43:41 +01:00
|
|
|
int resolve_name();
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2013-11-04 09:53:57 +01:00
|
|
|
void add_downstream_connection(Http2DownstreamConnection *dconn);
|
|
|
|
void remove_downstream_connection(Http2DownstreamConnection *dconn);
|
2012-11-20 17:29:39 +01:00
|
|
|
|
|
|
|
void remove_stream_data(StreamData *sd);
|
|
|
|
|
2016-01-14 16:09:53 +01:00
|
|
|
int submit_request(Http2DownstreamConnection *dconn, const nghttp2_nv *nva,
|
|
|
|
size_t nvlen, const nghttp2_data_provider *data_prd);
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2014-08-23 10:34:56 +02:00
|
|
|
int submit_rst_stream(int32_t stream_id, uint32_t error_code);
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2014-08-23 10:34:56 +02:00
|
|
|
int terminate_session(uint32_t error_code);
|
2013-10-31 13:45:17 +01:00
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
nghttp2_session *get_session() const;
|
2013-10-29 16:07:35 +01:00
|
|
|
|
2013-11-04 09:53:57 +01:00
|
|
|
int resume_data(Http2DownstreamConnection *dconn);
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2015-03-28 12:19:17 +01:00
|
|
|
int connection_made();
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int do_read();
|
|
|
|
int do_write();
|
|
|
|
|
2016-02-07 11:20:17 +01:00
|
|
|
int on_read(const uint8_t *data, size_t datalen);
|
2012-11-20 17:29:39 +01:00
|
|
|
int on_write();
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int connected();
|
|
|
|
int read_clear();
|
|
|
|
int write_clear();
|
|
|
|
int tls_handshake();
|
|
|
|
int read_tls();
|
|
|
|
int write_tls();
|
2016-12-25 15:03:57 +01:00
|
|
|
// This is a special write function which just stop write event
|
|
|
|
// watcher.
|
|
|
|
int write_void();
|
2014-12-27 18:59:06 +01:00
|
|
|
|
2016-02-07 11:20:17 +01:00
|
|
|
int downstream_read_proxy(const uint8_t *data, size_t datalen);
|
2014-12-27 18:59:06 +01:00
|
|
|
int downstream_connect_proxy();
|
2013-02-09 08:42:01 +01:00
|
|
|
|
2016-02-07 11:20:17 +01:00
|
|
|
int downstream_read(const uint8_t *data, size_t datalen);
|
2014-12-27 18:59:06 +01:00
|
|
|
int downstream_write();
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int noop();
|
2016-02-07 11:20:17 +01:00
|
|
|
int read_noop(const uint8_t *data, size_t datalen);
|
|
|
|
int write_noop();
|
2014-12-27 18:59:06 +01:00
|
|
|
|
|
|
|
void signal_write();
|
|
|
|
|
|
|
|
struct ev_loop *get_loop() const;
|
|
|
|
|
|
|
|
ev_io *get_wev();
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2018-10-17 04:03:49 +02:00
|
|
|
Http2SessionState get_state() const;
|
|
|
|
void set_state(Http2SessionState state);
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
void start_settings_timer();
|
2013-10-31 13:45:17 +01:00
|
|
|
void stop_settings_timer();
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
SSL *get_ssl() const;
|
2014-04-26 16:00:58 +02:00
|
|
|
|
2014-07-25 14:26:03 +02:00
|
|
|
int consume(int32_t stream_id, size_t len);
|
2014-07-02 16:20:45 +02:00
|
|
|
|
nghttpx: Check HTTP/2 downstream connection after certain idle time
Previously when requests are issued to HTTP/2 downstream connection,
but it turns out that connection is down, handlers of those requests
are deleted. In some situations, we only know connection is down when
we write something to network, so we'd like to handle this kind of
situation in more robust manner. In this change, certain seconds
passed after last network activity, we first issue PING frame to
downstream connection before issuing new HTTP request. If writing
PING frame is failed, it means connection was lost. In this case,
instead of deleting handler, pending requests are migrated to new
HTTP2/ downstream connection, so that it can continue without
affecting upstream connection.
2014-12-08 17:30:15 +01:00
|
|
|
// Returns true if request can be issued on downstream connection.
|
2018-03-11 04:02:18 +01:00
|
|
|
bool can_push_request(const Downstream *downstream) const;
|
nghttpx: Check HTTP/2 downstream connection after certain idle time
Previously when requests are issued to HTTP/2 downstream connection,
but it turns out that connection is down, handlers of those requests
are deleted. In some situations, we only know connection is down when
we write something to network, so we'd like to handle this kind of
situation in more robust manner. In this change, certain seconds
passed after last network activity, we first issue PING frame to
downstream connection before issuing new HTTP request. If writing
PING frame is failed, it means connection was lost. In this case,
instead of deleting handler, pending requests are migrated to new
HTTP2/ downstream connection, so that it can continue without
affecting upstream connection.
2014-12-08 17:30:15 +01:00
|
|
|
// Initiates the connection checking if downstream connection has
|
|
|
|
// been established and connection checking is required.
|
|
|
|
void start_checking_connection();
|
2015-03-09 13:22:31 +01:00
|
|
|
// 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);
|
2015-03-10 16:27:51 +01:00
|
|
|
void reset_connection_check_timer_if_not_checking();
|
nghttpx: Check HTTP/2 downstream connection after certain idle time
Previously when requests are issued to HTTP/2 downstream connection,
but it turns out that connection is down, handlers of those requests
are deleted. In some situations, we only know connection is down when
we write something to network, so we'd like to handle this kind of
situation in more robust manner. In this change, certain seconds
passed after last network activity, we first issue PING frame to
downstream connection before issuing new HTTP request. If writing
PING frame is failed, it means connection was lost. In this case,
instead of deleting handler, pending requests are migrated to new
HTTP2/ downstream connection, so that it can continue without
affecting upstream connection.
2014-12-08 17:30:15 +01:00
|
|
|
// Signals that connection is alive. Internally
|
|
|
|
// reset_connection_check_timer() is called.
|
2014-12-27 18:59:06 +01:00
|
|
|
void connection_alive();
|
nghttpx: Check HTTP/2 downstream connection after certain idle time
Previously when requests are issued to HTTP/2 downstream connection,
but it turns out that connection is down, handlers of those requests
are deleted. In some situations, we only know connection is down when
we write something to network, so we'd like to handle this kind of
situation in more robust manner. In this change, certain seconds
passed after last network activity, we first issue PING frame to
downstream connection before issuing new HTTP request. If writing
PING frame is failed, it means connection was lost. In this case,
instead of deleting handler, pending requests are migrated to new
HTTP2/ downstream connection, so that it can continue without
affecting upstream connection.
2014-12-08 17:30:15 +01:00
|
|
|
// Change connection check state.
|
2018-10-17 04:08:56 +02:00
|
|
|
void set_connection_check_state(ConnectionCheck state);
|
|
|
|
ConnectionCheck get_connection_check_state() const;
|
nghttpx: Check HTTP/2 downstream connection after certain idle time
Previously when requests are issued to HTTP/2 downstream connection,
but it turns out that connection is down, handlers of those requests
are deleted. In some situations, we only know connection is down when
we write something to network, so we'd like to handle this kind of
situation in more robust manner. In this change, certain seconds
passed after last network activity, we first issue PING frame to
downstream connection before issuing new HTTP request. If writing
PING frame is failed, it means connection was lost. In this case,
instead of deleting handler, pending requests are migrated to new
HTTP2/ downstream connection, so that it can continue without
affecting upstream connection.
2014-12-08 17:30:15 +01:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
bool should_hard_fail() const;
|
|
|
|
|
2015-02-17 15:15:53 +01:00
|
|
|
void submit_pending_requests();
|
|
|
|
|
2016-02-27 15:24:14 +01:00
|
|
|
DownstreamAddr *get_addr() const;
|
2015-03-10 13:54:29 +01:00
|
|
|
|
2016-08-04 17:04:47 +02:00
|
|
|
const std::shared_ptr<DownstreamAddrGroup> &get_downstream_addr_group() const;
|
2015-07-12 15:16:20 +02:00
|
|
|
|
2015-11-15 16:12:54 +01:00
|
|
|
int handle_downstream_push_promise(Downstream *downstream,
|
|
|
|
int32_t promised_stream_id);
|
|
|
|
int handle_downstream_push_promise_complete(Downstream *downstream,
|
|
|
|
Downstream *promised_downstream);
|
|
|
|
|
2016-02-27 11:39:03 +01:00
|
|
|
// Returns number of downstream connections, including pushed
|
|
|
|
// streams.
|
|
|
|
size_t get_num_dconns() const;
|
|
|
|
|
2016-04-02 16:11:03 +02:00
|
|
|
// 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();
|
2016-02-27 11:39:03 +01:00
|
|
|
|
2016-04-12 16:30:52 +02:00
|
|
|
// Removes this object form any freelist, and marks this object as
|
|
|
|
// not schedulable.
|
|
|
|
void exclude_from_scheduling();
|
|
|
|
|
2016-02-27 11:39:03 +01:00
|
|
|
// 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;
|
|
|
|
|
2016-05-14 10:17:27 +02:00
|
|
|
DefaultMemchunks *get_request_buf();
|
|
|
|
|
2016-05-24 14:59:24 +02:00
|
|
|
void on_timeout();
|
|
|
|
|
2016-06-04 05:36:22 +02:00
|
|
|
// 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();
|
|
|
|
|
2016-12-04 15:43:41 +01:00
|
|
|
// Returns address used to connect to backend. Could be nullptr.
|
|
|
|
const Address *get_raddr() const;
|
|
|
|
|
2018-03-11 04:02:18 +01:00
|
|
|
// 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;
|
|
|
|
|
2015-06-21 07:32:47 +02:00
|
|
|
using ReadBuf = Buffer<8_k>;
|
2015-01-08 13:28:52 +01:00
|
|
|
|
2016-02-27 11:39:03 +01:00
|
|
|
Http2Session *dlnext, *dlprev;
|
|
|
|
|
2012-11-20 17:29:39 +01:00
|
|
|
private:
|
2015-02-04 13:15:58 +01:00
|
|
|
Connection conn_;
|
2016-02-07 10:54:44 +01:00
|
|
|
DefaultMemchunks wb_;
|
2014-12-27 18:59:06 +01:00
|
|
|
ev_timer settings_timer_;
|
2015-03-09 13:22:31 +01:00
|
|
|
// This timer has 2 purpose: when it first timeout, set
|
2018-10-17 04:08:56 +02:00
|
|
|
// connection_check_state_ = ConnectionCheck::REQUIRED. After
|
2015-03-09 13:22:31 +01:00
|
|
|
// connection check has started, this timer is started again and
|
|
|
|
// traps PING ACK timeout.
|
2014-12-27 18:59:06 +01:00
|
|
|
ev_timer connchk_timer_;
|
2016-04-02 17:23:44 +02:00
|
|
|
// timer to initiate connection. usually, this fires immediately.
|
|
|
|
ev_timer initiate_connection_timer_;
|
2016-06-04 05:36:22 +02:00
|
|
|
ev_prepare prep_;
|
2015-03-11 13:35:47 +01:00
|
|
|
DList<Http2DownstreamConnection> dconns_;
|
|
|
|
DList<StreamData> streams_;
|
2014-12-27 18:59:06 +01:00
|
|
|
std::function<int(Http2Session &)> read_, write_;
|
2016-02-07 11:20:17 +01:00
|
|
|
std::function<int(Http2Session &, const uint8_t *, size_t)> on_read_;
|
|
|
|
std::function<int(Http2Session &)> on_write_;
|
2013-12-06 15:17:38 +01:00
|
|
|
// Used to parse the response from HTTP proxy
|
2018-11-23 12:44:36 +01:00
|
|
|
std::unique_ptr<llhttp_t> proxy_htp_;
|
2015-03-10 13:54:29 +01:00
|
|
|
Worker *worker_;
|
2013-02-22 13:54:07 +01:00
|
|
|
// NULL if no TLS is configured
|
2012-11-20 17:29:39 +01:00
|
|
|
SSL_CTX *ssl_ctx_;
|
2016-06-02 18:20:49 +02:00
|
|
|
std::shared_ptr<DownstreamAddrGroup> group_;
|
2016-02-07 10:22:57 +01:00
|
|
|
// Address of remote endpoint
|
2016-02-27 15:24:14 +01:00
|
|
|
DownstreamAddr *addr_;
|
2013-12-06 15:17:38 +01:00
|
|
|
nghttp2_session *session_;
|
2016-12-04 15:43:41 +01:00
|
|
|
// 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_;
|
2018-10-17 04:03:49 +02:00
|
|
|
Http2SessionState state_;
|
2018-10-17 04:08:56 +02:00
|
|
|
ConnectionCheck connection_check_state_;
|
2018-10-17 03:15:50 +02:00
|
|
|
FreelistZone freelist_zone_;
|
2018-03-11 04:02:18 +01:00
|
|
|
// true if SETTINGS without ACK is received from peer.
|
|
|
|
bool settings_recved_;
|
|
|
|
// true if peer enables RFC 8441 CONNECT protocol.
|
|
|
|
bool allow_connect_proto_;
|
2012-11-20 17:29:39 +01:00
|
|
|
};
|
|
|
|
|
2015-02-24 07:21:10 +01:00
|
|
|
nghttp2_session_callbacks *create_http2_downstream_callbacks();
|
|
|
|
|
2012-11-20 17:29:39 +01:00
|
|
|
} // namespace shrpx
|
|
|
|
|
2013-11-04 09:53:57 +01:00
|
|
|
#endif // SHRPX_HTTP2_SESSION_H
|