nghttpx: Add connection-level flow control window size options
This commit also changes SPDY's flow control size. Previously, the size for SPDY is the same amount of bytes with HTTP/2. For example, --frontend-http2-upstream-window-bits=N, the window size is 2**N - 1. Now SPDY code uses 2**N.
This commit is contained in:
parent
bc21edf5b6
commit
01f7162be3
43
src/shrpx.cc
43
src/shrpx.cc
|
@ -365,12 +365,17 @@ void fill_default_config()
|
||||||
// Timeout for pooled (idle) connections
|
// Timeout for pooled (idle) connections
|
||||||
mod_config()->downstream_idle_read_timeout.tv_sec = 60;
|
mod_config()->downstream_idle_read_timeout.tv_sec = 60;
|
||||||
|
|
||||||
// window bits for HTTP/2.0 and SPDY upstream/downstream
|
// window bits for HTTP/2.0 and SPDY upstream/downstream connection
|
||||||
// connection. 2**16-1 = 64KiB-1, which is HTTP/2.0 default. Please
|
// per stream. 2**16-1 = 64KiB-1, which is HTTP/2.0 default. Please
|
||||||
// note that SPDY/3 default is 64KiB.
|
// note that SPDY/3 default is 64KiB.
|
||||||
mod_config()->http2_upstream_window_bits = 16;
|
mod_config()->http2_upstream_window_bits = 16;
|
||||||
mod_config()->http2_downstream_window_bits = 16;
|
mod_config()->http2_downstream_window_bits = 16;
|
||||||
|
|
||||||
|
// HTTP/2.0 SPDY/3.1 has connection-level flow control. The default
|
||||||
|
// window size for HTTP/2 is 64KiB - 1. SPDY/3's default is 64KiB
|
||||||
|
mod_config()->http2_upstream_connection_window_bits = 16;
|
||||||
|
mod_config()->http2_downstream_connection_window_bits = 16;
|
||||||
|
|
||||||
mod_config()->upstream_no_tls = false;
|
mod_config()->upstream_no_tls = false;
|
||||||
mod_config()->downstream_no_tls = false;
|
mod_config()->downstream_no_tls = false;
|
||||||
|
|
||||||
|
@ -620,16 +625,28 @@ void print_help(std::ostream& out)
|
||||||
<< " Default: "
|
<< " Default: "
|
||||||
<< get_config()->http2_max_concurrent_streams << "\n"
|
<< get_config()->http2_max_concurrent_streams << "\n"
|
||||||
<< " --frontend-http2-window-bits=<N>\n"
|
<< " --frontend-http2-window-bits=<N>\n"
|
||||||
<< " Sets the initial window size of HTTP/2.0 and SPDY\n"
|
<< " Sets the per-stream initial window size of HTTP/2.0\n"
|
||||||
<< " frontend connection to 2**<N>-1.\n"
|
<< " SPDY frontend connection. For HTTP/2.0, the size is\n"
|
||||||
|
<< " 2**<N>-1. For SPDY, the size is 2**<N>\n"
|
||||||
<< " Default: "
|
<< " Default: "
|
||||||
<< get_config()->http2_upstream_window_bits << "\n"
|
<< get_config()->http2_upstream_window_bits << "\n"
|
||||||
|
<< " --frontend-http2-connection-window-bits=<N>\n"
|
||||||
|
<< " Sets the per-connection window size of HTTP/2.0 and\n"
|
||||||
|
<< " SPDY frontend connection. For HTTP/2.0, the size is\n"
|
||||||
|
<< " 2**<N>-1. For SPDY, the size is 2**<N>.\n"
|
||||||
|
<< " Default: "
|
||||||
|
<< get_config()->http2_upstream_connection_window_bits << "\n"
|
||||||
<< " --frontend-no-tls Disable SSL/TLS on frontend connections.\n"
|
<< " --frontend-no-tls Disable SSL/TLS on frontend connections.\n"
|
||||||
<< " --backend-http2-window-bits=<N>\n"
|
<< " --backend-http2-window-bits=<N>\n"
|
||||||
<< " Sets the initial window size of HTTP/2.0 and SPDY\n"
|
<< " Sets the initial window size of HTTP/2.0 backend\n"
|
||||||
<< " backend connection to 2**<N>-1.\n"
|
<< " connection to 2**<N>-1.\n"
|
||||||
<< " Default: "
|
<< " Default: "
|
||||||
<< get_config()->http2_downstream_window_bits << "\n"
|
<< get_config()->http2_downstream_window_bits << "\n"
|
||||||
|
<< " --backend-http2-connection-window-bits=<N>\n"
|
||||||
|
<< " Sets the per-connection window size of HTTP/2.0\n"
|
||||||
|
<< " backend connection to 2**<N>-1.\n"
|
||||||
|
<< " Default: "
|
||||||
|
<< get_config()->http2_downstream_connection_window_bits << "\n"
|
||||||
<< " --backend-no-tls Disable SSL/TLS on backend connections.\n"
|
<< " --backend-no-tls Disable SSL/TLS on backend connections.\n"
|
||||||
<< " --http2-no-cookie-crumbling\n"
|
<< " --http2-no-cookie-crumbling\n"
|
||||||
<< " Don't crumble cookie header field.\n"
|
<< " Don't crumble cookie header field.\n"
|
||||||
|
@ -774,6 +791,8 @@ int main(int argc, char **argv)
|
||||||
{"frontend-http2-dump-request-header", required_argument, &flag, 43},
|
{"frontend-http2-dump-request-header", required_argument, &flag, 43},
|
||||||
{"frontend-http2-dump-response-header", required_argument, &flag, 44},
|
{"frontend-http2-dump-response-header", required_argument, &flag, 44},
|
||||||
{"http2-no-cookie-crumbling", no_argument, &flag, 45},
|
{"http2-no-cookie-crumbling", no_argument, &flag, 45},
|
||||||
|
{"frontend-http2-connection-window-bits", required_argument, &flag, 46},
|
||||||
|
{"backend-http2-connection-window-bits", required_argument, &flag, 47},
|
||||||
{nullptr, 0, nullptr, 0 }
|
{nullptr, 0, nullptr, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1013,6 +1032,18 @@ int main(int argc, char **argv)
|
||||||
cmdcfgs.push_back(std::make_pair
|
cmdcfgs.push_back(std::make_pair
|
||||||
(SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING, "yes"));
|
(SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING, "yes"));
|
||||||
break;
|
break;
|
||||||
|
case 46:
|
||||||
|
// --frontend-http2-connection-window-bits
|
||||||
|
cmdcfgs.push_back(std::make_pair
|
||||||
|
(SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS,
|
||||||
|
optarg));
|
||||||
|
break;
|
||||||
|
case 47:
|
||||||
|
// --backend-http2-connection-window-bits
|
||||||
|
cmdcfgs.push_back(std::make_pair
|
||||||
|
(SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS,
|
||||||
|
optarg));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,10 @@ SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT[] = "backend-keep-alive-timeout";
|
||||||
const char
|
const char
|
||||||
SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS[] = "frontend-http2-window-bits";
|
SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS[] = "frontend-http2-window-bits";
|
||||||
const char SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS[] = "backend-http2-window-bits";
|
const char SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS[] = "backend-http2-window-bits";
|
||||||
|
const char SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS[] =
|
||||||
|
"frontend-http2-connection-window-bits";
|
||||||
|
const char SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS[] =
|
||||||
|
"backend-http2-connection-window-bits";
|
||||||
const char SHRPX_OPT_FRONTEND_NO_TLS[] = "frontend-no-tls";
|
const char SHRPX_OPT_FRONTEND_NO_TLS[] = "frontend-no-tls";
|
||||||
const char SHRPX_OPT_BACKEND_NO_TLS[] = "backend-no-tls";
|
const char SHRPX_OPT_BACKEND_NO_TLS[] = "backend-no-tls";
|
||||||
const char SHRPX_OPT_BACKEND_TLS_SNI_FIELD[] = "backend-tls-sni-field";
|
const char SHRPX_OPT_BACKEND_TLS_SNI_FIELD[] = "backend-tls-sni-field";
|
||||||
|
@ -321,6 +325,28 @@ int parse_config(const char *opt, const char *optarg)
|
||||||
<< " specify the integer in the range [0, 30], inclusive";
|
<< " specify the integer in the range [0, 30], inclusive";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
} else if(util::strieq(opt,
|
||||||
|
SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS) ||
|
||||||
|
util::strieq(opt,
|
||||||
|
SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS)) {
|
||||||
|
size_t *resp;
|
||||||
|
const char *optname;
|
||||||
|
if(util::strieq(opt, SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS)) {
|
||||||
|
resp = &mod_config()->http2_upstream_connection_window_bits;
|
||||||
|
optname = SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS;
|
||||||
|
} else {
|
||||||
|
resp = &mod_config()->http2_downstream_connection_window_bits;
|
||||||
|
optname = SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS;
|
||||||
|
}
|
||||||
|
errno = 0;
|
||||||
|
unsigned long int n = strtoul(optarg, 0, 10);
|
||||||
|
if(errno == 0 && n >= 16 && n < 31) {
|
||||||
|
*resp = n;
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "--" << optname
|
||||||
|
<< " specify the integer in the range [16, 30], inclusive";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
} else if(util::strieq(opt, SHRPX_OPT_FRONTEND_NO_TLS)) {
|
} else if(util::strieq(opt, SHRPX_OPT_FRONTEND_NO_TLS)) {
|
||||||
mod_config()->upstream_no_tls = util::strieq(optarg, "yes");
|
mod_config()->upstream_no_tls = util::strieq(optarg, "yes");
|
||||||
} else if(util::strieq(opt, SHRPX_OPT_BACKEND_NO_TLS)) {
|
} else if(util::strieq(opt, SHRPX_OPT_BACKEND_NO_TLS)) {
|
||||||
|
|
|
@ -71,6 +71,8 @@ extern const char SHRPX_OPT_ACCESSLOG[];
|
||||||
extern const char SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT[];
|
extern const char SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT[];
|
||||||
extern const char SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS[];
|
extern const char SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS[];
|
||||||
extern const char SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS[];
|
extern const char SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS[];
|
||||||
|
extern const char SHRPX_OPT_FRONTEND_HTTP2_CONNECTION_WINDOW_BITS[];
|
||||||
|
extern const char SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS[];
|
||||||
extern const char SHRPX_OPT_FRONTEND_NO_TLS[];
|
extern const char SHRPX_OPT_FRONTEND_NO_TLS[];
|
||||||
extern const char SHRPX_OPT_BACKEND_NO_TLS[];
|
extern const char SHRPX_OPT_BACKEND_NO_TLS[];
|
||||||
extern const char SHRPX_OPT_PID_FILE[];
|
extern const char SHRPX_OPT_PID_FILE[];
|
||||||
|
@ -146,6 +148,8 @@ struct Config {
|
||||||
bool accesslog;
|
bool accesslog;
|
||||||
size_t http2_upstream_window_bits;
|
size_t http2_upstream_window_bits;
|
||||||
size_t http2_downstream_window_bits;
|
size_t http2_downstream_window_bits;
|
||||||
|
size_t http2_upstream_connection_window_bits;
|
||||||
|
size_t http2_downstream_connection_window_bits;
|
||||||
bool upstream_no_tls;
|
bool upstream_no_tls;
|
||||||
bool downstream_no_tls;
|
bool downstream_no_tls;
|
||||||
char *backend_tls_sni_name;
|
char *backend_tls_sni_name;
|
||||||
|
|
|
@ -1170,6 +1170,16 @@ int Http2Session::on_connect()
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(get_config()->http2_downstream_connection_window_bits > 16) {
|
||||||
|
int32_t delta =
|
||||||
|
(1 << get_config()->http2_downstream_connection_window_bits) - 1
|
||||||
|
- NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
|
||||||
|
rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_NONE, 0, delta);
|
||||||
|
if(rv != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bufferevent_write(bev_, NGHTTP2_CLIENT_CONNECTION_HEADER,
|
bufferevent_write(bev_, NGHTTP2_CLIENT_CONNECTION_HEADER,
|
||||||
NGHTTP2_CLIENT_CONNECTION_HEADER_LEN);
|
NGHTTP2_CLIENT_CONNECTION_HEADER_LEN);
|
||||||
|
|
||||||
|
|
|
@ -513,6 +513,13 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
|
||||||
entry,
|
entry,
|
||||||
sizeof(entry)/sizeof(nghttp2_settings_entry));
|
sizeof(entry)/sizeof(nghttp2_settings_entry));
|
||||||
assert(rv == 0);
|
assert(rv == 0);
|
||||||
|
|
||||||
|
if(get_config()->http2_upstream_connection_window_bits > 16) {
|
||||||
|
int32_t delta = (1 << get_config()->http2_upstream_connection_window_bits)
|
||||||
|
- 1 - NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
|
||||||
|
rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_NONE, 0, delta);
|
||||||
|
assert(rv == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Http2Upstream::~Http2Upstream()
|
Http2Upstream::~Http2Upstream()
|
||||||
|
|
|
@ -259,27 +259,27 @@ void on_data_chunk_recv_callback(spdylay_session *session,
|
||||||
// returns 0.
|
// returns 0.
|
||||||
if(spdylay_session_get_recv_data_length(session) >
|
if(spdylay_session_get_recv_data_length(session) >
|
||||||
std::max(SPDYLAY_INITIAL_WINDOW_SIZE,
|
std::max(SPDYLAY_INITIAL_WINDOW_SIZE,
|
||||||
spdylay_session_get_local_window_size(session))) {
|
1 << get_config()->http2_upstream_connection_window_bits)) {
|
||||||
if(LOG_ENABLED(INFO)) {
|
if(LOG_ENABLED(INFO)) {
|
||||||
ULOG(INFO, upstream)
|
ULOG(INFO, upstream)
|
||||||
<< "Flow control error on connection: "
|
<< "Flow control error on connection: "
|
||||||
<< "recv_window_size="
|
<< "recv_window_size="
|
||||||
<< spdylay_session_get_recv_data_length(session)
|
<< spdylay_session_get_recv_data_length(session)
|
||||||
<< ", initial_window_size="
|
<< ", window_size="
|
||||||
<< spdylay_session_get_local_window_size(session);
|
<< (1 << get_config()->http2_upstream_connection_window_bits);
|
||||||
}
|
}
|
||||||
spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
|
spdylay_session_fail_session(session, SPDYLAY_GOAWAY_PROTOCOL_ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(spdylay_session_get_stream_recv_data_length(session, stream_id) >
|
if(spdylay_session_get_stream_recv_data_length(session, stream_id) >
|
||||||
std::max(SPDYLAY_INITIAL_WINDOW_SIZE,
|
std::max(SPDYLAY_INITIAL_WINDOW_SIZE,
|
||||||
spdylay_session_get_stream_local_window_size(session))) {
|
1 << get_config()->http2_upstream_window_bits)) {
|
||||||
if(LOG_ENABLED(INFO)) {
|
if(LOG_ENABLED(INFO)) {
|
||||||
ULOG(INFO, upstream)
|
ULOG(INFO, upstream)
|
||||||
<< "Flow control error: recv_window_size="
|
<< "Flow control error: recv_window_size="
|
||||||
<< spdylay_session_get_stream_recv_data_length(session, stream_id)
|
<< spdylay_session_get_stream_recv_data_length(session, stream_id)
|
||||||
<< ", initial_window_size="
|
<< ", initial_window_size="
|
||||||
<< spdylay_session_get_stream_local_window_size(session);
|
<< (1 << get_config()->http2_upstream_window_bits);
|
||||||
}
|
}
|
||||||
upstream->rst_stream(downstream, SPDYLAY_FLOW_CONTROL_ERROR);
|
upstream->rst_stream(downstream, SPDYLAY_FLOW_CONTROL_ERROR);
|
||||||
return;
|
return;
|
||||||
|
@ -395,10 +395,10 @@ SpdyUpstream::SpdyUpstream(uint16_t version, ClientHandler *handler)
|
||||||
rv = spdylay_session_server_new(&session_, version, &callbacks, this);
|
rv = spdylay_session_server_new(&session_, version, &callbacks, this);
|
||||||
assert(rv == 0);
|
assert(rv == 0);
|
||||||
|
|
||||||
if(version == SPDYLAY_PROTO_SPDY3) {
|
if(version >= SPDYLAY_PROTO_SPDY3) {
|
||||||
int val = 1;
|
int val = 1;
|
||||||
flow_control_ = true;
|
flow_control_ = true;
|
||||||
initial_window_size_ = (1 << get_config()->http2_upstream_window_bits) - 1;
|
initial_window_size_ = 1 << get_config()->http2_upstream_window_bits;
|
||||||
rv = spdylay_session_set_option(session_,
|
rv = spdylay_session_set_option(session_,
|
||||||
SPDYLAY_OPT_NO_AUTO_WINDOW_UPDATE, &val,
|
SPDYLAY_OPT_NO_AUTO_WINDOW_UPDATE, &val,
|
||||||
sizeof(val));
|
sizeof(val));
|
||||||
|
@ -421,6 +421,15 @@ SpdyUpstream::SpdyUpstream(uint16_t version, ClientHandler *handler)
|
||||||
(session_, SPDYLAY_FLAG_SETTINGS_NONE,
|
(session_, SPDYLAY_FLAG_SETTINGS_NONE,
|
||||||
entry, sizeof(entry)/sizeof(spdylay_settings_entry));
|
entry, sizeof(entry)/sizeof(spdylay_settings_entry));
|
||||||
assert(rv == 0);
|
assert(rv == 0);
|
||||||
|
|
||||||
|
if(version >= SPDYLAY_PROTO_SPDY3_1 &&
|
||||||
|
get_config()->http2_upstream_connection_window_bits > 16) {
|
||||||
|
int32_t delta = (1 << get_config()->http2_upstream_connection_window_bits)
|
||||||
|
- SPDYLAY_INITIAL_WINDOW_SIZE;
|
||||||
|
rv = spdylay_submit_window_update(session_, 0, delta);
|
||||||
|
assert(rv == 0);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Maybe call from outside?
|
// TODO Maybe call from outside?
|
||||||
send();
|
send();
|
||||||
}
|
}
|
||||||
|
@ -942,17 +951,15 @@ int32_t determine_window_update_transmission(spdylay_session *session,
|
||||||
int32_t recv_length, window_size;
|
int32_t recv_length, window_size;
|
||||||
if(stream_id == 0) {
|
if(stream_id == 0) {
|
||||||
recv_length = spdylay_session_get_recv_data_length(session);
|
recv_length = spdylay_session_get_recv_data_length(session);
|
||||||
window_size = spdylay_session_get_local_window_size(session);
|
window_size = 1 << get_config()->http2_upstream_connection_window_bits;
|
||||||
} else {
|
} else {
|
||||||
recv_length = spdylay_session_get_stream_recv_data_length
|
recv_length = spdylay_session_get_stream_recv_data_length
|
||||||
(session, stream_id);
|
(session, stream_id);
|
||||||
window_size = spdylay_session_get_stream_local_window_size(session);
|
window_size = 1 << get_config()->http2_upstream_window_bits;
|
||||||
}
|
}
|
||||||
if(recv_length != -1 && window_size != -1) {
|
if(recv_length != -1 && recv_length >= window_size / 2) {
|
||||||
if(recv_length >= window_size / 2) {
|
|
||||||
return recv_length;
|
return recv_length;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
Loading…
Reference in New Issue