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"
|
|
|
|
|
|
|
|
#include <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
|
|
|
|
2013-02-09 08:42:01 +01:00
|
|
|
#include "http-parser/http_parser.h"
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
#include "ringbuf.h"
|
|
|
|
|
|
|
|
using namespace nghttp2;
|
|
|
|
|
2012-11-20 17:29:39 +01:00
|
|
|
namespace shrpx {
|
|
|
|
|
2013-11-04 09:53:57 +01:00
|
|
|
class Http2DownstreamConnection;
|
2012-11-20 17:29:39 +01:00
|
|
|
|
|
|
|
struct StreamData {
|
2013-11-04 09:53:57 +01:00
|
|
|
Http2DownstreamConnection *dconn;
|
2012-11-20 17:29:39 +01:00
|
|
|
};
|
|
|
|
|
2013-11-04 09:53:57 +01:00
|
|
|
class Http2Session {
|
2012-11-20 17:29:39 +01:00
|
|
|
public:
|
2014-12-27 18:59:06 +01:00
|
|
|
Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx);
|
|
|
|
~Http2Session();
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2012-11-22 13:46:15 +01:00
|
|
|
int check_cert();
|
|
|
|
|
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();
|
|
|
|
|
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);
|
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
int submit_request(Http2DownstreamConnection *dconn, int32_t pri,
|
|
|
|
const nghttp2_nv *nva, size_t nvlen,
|
2013-07-12 17:19:03 +02:00
|
|
|
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-01-18 08:12:03 +01:00
|
|
|
int submit_priority(Http2DownstreamConnection *dconn, int32_t pri);
|
|
|
|
|
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
|
|
|
|
2012-11-21 15:47:48 +01:00
|
|
|
bool get_flow_control() const;
|
|
|
|
|
2013-11-04 09:53:57 +01:00
|
|
|
int resume_data(Http2DownstreamConnection *dconn);
|
2012-11-20 17:29:39 +01:00
|
|
|
|
|
|
|
int on_connect();
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int do_read();
|
|
|
|
int do_write();
|
|
|
|
|
2012-11-20 17:29:39 +01:00
|
|
|
int on_read();
|
|
|
|
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();
|
|
|
|
|
|
|
|
int downstream_read_proxy();
|
|
|
|
int downstream_connect_proxy();
|
2013-02-09 08:42:01 +01:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int downstream_read();
|
|
|
|
int downstream_write();
|
2012-11-20 17:29:39 +01:00
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
int noop();
|
|
|
|
|
|
|
|
void signal_write();
|
|
|
|
void clear_write_request();
|
|
|
|
bool write_requested() const;
|
|
|
|
|
|
|
|
struct ev_loop *get_loop() const;
|
|
|
|
|
|
|
|
ev_io *get_wev();
|
2012-11-20 17:29:39 +01:00
|
|
|
|
|
|
|
int get_state() const;
|
2013-02-09 08:42:01 +01:00
|
|
|
void set_state(int 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.
|
|
|
|
bool can_push_request() const;
|
|
|
|
// Initiates the connection checking if downstream connection has
|
|
|
|
// been established and connection checking is required.
|
|
|
|
void start_checking_connection();
|
|
|
|
// Resets connection check timer. After timeout, we require
|
|
|
|
// connection checking.
|
2014-12-27 18:59:06 +01:00
|
|
|
void reset_connection_check_timer();
|
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.
|
|
|
|
void set_connection_check_state(int state);
|
|
|
|
|
2014-12-27 18:59:06 +01:00
|
|
|
bool should_hard_fail() const;
|
|
|
|
|
2012-11-20 17:29:39 +01:00
|
|
|
enum {
|
2013-02-09 08:42:01 +01:00
|
|
|
// Disconnected
|
2012-11-20 17:29:39 +01:00
|
|
|
DISCONNECTED,
|
2013-02-09 08:42:01 +01:00
|
|
|
// 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
|
2012-11-20 17:29:39 +01:00
|
|
|
CONNECTING,
|
2013-02-09 08:42:01 +01:00
|
|
|
// Connected to downstream
|
2014-12-27 18:59:06 +01:00
|
|
|
CONNECTED,
|
|
|
|
// Connection is started to fail
|
|
|
|
CONNECT_FAILING,
|
2012-11-20 17:29:39 +01:00
|
|
|
};
|
2014-01-19 10:07:50 +01:00
|
|
|
|
2014-11-27 15:39:04 +01:00
|
|
|
static const size_t OUTBUF_MAX_THRES = 64 * 1024;
|
|
|
|
|
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
|
|
|
enum {
|
|
|
|
// Connection checking is not required
|
|
|
|
CONNECTION_CHECK_NONE,
|
|
|
|
// Connection checking is required
|
|
|
|
CONNECTION_CHECK_REQUIRED,
|
|
|
|
// Connection checking has been started
|
|
|
|
CONNECTION_CHECK_STARTED
|
|
|
|
};
|
|
|
|
|
2015-01-08 13:28:52 +01:00
|
|
|
using ReadBuf = RingBuf<8192>;
|
2015-01-09 12:55:39 +01:00
|
|
|
using WriteBuf = RingBuf<65536>;
|
2015-01-08 13:28:52 +01:00
|
|
|
|
2012-11-20 17:29:39 +01:00
|
|
|
private:
|
2014-12-27 18:59:06 +01:00
|
|
|
ev_io wev_;
|
|
|
|
ev_io rev_;
|
|
|
|
ev_timer wt_;
|
|
|
|
ev_timer rt_;
|
|
|
|
ev_timer settings_timer_;
|
|
|
|
ev_timer connchk_timer_;
|
|
|
|
ev_prepare wrsched_prep_;
|
2014-11-27 15:39:04 +01:00
|
|
|
std::set<Http2DownstreamConnection *> dconns_;
|
|
|
|
std::set<StreamData *> streams_;
|
2014-12-27 18:59:06 +01:00
|
|
|
std::function<int(Http2Session &)> read_, write_;
|
|
|
|
std::function<int(Http2Session &)> on_read_, on_write_;
|
2013-12-06 15:17:38 +01:00
|
|
|
// Used to parse the response from HTTP proxy
|
|
|
|
std::unique_ptr<http_parser> proxy_htp_;
|
2014-12-27 18:59:06 +01:00
|
|
|
struct ev_loop *loop_;
|
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_;
|
|
|
|
SSL *ssl_;
|
2013-12-06 15:17:38 +01:00
|
|
|
nghttp2_session *session_;
|
2014-12-27 18:59:06 +01:00
|
|
|
const uint8_t *data_pending_;
|
|
|
|
size_t data_pendinglen_;
|
2013-02-22 13:54:07 +01:00
|
|
|
// fd_ is used for proxy connection and no TLS connection. For
|
|
|
|
// direct or TLS connection, it may be -1 even after connection is
|
|
|
|
// established. Use bufferevent_getfd(bev_) to get file descriptor
|
|
|
|
// in these cases.
|
2013-02-09 08:42:01 +01:00
|
|
|
int fd_;
|
2012-11-20 17:29:39 +01:00
|
|
|
int state_;
|
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
|
|
|
int connection_check_state_;
|
2012-11-21 15:47:48 +01:00
|
|
|
bool flow_control_;
|
2014-12-27 18:59:06 +01:00
|
|
|
bool write_requested_;
|
2015-01-08 13:28:52 +01:00
|
|
|
WriteBuf wb_;
|
|
|
|
ReadBuf rb_;
|
2012-11-20 17:29:39 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace shrpx
|
|
|
|
|
2013-11-04 09:53:57 +01:00
|
|
|
#endif // SHRPX_HTTP2_SESSION_H
|