nghttpx: Support spdy/3.1, require spdylay >= 1.2.0

This commit is contained in:
Tatsuhiro Tsujikawa 2013-11-12 11:03:46 +09:00
parent 45c3c5b80f
commit 58beaa371d
6 changed files with 65 additions and 37 deletions

View File

@ -210,7 +210,7 @@ fi
AM_CONDITIONAL([HAVE_LIBXML2], [ test "x${have_libxml2}" = "xyes" ]) AM_CONDITIONAL([HAVE_LIBXML2], [ test "x${have_libxml2}" = "xyes" ])
# spdylay (for src/nghttpx) # spdylay (for src/nghttpx)
PKG_CHECK_MODULES([LIBSPDYLAY], [libspdylay >= 1.0.0], PKG_CHECK_MODULES([LIBSPDYLAY], [libspdylay >= 1.2.0],
[have_spdylay=yes], [have_spdylay=no]) [have_spdylay=yes], [have_spdylay=no])
if test "x${have_spdylay}" = "xyes"; then if test "x${have_spdylay}" = "xyes"; then
AC_DEFINE([HAVE_SPDYLAY], [1], [Define to 1 if you have `spdylay` library.]) AC_DEFINE([HAVE_SPDYLAY], [1], [Define to 1 if you have `spdylay` library.])

View File

@ -324,7 +324,7 @@ bool conf_exists(const char *path)
namespace { namespace {
const char *DEFAULT_NPN_LIST = NGHTTP2_PROTO_VERSION_ID "," const char *DEFAULT_NPN_LIST = NGHTTP2_PROTO_VERSION_ID ","
#ifdef HAVE_SPDYLAY #ifdef HAVE_SPDYLAY
"spdy/3,spdy/2," "spdy/3.1,spdy/3,spdy/2,"
#endif // HAVE_SPDYLAY #endif // HAVE_SPDYLAY
"http/1.1"; "http/1.1";
} // namespace } // namespace

View File

@ -61,8 +61,7 @@ Downstream::Downstream(Upstream *upstream, int stream_id, int priority)
response_connection_close_(false), response_connection_close_(false),
response_header_key_prev_(false), response_header_key_prev_(false),
response_body_buf_(nullptr), response_body_buf_(nullptr),
response_rst_stream_error_code_(NGHTTP2_NO_ERROR), response_rst_stream_error_code_(NGHTTP2_NO_ERROR)
recv_window_size_(0)
{} {}
Downstream::~Downstream() Downstream::~Downstream()
@ -531,21 +530,6 @@ void Downstream::set_priority(int pri)
priority_ = pri; priority_ = pri;
} }
int32_t Downstream::get_recv_window_size() const
{
return recv_window_size_;
}
void Downstream::inc_recv_window_size(int32_t amount)
{
recv_window_size_ += amount;
}
void Downstream::set_recv_window_size(int32_t new_size)
{
recv_window_size_ = new_size;
}
void Downstream::check_upgrade_fulfilled() void Downstream::check_upgrade_fulfilled()
{ {
if(request_method_ == "CONNECT") { if(request_method_ == "CONNECT") {

View File

@ -67,9 +67,6 @@ public:
// Returns true if output buffer is full. If underlying dconn_ is // Returns true if output buffer is full. If underlying dconn_ is
// NULL, this function always returns false. // NULL, this function always returns false.
bool get_output_buffer_full(); bool get_output_buffer_full();
int32_t get_recv_window_size() const;
void inc_recv_window_size(int32_t amount);
void set_recv_window_size(int32_t new_size);
// Returns true if upgrade (HTTP Upgrade or CONNECT) is succeeded. // Returns true if upgrade (HTTP Upgrade or CONNECT) is succeeded.
void check_upgrade_fulfilled(); void check_upgrade_fulfilled();
// Checks request headers whether the request is upgrade request or // Checks request headers whether the request is upgrade request or
@ -217,7 +214,6 @@ private:
evbuffer *response_body_buf_; evbuffer *response_body_buf_;
// RST_STREAM error_code from downstream HTTP2 connection // RST_STREAM error_code from downstream HTTP2 connection
nghttp2_error_code response_rst_stream_error_code_; nghttp2_error_code response_rst_stream_error_code_;
int32_t recv_window_size_;
}; };
} // namespace shrpx } // namespace shrpx

View File

@ -254,14 +254,32 @@ void on_data_chunk_recv_callback(spdylay_session *session,
return; return;
} }
if(upstream->get_flow_control()) { if(upstream->get_flow_control()) {
downstream->inc_recv_window_size(len); // If connection-level window control is not enabled (e.g,
if(downstream->get_recv_window_size() > // spdy/3), spdylay_session_get_recv_data_length() is always
std::max(65536, upstream->get_initial_window_size())) { // returns 0.
if(spdylay_session_get_recv_data_length(session) >
std::max(SPDYLAY_INITIAL_WINDOW_SIZE,
spdylay_session_get_local_window_size(session))) {
if(LOG_ENABLED(INFO)) { if(LOG_ENABLED(INFO)) {
ULOG(INFO, upstream) << "Flow control error: recv_window_size=" ULOG(INFO, upstream)
<< downstream->get_recv_window_size() << "Flow control error on connection: "
<< "recv_window_size="
<< spdylay_session_get_recv_data_length(session)
<< ", initial_window_size=" << ", initial_window_size="
<< upstream->get_initial_window_size(); << spdylay_session_get_local_window_size(session);
}
spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
return;
}
if(spdylay_session_get_stream_recv_data_length(session, stream_id) >
std::max(SPDYLAY_INITIAL_WINDOW_SIZE,
spdylay_session_get_stream_local_window_size(session))) {
if(LOG_ENABLED(INFO)) {
ULOG(INFO, upstream)
<< "Flow control error: recv_window_size="
<< spdylay_session_get_stream_recv_data_length(session, stream_id)
<< ", initial_window_size="
<< spdylay_session_get_stream_local_window_size(session);
} }
upstream->rst_stream(downstream, SPDYLAY_FLOW_CONTROL_ERROR); upstream->rst_stream(downstream, SPDYLAY_FLOW_CONTROL_ERROR);
return; return;
@ -679,12 +697,13 @@ int SpdyUpstream::rst_stream(Downstream *downstream, int status_code)
return 0; return 0;
} }
int SpdyUpstream::window_update(Downstream *downstream) int SpdyUpstream::window_update(Downstream *downstream, int32_t delta)
{ {
int rv; int rv;
rv = spdylay_submit_window_update(session_, downstream->get_stream_id(), rv = spdylay_submit_window_update(session_,
downstream->get_recv_window_size()); downstream ?
downstream->set_recv_window_size(0); downstream->get_stream_id() : 0,
delta);
if(rv < SPDYLAY_ERR_FATAL) { if(rv < SPDYLAY_ERR_FATAL) {
ULOG(FATAL, this) << "spdylay_submit_window_update() failed: " ULOG(FATAL, this) << "spdylay_submit_window_update() failed: "
<< spdylay_strerror(rv); << spdylay_strerror(rv);
@ -921,11 +940,40 @@ int32_t SpdyUpstream::get_initial_window_size() const
void SpdyUpstream::pause_read(IOCtrlReason reason) void SpdyUpstream::pause_read(IOCtrlReason reason)
{} {}
namespace {
int32_t determine_window_update_transmission(spdylay_session *session,
int32_t stream_id)
{
int32_t recv_length, window_size;
if(stream_id == 0) {
recv_length = spdylay_session_get_recv_data_length(session);
window_size = spdylay_session_get_local_window_size(session);
} else {
recv_length = spdylay_session_get_stream_recv_data_length
(session, stream_id);
window_size = spdylay_session_get_stream_local_window_size(session);
}
if(recv_length != -1 && window_size != -1) {
if(recv_length >= window_size / 2) {
return recv_length;
}
}
return -1;
}
} // namespace
int SpdyUpstream::resume_read(IOCtrlReason reason, Downstream *downstream) int SpdyUpstream::resume_read(IOCtrlReason reason, Downstream *downstream)
{ {
if(get_flow_control()) { if(get_flow_control()) {
if(downstream->get_recv_window_size() >= get_initial_window_size()/2) { int32_t delta;
window_update(downstream); delta = determine_window_update_transmission(session_, 0);
if(delta != -1) {
window_update(0, delta);
}
delta = determine_window_update_transmission
(session_, downstream->get_stream_id());
if(delta != -1) {
window_update(downstream, delta);
} }
} }
return send(); return send();

View File

@ -55,7 +55,7 @@ public:
spdylay_session* get_http2_session(); spdylay_session* get_http2_session();
int rst_stream(Downstream *downstream, int status_code); int rst_stream(Downstream *downstream, int status_code);
int window_update(Downstream *downstream); int window_update(Downstream *downstream, int32_t delta);
int error_reply(Downstream *downstream, unsigned int status_code); int error_reply(Downstream *downstream, unsigned int status_code);
virtual void pause_read(IOCtrlReason reason); virtual void pause_read(IOCtrlReason reason);