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",
"ocsp-update-interval",
"no-ocsp",
"header-field-buffer",
"max-header-fields",
"include",
"tls-ticket-key-cipher",
"host-rewrite",
@ -110,6 +108,10 @@ OPTIONS = [
"forwarded-for",
"response-header-field-buffer",
"max-response-header-fields",
"request-header-field-buffer",
"max-request-header-fields",
"header-field-buffer",
"max-header-fields",
"no-http2-cipher-black-list"
]

View File

@ -1071,8 +1071,8 @@ void fill_default_config() {
auto &httpconf = mod_config()->http;
httpconf.server_name = "nghttpx nghttp2/" NGHTTP2_VERSION;
httpconf.no_host_rewrite = true;
httpconf.header_field_buffer = 64_k;
httpconf.max_header_fields = 100;
httpconf.request_header_field_buffer = 64_k;
httpconf.max_request_header_fields = 100;
httpconf.response_header_field_buffer = 64_k;
httpconf.max_response_header_fields = 500;
@ -1775,18 +1775,18 @@ HTTP:
won't replace anything already set. This option can be
used several times to specify multiple header fields.
Example: --add-response-header="foo: bar"
--header-field-buffer=<SIZE>
--request-header-field-buffer=<SIZE>
Set maximum buffer size for incoming HTTP request header
field list. This is the sum of header name and value in
bytes. If trailer fields exist, they are counted
towards this number.
Default: )"
<< util::utos_unit(get_config()->http.header_field_buffer) << R"(
--max-header-fields=<N>
<< util::utos_unit(get_config()->http.request_header_field_buffer) << R"(
--max-request-header-fields=<N>
Set maximum number of incoming HTTP request header
fields. If trailer fields exist, they are counted
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>
Set maximum buffer size for incoming HTTP response
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_MAX_RESPONSE_HEADER_FIELDS, required_argument, &flag, 102},
{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}};
int option_index = 0;
@ -2813,6 +2815,14 @@ int main(int argc, char **argv) {
// --no-http2-cipher-black-list
cmdcfgs.emplace_back(SHRPX_OPT_NO_HTTP2_CIPHER_BLACK_LIST, "yes");
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:
break;
}

View File

@ -726,6 +726,7 @@ enum {
SHRPX_OPTID_LISTENER_DISABLE_TIMEOUT,
SHRPX_OPTID_LOG_LEVEL,
SHRPX_OPTID_MAX_HEADER_FIELDS,
SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS,
SHRPX_OPTID_MAX_RESPONSE_HEADER_FIELDS,
SHRPX_OPTID_MRUBY_FILE,
SHRPX_OPTID_NO_HOST_REWRITE,
@ -742,6 +743,7 @@ enum {
SHRPX_OPTID_PRIVATE_KEY_PASSWD_FILE,
SHRPX_OPTID_READ_BURST,
SHRPX_OPTID_READ_RATE,
SHRPX_OPTID_REQUEST_HEADER_FIELD_BUFFER,
SHRPX_OPTID_RESPONSE_HEADER_FIELD_BUFFER,
SHRPX_OPTID_RLIMIT_NOFILE,
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)) {
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;
@ -1282,6 +1287,11 @@ int option_lookup_token(const char *name, size_t namelen) {
return SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED;
}
break;
case 'r':
if (util::strieq_l("request-header-field-buffe", name, 26)) {
return SHRPX_OPTID_REQUEST_HEADER_FIELD_BUFFER;
}
break;
case 's':
if (util::strieq_l("worker-frontend-connection", name, 26)) {
return SHRPX_OPTID_WORKER_FRONTEND_CONNECTIONS;
@ -2017,10 +2027,18 @@ int parse_config(const char *opt, const char *optarg,
return 0;
case SHRPX_OPTID_HEADER_FIELD_BUFFER:
return parse_uint_with_unit(&mod_config()->http.header_field_buffer, opt,
optarg);
LOG(WARN) << opt
<< ": 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:
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:
return parse_uint_with_unit(
&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";
constexpr static char SHRPX_OPT_FORWARDED_BY[] = "forwarded-by";
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[] =
"response-header-field-buffer";
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_response_headers;
StringRef server_name;
size_t header_field_buffer;
size_t max_header_fields;
size_t request_header_field_buffer;
size_t max_request_header_fields;
size_t response_header_field_buffer;
size_t max_response_header_fields;
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
if (promised_req.fs.buffer_size() + namelen + valuelen >
httpconf.header_field_buffer ||
promised_req.fs.num_fields() >= httpconf.max_header_fields) {
httpconf.request_header_field_buffer ||
promised_req.fs.num_fields() >= httpconf.max_request_header_fields) {
if (LOG_ENABLED(INFO)) {
DLOG(INFO, downstream)
<< "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;
if (req.fs.buffer_size() + namelen + valuelen >
httpconf.header_field_buffer ||
req.fs.num_fields() >= httpconf.max_header_fields) {
httpconf.request_header_field_buffer ||
req.fs.num_fields() >= httpconf.max_request_header_fields) {
if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
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.
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)) {
ULOG(INFO, upstream) << "Too large URI size="
<< 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 &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)) {
ULOG(INFO, upstream) << "Too large header block size="
<< 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()) {
req.fs.append_last_header_key(data, len);
} else {
if (req.fs.num_fields() >= httpconf.max_header_fields) {
if (req.fs.num_fields() >= httpconf.max_request_header_fields) {
if (LOG_ENABLED(INFO)) {
ULOG(INFO, upstream)
<< "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()) {
req.fs.append_last_trailer_key(data, len);
} else {
if (req.fs.num_fields() >= httpconf.max_header_fields) {
if (req.fs.num_fields() >= httpconf.max_request_header_fields) {
if (LOG_ENABLED(INFO)) {
ULOG(INFO, upstream)
<< "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 &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)) {
ULOG(INFO, upstream) << "Too large header block size="
<< 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
// them.
if (header_buffer > httpconf.header_field_buffer ||
num_headers > httpconf.max_header_fields) {
if (header_buffer > httpconf.request_header_field_buffer ||
num_headers > httpconf.max_request_header_fields) {
upstream->rst_stream(downstream, SPDYLAY_INTERNAL_ERROR);
return;
}