diff --git a/configure.ac b/configure.ac index 8ea3fb7a..039d3055 100644 --- a/configure.ac +++ b/configure.ac @@ -210,7 +210,7 @@ fi AM_CONDITIONAL([HAVE_LIBXML2], [ test "x${have_libxml2}" = "xyes" ]) # 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]) if test "x${have_spdylay}" = "xyes"; then AC_DEFINE([HAVE_SPDYLAY], [1], [Define to 1 if you have `spdylay` library.]) diff --git a/src/shrpx.cc b/src/shrpx.cc index 73369da2..cc3797a5 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -324,7 +324,7 @@ bool conf_exists(const char *path) namespace { const char *DEFAULT_NPN_LIST = NGHTTP2_PROTO_VERSION_ID "," #ifdef HAVE_SPDYLAY - "spdy/3,spdy/2," + "spdy/3.1,spdy/3,spdy/2," #endif // HAVE_SPDYLAY "http/1.1"; } // namespace diff --git a/src/shrpx_downstream.cc b/src/shrpx_downstream.cc index 8a3676bd..6efb8308 100644 --- a/src/shrpx_downstream.cc +++ b/src/shrpx_downstream.cc @@ -61,8 +61,7 @@ Downstream::Downstream(Upstream *upstream, int stream_id, int priority) response_connection_close_(false), response_header_key_prev_(false), response_body_buf_(nullptr), - response_rst_stream_error_code_(NGHTTP2_NO_ERROR), - recv_window_size_(0) + response_rst_stream_error_code_(NGHTTP2_NO_ERROR) {} Downstream::~Downstream() @@ -531,21 +530,6 @@ void Downstream::set_priority(int 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() { if(request_method_ == "CONNECT") { diff --git a/src/shrpx_downstream.h b/src/shrpx_downstream.h index c78188da..934b49fb 100644 --- a/src/shrpx_downstream.h +++ b/src/shrpx_downstream.h @@ -67,9 +67,6 @@ public: // Returns true if output buffer is full. If underlying dconn_ is // NULL, this function always returns false. 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. void check_upgrade_fulfilled(); // Checks request headers whether the request is upgrade request or @@ -217,7 +214,6 @@ private: evbuffer *response_body_buf_; // RST_STREAM error_code from downstream HTTP2 connection nghttp2_error_code response_rst_stream_error_code_; - int32_t recv_window_size_; }; } // namespace shrpx diff --git a/src/shrpx_spdy_upstream.cc b/src/shrpx_spdy_upstream.cc index ae0691d5..4dfb590a 100644 --- a/src/shrpx_spdy_upstream.cc +++ b/src/shrpx_spdy_upstream.cc @@ -254,14 +254,32 @@ void on_data_chunk_recv_callback(spdylay_session *session, return; } if(upstream->get_flow_control()) { - downstream->inc_recv_window_size(len); - if(downstream->get_recv_window_size() > - std::max(65536, upstream->get_initial_window_size())) { + // If connection-level window control is not enabled (e.g, + // spdy/3), spdylay_session_get_recv_data_length() is always + // 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)) { - ULOG(INFO, upstream) << "Flow control error: recv_window_size=" - << downstream->get_recv_window_size() - << ", initial_window_size=" - << upstream->get_initial_window_size(); + ULOG(INFO, upstream) + << "Flow control error on connection: " + << "recv_window_size=" + << spdylay_session_get_recv_data_length(session) + << ", 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); return; @@ -679,12 +697,13 @@ int SpdyUpstream::rst_stream(Downstream *downstream, int status_code) return 0; } -int SpdyUpstream::window_update(Downstream *downstream) +int SpdyUpstream::window_update(Downstream *downstream, int32_t delta) { int rv; - rv = spdylay_submit_window_update(session_, downstream->get_stream_id(), - downstream->get_recv_window_size()); - downstream->set_recv_window_size(0); + rv = spdylay_submit_window_update(session_, + downstream ? + downstream->get_stream_id() : 0, + delta); if(rv < SPDYLAY_ERR_FATAL) { ULOG(FATAL, this) << "spdylay_submit_window_update() failed: " << spdylay_strerror(rv); @@ -921,11 +940,40 @@ int32_t SpdyUpstream::get_initial_window_size() const 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) { if(get_flow_control()) { - if(downstream->get_recv_window_size() >= get_initial_window_size()/2) { - window_update(downstream); + int32_t delta; + 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(); diff --git a/src/shrpx_spdy_upstream.h b/src/shrpx_spdy_upstream.h index a499d82a..8811a5df 100644 --- a/src/shrpx_spdy_upstream.h +++ b/src/shrpx_spdy_upstream.h @@ -55,7 +55,7 @@ public: spdylay_session* get_http2_session(); 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); virtual void pause_read(IOCtrlReason reason);