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:
Tatsuhiro Tsujikawa 2016-02-06 17:22:23 +09:00
parent 8741503db1
commit ee07694783
8 changed files with 60 additions and 24 deletions

View File

@ -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"
] ]

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;

View File

@ -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="

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;
} }