nghttpx: Add request-header-field-buffer and max-request-header-fields options
This commit adds request-header-field-buffer and max-request-header-fields, and deprecates header-field-buffer and max-header-fields options.
This commit is contained in:
parent
8741503db1
commit
ee07694783
|
@ -88,8 +88,6 @@ OPTIONS = [
|
||||||
"fetch-ocsp-response-file",
|
"fetch-ocsp-response-file",
|
||||||
"ocsp-update-interval",
|
"ocsp-update-interval",
|
||||||
"no-ocsp",
|
"no-ocsp",
|
||||||
"header-field-buffer",
|
|
||||||
"max-header-fields",
|
|
||||||
"include",
|
"include",
|
||||||
"tls-ticket-key-cipher",
|
"tls-ticket-key-cipher",
|
||||||
"host-rewrite",
|
"host-rewrite",
|
||||||
|
@ -110,6 +108,10 @@ OPTIONS = [
|
||||||
"forwarded-for",
|
"forwarded-for",
|
||||||
"response-header-field-buffer",
|
"response-header-field-buffer",
|
||||||
"max-response-header-fields",
|
"max-response-header-fields",
|
||||||
|
"request-header-field-buffer",
|
||||||
|
"max-request-header-fields",
|
||||||
|
"header-field-buffer",
|
||||||
|
"max-header-fields",
|
||||||
"no-http2-cipher-black-list"
|
"no-http2-cipher-black-list"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
22
src/shrpx.cc
22
src/shrpx.cc
|
@ -1071,8 +1071,8 @@ void fill_default_config() {
|
||||||
auto &httpconf = mod_config()->http;
|
auto &httpconf = mod_config()->http;
|
||||||
httpconf.server_name = "nghttpx nghttp2/" NGHTTP2_VERSION;
|
httpconf.server_name = "nghttpx nghttp2/" NGHTTP2_VERSION;
|
||||||
httpconf.no_host_rewrite = true;
|
httpconf.no_host_rewrite = true;
|
||||||
httpconf.header_field_buffer = 64_k;
|
httpconf.request_header_field_buffer = 64_k;
|
||||||
httpconf.max_header_fields = 100;
|
httpconf.max_request_header_fields = 100;
|
||||||
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;
|
||||||
|
|
||||||
|
@ -1775,18 +1775,18 @@ HTTP:
|
||||||
won't replace anything already set. This option can be
|
won't replace anything already set. This option can be
|
||||||
used several times to specify multiple header fields.
|
used several times to specify multiple header fields.
|
||||||
Example: --add-response-header="foo: bar"
|
Example: --add-response-header="foo: bar"
|
||||||
--header-field-buffer=<SIZE>
|
--request-header-field-buffer=<SIZE>
|
||||||
Set maximum buffer size for incoming HTTP request header
|
Set maximum buffer size for incoming HTTP request header
|
||||||
field list. This is the sum of header name and value in
|
field list. This is the sum of header name and value in
|
||||||
bytes. If trailer fields exist, they are counted
|
bytes. If trailer fields exist, they are counted
|
||||||
towards this number.
|
towards this number.
|
||||||
Default: )"
|
Default: )"
|
||||||
<< util::utos_unit(get_config()->http.header_field_buffer) << R"(
|
<< util::utos_unit(get_config()->http.request_header_field_buffer) << R"(
|
||||||
--max-header-fields=<N>
|
--max-request-header-fields=<N>
|
||||||
Set maximum number of incoming HTTP request header
|
Set maximum number of incoming HTTP request header
|
||||||
fields. If trailer fields exist, they are counted
|
fields. If trailer fields exist, they are counted
|
||||||
towards this number.
|
towards this number.
|
||||||
Default: )" << get_config()->http.max_header_fields << R"(
|
Default: )" << get_config()->http.max_request_header_fields << R"(
|
||||||
--response-header-field-buffer=<SIZE>
|
--response-header-field-buffer=<SIZE>
|
||||||
Set maximum buffer size for incoming HTTP response
|
Set maximum buffer size for incoming HTTP response
|
||||||
header field list. This is the sum of header name and
|
header field list. This is the sum of header name and
|
||||||
|
@ -2372,6 +2372,8 @@ int main(int argc, char **argv) {
|
||||||
{SHRPX_OPT_RESPONSE_HEADER_FIELD_BUFFER, required_argument, &flag, 101},
|
{SHRPX_OPT_RESPONSE_HEADER_FIELD_BUFFER, required_argument, &flag, 101},
|
||||||
{SHRPX_OPT_MAX_RESPONSE_HEADER_FIELDS, required_argument, &flag, 102},
|
{SHRPX_OPT_MAX_RESPONSE_HEADER_FIELDS, required_argument, &flag, 102},
|
||||||
{SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST, no_argument, &flag, 103},
|
{SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST, no_argument, &flag, 103},
|
||||||
|
{SHRPX_OPT_REQUEST_HEADER_FIELD_BUFFER, required_argument, &flag, 104},
|
||||||
|
{SHRPX_OPT_MAX_REQUEST_HEADER_FIELDS, required_argument, &flag, 105},
|
||||||
{nullptr, 0, nullptr, 0}};
|
{nullptr, 0, nullptr, 0}};
|
||||||
|
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
|
@ -2813,6 +2815,14 @@ int main(int argc, char **argv) {
|
||||||
// --no-http2-cipher-black-list
|
// --no-http2-cipher-black-list
|
||||||
cmdcfgs.emplace_back(SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST, "yes");
|
cmdcfgs.emplace_back(SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST, "yes");
|
||||||
break;
|
break;
|
||||||
|
case 104:
|
||||||
|
// --request-header-field-buffer
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_REQUEST_HEADER_FIELD_BUFFER, optarg);
|
||||||
|
break;
|
||||||
|
case 105:
|
||||||
|
// --max-request-header-fields
|
||||||
|
cmdcfgs.emplace_back(SHRPX_OPT_MAX_REQUEST_HEADER_FIELDS, optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -726,6 +726,7 @@ enum {
|
||||||
SHRPX_OPTID_LISTENER_DISABLE_TIMEOUT,
|
SHRPX_OPTID_LISTENER_DISABLE_TIMEOUT,
|
||||||
SHRPX_OPTID_LOG_LEVEL,
|
SHRPX_OPTID_LOG_LEVEL,
|
||||||
SHRPX_OPTID_MAX_HEADER_FIELDS,
|
SHRPX_OPTID_MAX_HEADER_FIELDS,
|
||||||
|
SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS,
|
||||||
SHRPX_OPTID_MAX_RESPONSE_HEADER_FIELDS,
|
SHRPX_OPTID_MAX_RESPONSE_HEADER_FIELDS,
|
||||||
SHRPX_OPTID_MRUBY_FILE,
|
SHRPX_OPTID_MRUBY_FILE,
|
||||||
SHRPX_OPTID_NO_HOST_REWRITE,
|
SHRPX_OPTID_NO_HOST_REWRITE,
|
||||||
|
@ -742,6 +743,7 @@ enum {
|
||||||
SHRPX_OPTID_PRIVATE_KEY_PASSWD_FILE,
|
SHRPX_OPTID_PRIVATE_KEY_PASSWD_FILE,
|
||||||
SHRPX_OPTID_READ_BURST,
|
SHRPX_OPTID_READ_BURST,
|
||||||
SHRPX_OPTID_READ_RATE,
|
SHRPX_OPTID_READ_RATE,
|
||||||
|
SHRPX_OPTID_REQUEST_HEADER_FIELD_BUFFER,
|
||||||
SHRPX_OPTID_RESPONSE_HEADER_FIELD_BUFFER,
|
SHRPX_OPTID_RESPONSE_HEADER_FIELD_BUFFER,
|
||||||
SHRPX_OPTID_RLIMIT_NOFILE,
|
SHRPX_OPTID_RLIMIT_NOFILE,
|
||||||
SHRPX_OPTID_STREAM_READ_TIMEOUT,
|
SHRPX_OPTID_STREAM_READ_TIMEOUT,
|
||||||
|
@ -1252,6 +1254,9 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||||
if (util::strieq_l("backend-http2-window-bit", name, 24)) {
|
if (util::strieq_l("backend-http2-window-bit", name, 24)) {
|
||||||
return SHRPX_OPTID_BACKEND_HTTP2_WINDOW_BITS;
|
return SHRPX_OPTID_BACKEND_HTTP2_WINDOW_BITS;
|
||||||
}
|
}
|
||||||
|
if (util::strieq_l("max-request-header-field", name, 24)) {
|
||||||
|
return SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1282,6 +1287,11 @@ int option_lookup_token(const char *name, size_t namelen) {
|
||||||
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED;
|
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
if (util::strieq_l("request-header-field-buffe", name, 26)) {
|
||||||
|
return SHRPX_OPTID_REQUEST_HEADER_FIELD_BUFFER;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
if (util::strieq_l("worker-frontend-connection", name, 26)) {
|
if (util::strieq_l("worker-frontend-connection", name, 26)) {
|
||||||
return SHRPX_OPTID_WORKER_FRONTEND_CONNECTIONS;
|
return SHRPX_OPTID_WORKER_FRONTEND_CONNECTIONS;
|
||||||
|
@ -2017,10 +2027,18 @@ int parse_config(const char *opt, const char *optarg,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
case SHRPX_OPTID_HEADER_FIELD_BUFFER:
|
case SHRPX_OPTID_HEADER_FIELD_BUFFER:
|
||||||
return parse_uint_with_unit(&mod_config()->http.header_field_buffer, opt,
|
LOG(WARN) << opt
|
||||||
optarg);
|
<< ": deprecated. Use request-header-field-buffer instead.";
|
||||||
|
// fall through
|
||||||
|
case SHRPX_OPTID_REQUEST_HEADER_FIELD_BUFFER:
|
||||||
|
return parse_uint_with_unit(&mod_config()->http.request_header_field_buffer,
|
||||||
|
opt, optarg);
|
||||||
case SHRPX_OPTID_MAX_HEADER_FIELDS:
|
case SHRPX_OPTID_MAX_HEADER_FIELDS:
|
||||||
return parse_uint(&mod_config()->http.max_header_fields, opt, optarg);
|
LOG(WARN) << opt << ": deprecated. Use max-request-header-fields instead.";
|
||||||
|
// fall through
|
||||||
|
case SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS:
|
||||||
|
return parse_uint(&mod_config()->http.max_request_header_fields, opt,
|
||||||
|
optarg);
|
||||||
case SHRPX_OPTID_RESPONSE_HEADER_FIELD_BUFFER:
|
case SHRPX_OPTID_RESPONSE_HEADER_FIELD_BUFFER:
|
||||||
return parse_uint_with_unit(
|
return parse_uint_with_unit(
|
||||||
&mod_config()->http.response_header_field_buffer, opt, optarg);
|
&mod_config()->http.response_header_field_buffer, opt, optarg);
|
||||||
|
|
|
@ -196,6 +196,10 @@ constexpr char SHRPX_OPT_STRIP_INCOMING_FORWARDED[] =
|
||||||
"strip-incoming-forwarded";
|
"strip-incoming-forwarded";
|
||||||
constexpr static char SHRPX_OPT_FORWARDED_BY[] = "forwarded-by";
|
constexpr static char SHRPX_OPT_FORWARDED_BY[] = "forwarded-by";
|
||||||
constexpr char SHRPX_OPT_FORWARDED_FOR[] = "forwarded-for";
|
constexpr char SHRPX_OPT_FORWARDED_FOR[] = "forwarded-for";
|
||||||
|
constexpr char SHRPX_OPT_REQUEST_HEADER_FIELD_BUFFER[] =
|
||||||
|
"request-header-field-buffer";
|
||||||
|
constexpr char SHRPX_OPT_MAX_REQUEST_HEADER_FIELDS[] =
|
||||||
|
"max-request-header-fields";
|
||||||
constexpr char SHRPX_OPT_RESPONSE_HEADER_FIELD_BUFFER[] =
|
constexpr char SHRPX_OPT_RESPONSE_HEADER_FIELD_BUFFER[] =
|
||||||
"response-header-field-buffer";
|
"response-header-field-buffer";
|
||||||
constexpr char SHRPX_OPT_MAX_RESPONSE_HEADER_FIELDS[] =
|
constexpr char SHRPX_OPT_MAX_RESPONSE_HEADER_FIELDS[] =
|
||||||
|
@ -425,8 +429,8 @@ struct HttpConfig {
|
||||||
std::vector<std::pair<std::string, std::string>> add_request_headers;
|
std::vector<std::pair<std::string, std::string>> add_request_headers;
|
||||||
std::vector<std::pair<std::string, std::string>> add_response_headers;
|
std::vector<std::pair<std::string, std::string>> add_response_headers;
|
||||||
StringRef server_name;
|
StringRef server_name;
|
||||||
size_t header_field_buffer;
|
size_t request_header_field_buffer;
|
||||||
size_t max_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;
|
||||||
bool no_via;
|
bool no_via;
|
||||||
|
|
|
@ -784,8 +784,8 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||||
|
|
||||||
// We use request header limit for PUSH_PROMISE
|
// We use request header limit for PUSH_PROMISE
|
||||||
if (promised_req.fs.buffer_size() + namelen + valuelen >
|
if (promised_req.fs.buffer_size() + namelen + valuelen >
|
||||||
httpconf.header_field_buffer ||
|
httpconf.request_header_field_buffer ||
|
||||||
promised_req.fs.num_fields() >= httpconf.max_header_fields) {
|
promised_req.fs.num_fields() >= httpconf.max_request_header_fields) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
DLOG(INFO, downstream)
|
DLOG(INFO, downstream)
|
||||||
<< "Too large or many header field size="
|
<< "Too large or many header field size="
|
||||||
|
|
|
@ -177,8 +177,8 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||||
auto &httpconf = get_config()->http;
|
auto &httpconf = get_config()->http;
|
||||||
|
|
||||||
if (req.fs.buffer_size() + namelen + valuelen >
|
if (req.fs.buffer_size() + namelen + valuelen >
|
||||||
httpconf.header_field_buffer ||
|
httpconf.request_header_field_buffer ||
|
||||||
req.fs.num_fields() >= httpconf.max_header_fields) {
|
req.fs.num_fields() >= httpconf.max_request_header_fields) {
|
||||||
if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,8 @@ int htp_uricb(http_parser *htp, const char *data, size_t len) {
|
||||||
// We happen to have the same value for method token.
|
// We happen to have the same value for method token.
|
||||||
req.method = htp->method;
|
req.method = htp->method;
|
||||||
|
|
||||||
if (req.fs.buffer_size() + len > get_config()->http.header_field_buffer) {
|
if (req.fs.buffer_size() + len >
|
||||||
|
get_config()->http.request_header_field_buffer) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
ULOG(INFO, upstream) << "Too large URI size="
|
ULOG(INFO, upstream) << "Too large URI size="
|
||||||
<< req.fs.buffer_size() + len;
|
<< req.fs.buffer_size() + len;
|
||||||
|
@ -118,7 +119,7 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
||||||
auto &req = downstream->request();
|
auto &req = downstream->request();
|
||||||
auto &httpconf = get_config()->http;
|
auto &httpconf = get_config()->http;
|
||||||
|
|
||||||
if (req.fs.buffer_size() + len > httpconf.header_field_buffer) {
|
if (req.fs.buffer_size() + len > httpconf.request_header_field_buffer) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
ULOG(INFO, upstream) << "Too large header block size="
|
ULOG(INFO, upstream) << "Too large header block size="
|
||||||
<< req.fs.buffer_size() + len;
|
<< req.fs.buffer_size() + len;
|
||||||
|
@ -132,7 +133,7 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
||||||
if (req.fs.header_key_prev()) {
|
if (req.fs.header_key_prev()) {
|
||||||
req.fs.append_last_header_key(data, len);
|
req.fs.append_last_header_key(data, len);
|
||||||
} else {
|
} else {
|
||||||
if (req.fs.num_fields() >= httpconf.max_header_fields) {
|
if (req.fs.num_fields() >= httpconf.max_request_header_fields) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
ULOG(INFO, upstream)
|
ULOG(INFO, upstream)
|
||||||
<< "Too many header field num=" << req.fs.num_fields() + 1;
|
<< "Too many header field num=" << req.fs.num_fields() + 1;
|
||||||
|
@ -148,7 +149,7 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
||||||
if (req.fs.trailer_key_prev()) {
|
if (req.fs.trailer_key_prev()) {
|
||||||
req.fs.append_last_trailer_key(data, len);
|
req.fs.append_last_trailer_key(data, len);
|
||||||
} else {
|
} else {
|
||||||
if (req.fs.num_fields() >= httpconf.max_header_fields) {
|
if (req.fs.num_fields() >= httpconf.max_request_header_fields) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
ULOG(INFO, upstream)
|
ULOG(INFO, upstream)
|
||||||
<< "Too many header field num=" << req.fs.num_fields() + 1;
|
<< "Too many header field num=" << req.fs.num_fields() + 1;
|
||||||
|
@ -168,7 +169,8 @@ int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
|
||||||
auto downstream = upstream->get_downstream();
|
auto downstream = upstream->get_downstream();
|
||||||
auto &req = downstream->request();
|
auto &req = downstream->request();
|
||||||
|
|
||||||
if (req.fs.buffer_size() + len > get_config()->http.header_field_buffer) {
|
if (req.fs.buffer_size() + len >
|
||||||
|
get_config()->http.request_header_field_buffer) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
ULOG(INFO, upstream) << "Too large header block size="
|
ULOG(INFO, upstream) << "Too large header block size="
|
||||||
<< req.fs.buffer_size() + len;
|
<< req.fs.buffer_size() + len;
|
||||||
|
|
|
@ -181,8 +181,8 @@ void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
|
||||||
|
|
||||||
// spdy does not define usage of trailer fields, and we ignores
|
// spdy does not define usage of trailer fields, and we ignores
|
||||||
// them.
|
// them.
|
||||||
if (header_buffer > httpconf.header_field_buffer ||
|
if (header_buffer > httpconf.request_header_field_buffer ||
|
||||||
num_headers > httpconf.max_header_fields) {
|
num_headers > httpconf.max_request_header_fields) {
|
||||||
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
|
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue