nghttpx: Add --frontend-max-requests option
This commit is contained in:
parent
e2b9590c0f
commit
9d16292fe4
|
@ -161,6 +161,7 @@ OPTIONS = [
|
||||||
"tls-min-proto-version",
|
"tls-min-proto-version",
|
||||||
"tls-max-proto-version",
|
"tls-max-proto-version",
|
||||||
"redirect-https-port",
|
"redirect-https-port",
|
||||||
|
"frontend-max-requests",
|
||||||
]
|
]
|
||||||
|
|
||||||
LOGVARS = [
|
LOGVARS = [
|
||||||
|
|
15
src/shrpx.cc
15
src/shrpx.cc
|
@ -1448,6 +1448,7 @@ void fill_default_config(Config *config) {
|
||||||
httpconf.response_header_field_buffer = 64_k;
|
httpconf.response_header_field_buffer = 64_k;
|
||||||
httpconf.max_response_header_fields = 500;
|
httpconf.max_response_header_fields = 500;
|
||||||
httpconf.redirect_https_port = StringRef::from_lit("443");
|
httpconf.redirect_https_port = StringRef::from_lit("443");
|
||||||
|
httpconf.max_requests = std::numeric_limits<size_t>::max();
|
||||||
|
|
||||||
auto &http2conf = config->http2;
|
auto &http2conf = config->http2;
|
||||||
{
|
{
|
||||||
|
@ -2581,6 +2582,13 @@ DNS:
|
||||||
lookup.
|
lookup.
|
||||||
Default: )"
|
Default: )"
|
||||||
<< config->dns.max_try << R"(
|
<< config->dns.max_try << R"(
|
||||||
|
--frontend-max-requests=<N>
|
||||||
|
The number of requests that single frontend connection
|
||||||
|
can process. For HTTP/2, this is the number of streams
|
||||||
|
in one HTTP/2 connection. For HTTP/1, this is the
|
||||||
|
number of keep alive requests. This is hint to nghttpx,
|
||||||
|
and it may allow additional few requests. The default
|
||||||
|
value is unlimited.
|
||||||
|
|
||||||
Debug:
|
Debug:
|
||||||
--frontend-http2-dump-request-header=<PATH>
|
--frontend-http2-dump-request-header=<PATH>
|
||||||
|
@ -3266,6 +3274,8 @@ int main(int argc, char **argv) {
|
||||||
{SHRPX_OPT_TLS_MAX_PROTO_VERSION.c_str(), required_argument, &flag,
|
{SHRPX_OPT_TLS_MAX_PROTO_VERSION.c_str(), required_argument, &flag,
|
||||||
153},
|
153},
|
||||||
{SHRPX_OPT_REDIRECT_HTTPS_PORT.c_str(), required_argument, &flag, 154},
|
{SHRPX_OPT_REDIRECT_HTTPS_PORT.c_str(), required_argument, &flag, 154},
|
||||||
|
{SHRPX_OPT_FRONTEND_MAX_REQUESTS.c_str(), required_argument, &flag,
|
||||||
|
155},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
|
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
@ -3992,6 +4002,11 @@ int main(int argc, char **argv) {
|
||||||
// --redirect-https-port
|
// --redirect-https-port
|
||||||
cmdcfgs.emplace_back(SHRPX_OPT_REDIRECT_HTTPS_PORT, StringRef{optarg});
|
cmdcfgs.emplace_back(SHRPX_OPT_REDIRECT_HTTPS_PORT, StringRef{optarg});
|
||||||
break;
|
break;
|
||||||
|
case 155:
|
||||||
|
// --frontend-max-requests
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_MAX_REQUESTS,
|
||||||
|
StringRef{optarg});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1817,6 +1817,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||||
return SHRPX_OPTID_TLS_TICKET_KEY_CIPHER;
|
return SHRPX_OPTID_TLS_TICKET_KEY_CIPHER;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 's':
|
||||||
|
if (util::strieq_l("frontend-max-request", name, 20)) {
|
||||||
|
return SHRPX_OPTID_FRONTEND_MAX_REQUESTS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
if (util::strieq_l("backend-write-timeou", name, 20)) {
|
if (util::strieq_l("backend-write-timeou", name, 20)) {
|
||||||
return SHRPX_OPTID_BACKEND_WRITE_TIMEOUT;
|
return SHRPX_OPTID_BACKEND_WRITE_TIMEOUT;
|
||||||
|
@ -3369,6 +3374,8 @@ int parse_config(Config *config, int optid, const StringRef &opt,
|
||||||
config->http.redirect_https_port = optarg;
|
config->http.redirect_https_port = optarg;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
case SHRPX_OPTID_FRONTEND_MAX_REQUESTS:
|
||||||
|
return parse_uint(&config->http.max_requests, opt, optarg);
|
||||||
case SHRPX_OPTID_CONF:
|
case SHRPX_OPTID_CONF:
|
||||||
LOG(WARN) << "conf: ignored";
|
LOG(WARN) << "conf: ignored";
|
||||||
|
|
||||||
|
|
|
@ -333,6 +333,8 @@ constexpr auto SHRPX_OPT_TLS_MAX_PROTO_VERSION =
|
||||||
StringRef::from_lit("tls-max-proto-version");
|
StringRef::from_lit("tls-max-proto-version");
|
||||||
constexpr auto SHRPX_OPT_REDIRECT_HTTPS_PORT =
|
constexpr auto SHRPX_OPT_REDIRECT_HTTPS_PORT =
|
||||||
StringRef::from_lit("redirect-https-port");
|
StringRef::from_lit("redirect-https-port");
|
||||||
|
constexpr auto SHRPX_OPT_FRONTEND_MAX_REQUESTS =
|
||||||
|
StringRef::from_lit("frontend-max-requests");
|
||||||
|
|
||||||
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
|
||||||
|
|
||||||
|
@ -647,6 +649,7 @@ struct HttpConfig {
|
||||||
size_t max_request_header_fields;
|
size_t max_request_header_fields;
|
||||||
size_t response_header_field_buffer;
|
size_t response_header_field_buffer;
|
||||||
size_t max_response_header_fields;
|
size_t max_response_header_fields;
|
||||||
|
size_t max_requests;
|
||||||
bool no_via;
|
bool no_via;
|
||||||
bool no_location_rewrite;
|
bool no_location_rewrite;
|
||||||
bool no_host_rewrite;
|
bool no_host_rewrite;
|
||||||
|
@ -994,6 +997,7 @@ enum {
|
||||||
SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_BITS,
|
SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_BITS,
|
||||||
SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_SIZE,
|
SHRPX_OPTID_FRONTEND_HTTP2_WINDOW_SIZE,
|
||||||
SHRPX_OPTID_FRONTEND_KEEP_ALIVE_TIMEOUT,
|
SHRPX_OPTID_FRONTEND_KEEP_ALIVE_TIMEOUT,
|
||||||
|
SHRPX_OPTID_FRONTEND_MAX_REQUESTS,
|
||||||
SHRPX_OPTID_FRONTEND_NO_TLS,
|
SHRPX_OPTID_FRONTEND_NO_TLS,
|
||||||
SHRPX_OPTID_FRONTEND_READ_TIMEOUT,
|
SHRPX_OPTID_FRONTEND_READ_TIMEOUT,
|
||||||
SHRPX_OPTID_FRONTEND_WRITE_TIMEOUT,
|
SHRPX_OPTID_FRONTEND_WRITE_TIMEOUT,
|
||||||
|
|
|
@ -271,16 +271,21 @@ int on_begin_headers_callback(nghttp2_session *session,
|
||||||
<< frame->hd.stream_id;
|
<< frame->hd.stream_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto handler = upstream->get_client_handler();
|
upstream->on_start_request(frame);
|
||||||
|
|
||||||
auto downstream = make_unique<Downstream>(upstream, handler->get_mcpool(),
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void Http2Upstream::on_start_request(const nghttp2_frame *frame) {
|
||||||
|
auto downstream = make_unique<Downstream>(this, handler_->get_mcpool(),
|
||||||
frame->hd.stream_id);
|
frame->hd.stream_id);
|
||||||
nghttp2_session_set_stream_user_data(session, frame->hd.stream_id,
|
nghttp2_session_set_stream_user_data(session_, frame->hd.stream_id,
|
||||||
downstream.get());
|
downstream.get());
|
||||||
|
|
||||||
downstream->reset_upstream_rtimer();
|
downstream->reset_upstream_rtimer();
|
||||||
|
|
||||||
handler->repeat_read_timer();
|
handler_->repeat_read_timer();
|
||||||
|
|
||||||
auto &req = downstream->request();
|
auto &req = downstream->request();
|
||||||
|
|
||||||
|
@ -289,11 +294,16 @@ int on_begin_headers_callback(nghttp2_session *session,
|
||||||
req.http_major = 2;
|
req.http_major = 2;
|
||||||
req.http_minor = 0;
|
req.http_minor = 0;
|
||||||
|
|
||||||
upstream->add_pending_downstream(std::move(downstream));
|
add_pending_downstream(std::move(downstream));
|
||||||
|
|
||||||
return 0;
|
++num_requests_;
|
||||||
|
|
||||||
|
auto config = get_config();
|
||||||
|
auto &httpconf = config->http;
|
||||||
|
if (httpconf.max_requests <= num_requests_) {
|
||||||
|
start_graceful_shutdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace
|
|
||||||
|
|
||||||
int Http2Upstream::on_request_headers(Downstream *downstream,
|
int Http2Upstream::on_request_headers(Downstream *downstream,
|
||||||
const nghttp2_frame *frame) {
|
const nghttp2_frame *frame) {
|
||||||
|
@ -873,8 +883,6 @@ void Http2Upstream::submit_goaway() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Http2Upstream::check_shutdown() {
|
void Http2Upstream::check_shutdown() {
|
||||||
int rv;
|
|
||||||
|
|
||||||
auto worker = handler_->get_worker();
|
auto worker = handler_->get_worker();
|
||||||
|
|
||||||
if (!worker->get_graceful_shutdown()) {
|
if (!worker->get_graceful_shutdown()) {
|
||||||
|
@ -883,6 +891,15 @@ void Http2Upstream::check_shutdown() {
|
||||||
|
|
||||||
ev_prepare_stop(handler_->get_loop(), &prep_);
|
ev_prepare_stop(handler_->get_loop(), &prep_);
|
||||||
|
|
||||||
|
start_graceful_shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Http2Upstream::start_graceful_shutdown() {
|
||||||
|
int rv;
|
||||||
|
if (ev_is_active(&shutdown_timer_)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rv = nghttp2_submit_shutdown_notice(session_);
|
rv = nghttp2_submit_shutdown_notice(session_);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
ULOG(FATAL, this) << "nghttp2_submit_shutdown_notice() failed: "
|
ULOG(FATAL, this) << "nghttp2_submit_shutdown_notice() failed: "
|
||||||
|
@ -965,7 +982,8 @@ Http2Upstream::Http2Upstream(ClientHandler *handler)
|
||||||
!get_config()->http2_proxy),
|
!get_config()->http2_proxy),
|
||||||
handler_(handler),
|
handler_(handler),
|
||||||
session_(nullptr),
|
session_(nullptr),
|
||||||
max_buffer_size_(MAX_BUFFER_SIZE) {
|
max_buffer_size_(MAX_BUFFER_SIZE),
|
||||||
|
num_requests_(0) {
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
auto config = get_config();
|
auto config = get_config();
|
||||||
|
|
|
@ -111,11 +111,15 @@ public:
|
||||||
|
|
||||||
void submit_goaway();
|
void submit_goaway();
|
||||||
void check_shutdown();
|
void check_shutdown();
|
||||||
|
// Starts graceful shutdown period.
|
||||||
|
void start_graceful_shutdown();
|
||||||
|
|
||||||
int prepare_push_promise(Downstream *downstream);
|
int prepare_push_promise(Downstream *downstream);
|
||||||
int submit_push_promise(const StringRef &scheme, const StringRef &authority,
|
int submit_push_promise(const StringRef &scheme, const StringRef &authority,
|
||||||
const StringRef &path, Downstream *downstream);
|
const StringRef &path, Downstream *downstream);
|
||||||
|
|
||||||
|
// Called when new request has started.
|
||||||
|
void on_start_request(const nghttp2_frame *frame);
|
||||||
int on_request_headers(Downstream *downstream, const nghttp2_frame *frame);
|
int on_request_headers(Downstream *downstream, const nghttp2_frame *frame);
|
||||||
|
|
||||||
DefaultMemchunks *get_response_buf();
|
DefaultMemchunks *get_response_buf();
|
||||||
|
@ -134,6 +138,8 @@ private:
|
||||||
ClientHandler *handler_;
|
ClientHandler *handler_;
|
||||||
nghttp2_session *session_;
|
nghttp2_session *session_;
|
||||||
size_t max_buffer_size_;
|
size_t max_buffer_size_;
|
||||||
|
// The number of requests seen so far.
|
||||||
|
size_t num_requests_;
|
||||||
bool flow_control_;
|
bool flow_control_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,8 @@ namespace shrpx {
|
||||||
HttpsUpstream::HttpsUpstream(ClientHandler *handler)
|
HttpsUpstream::HttpsUpstream(ClientHandler *handler)
|
||||||
: handler_(handler),
|
: handler_(handler),
|
||||||
current_header_length_(0),
|
current_header_length_(0),
|
||||||
ioctrl_(handler->get_rlimit()) {
|
ioctrl_(handler->get_rlimit()),
|
||||||
|
num_requests_(0) {
|
||||||
http_parser_init(&htp_, HTTP_REQUEST);
|
http_parser_init(&htp_, HTTP_REQUEST);
|
||||||
htp_.data = this;
|
htp_.data = this;
|
||||||
}
|
}
|
||||||
|
@ -63,27 +64,30 @@ void HttpsUpstream::reset_current_header_length() {
|
||||||
current_header_length_ = 0;
|
current_header_length_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
void HttpsUpstream::on_start_request() {
|
||||||
int htp_msg_begin(http_parser *htp) {
|
|
||||||
auto upstream = static_cast<HttpsUpstream *>(htp->data);
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
ULOG(INFO, upstream) << "HTTP request started";
|
ULOG(INFO, this) << "HTTP request started";
|
||||||
}
|
}
|
||||||
upstream->reset_current_header_length();
|
reset_current_header_length();
|
||||||
|
|
||||||
auto handler = upstream->get_client_handler();
|
auto downstream = make_unique<Downstream>(this, handler_->get_mcpool(), 0);
|
||||||
|
|
||||||
auto downstream = make_unique<Downstream>(upstream, handler->get_mcpool(), 0);
|
attach_downstream(std::move(downstream));
|
||||||
|
|
||||||
upstream->attach_downstream(std::move(downstream));
|
auto conn = handler_->get_connection();
|
||||||
|
|
||||||
auto conn = handler->get_connection();
|
|
||||||
auto &upstreamconf = get_config()->conn.upstream;
|
auto &upstreamconf = get_config()->conn.upstream;
|
||||||
|
|
||||||
conn->rt.repeat = upstreamconf.timeout.read;
|
conn->rt.repeat = upstreamconf.timeout.read;
|
||||||
|
|
||||||
handler->repeat_read_timer();
|
handler_->repeat_read_timer();
|
||||||
|
|
||||||
|
++num_requests_;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int htp_msg_begin(http_parser *htp) {
|
||||||
|
auto upstream = static_cast<HttpsUpstream *>(htp->data);
|
||||||
|
upstream->on_start_request();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -868,12 +872,14 @@ int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||||
auto &resp = downstream->response();
|
auto &resp = downstream->response();
|
||||||
auto &balloc = downstream->get_block_allocator();
|
auto &balloc = downstream->get_block_allocator();
|
||||||
auto config = get_config();
|
auto config = get_config();
|
||||||
|
auto &httpconf = config->http;
|
||||||
|
|
||||||
auto connection_close = false;
|
auto connection_close = false;
|
||||||
|
|
||||||
auto worker = handler_->get_worker();
|
auto worker = handler_->get_worker();
|
||||||
|
|
||||||
if (worker->get_graceful_shutdown()) {
|
if (httpconf.max_requests <= num_requests_ &&
|
||||||
|
worker->get_graceful_shutdown()) {
|
||||||
resp.fs.add_header_token(StringRef::from_lit("connection"),
|
resp.fs.add_header_token(StringRef::from_lit("connection"),
|
||||||
StringRef::from_lit("close"), false,
|
StringRef::from_lit("close"), false,
|
||||||
http2::HD_CONNECTION);
|
http2::HD_CONNECTION);
|
||||||
|
@ -917,8 +923,6 @@ int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||||
output->append("\r\n");
|
output->append("\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &httpconf = config->http;
|
|
||||||
|
|
||||||
for (auto &p : httpconf.add_response_headers) {
|
for (auto &p : httpconf.add_response_headers) {
|
||||||
output->append(p.name);
|
output->append(p.name);
|
||||||
output->append(": ");
|
output->append(": ");
|
||||||
|
@ -1078,7 +1082,8 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
|
|
||||||
// after graceful shutdown commenced, add connection: close header
|
// after graceful shutdown commenced, add connection: close header
|
||||||
// field.
|
// field.
|
||||||
if (worker->get_graceful_shutdown()) {
|
if (httpconf.max_requests <= num_requests_ ||
|
||||||
|
worker->get_graceful_shutdown()) {
|
||||||
resp.connection_close = true;
|
resp.connection_close = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,12 +95,17 @@ public:
|
||||||
void log_response_headers(DefaultMemchunks *buf) const;
|
void log_response_headers(DefaultMemchunks *buf) const;
|
||||||
int redirect_to_https(Downstream *downstream);
|
int redirect_to_https(Downstream *downstream);
|
||||||
|
|
||||||
|
// Called when new request has started.
|
||||||
|
void on_start_request();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ClientHandler *handler_;
|
ClientHandler *handler_;
|
||||||
http_parser htp_;
|
http_parser htp_;
|
||||||
size_t current_header_length_;
|
size_t current_header_length_;
|
||||||
std::unique_ptr<Downstream> downstream_;
|
std::unique_ptr<Downstream> downstream_;
|
||||||
IOControl ioctrl_;
|
IOControl ioctrl_;
|
||||||
|
// The number of requests seen so far.
|
||||||
|
size_t num_requests_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
Loading…
Reference in New Issue