nghttpx: Add --header-field-buffer and --max-header-fields options
This commit is contained in:
parent
f9a50333d2
commit
552f675466
22
src/shrpx.cc
22
src/shrpx.cc
|
@ -912,6 +912,8 @@ void fill_default_config() {
|
|||
mod_config()->fetch_ocsp_response_file =
|
||||
strcopy(PKGDATADIR "/fetch-ocsp-response");
|
||||
mod_config()->no_ocsp = false;
|
||||
mod_config()->header_field_buffer = 64 * 1024;
|
||||
mod_config()->max_header_fields = 100;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
@ -1336,6 +1338,16 @@ 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>
|
||||
Set maximum buffer size for incoming HTTP header field
|
||||
list. This is the sum of header name and value in
|
||||
bytes.
|
||||
Default: )"
|
||||
<< util::utos_with_unit(get_config()->header_field_buffer) << R"(
|
||||
--max-header-fields=<N>
|
||||
Set maximum number of incoming HTTP header fields, which
|
||||
appear in one request or response header field list.
|
||||
Default: )" << get_config()->max_header_fields << R"(
|
||||
|
||||
Debug:
|
||||
--frontend-http2-dump-request-header=<PATH>
|
||||
|
@ -1496,6 +1508,8 @@ int main(int argc, char **argv) {
|
|||
{"fetch-ocsp-response-file", required_argument, &flag, 77},
|
||||
{"ocsp-update-interval", required_argument, &flag, 78},
|
||||
{"no-ocsp", no_argument, &flag, 79},
|
||||
{"header-field-buffer", required_argument, &flag, 80},
|
||||
{"max-header-fields", required_argument, &flag, 81},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
|
||||
int option_index = 0;
|
||||
|
@ -1846,6 +1860,14 @@ int main(int argc, char **argv) {
|
|||
// --no-ocsp
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_NO_OCSP, "yes");
|
||||
break;
|
||||
case 80:
|
||||
// --header-field-buffer
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_HEADER_FIELD_BUFFER, optarg);
|
||||
break;
|
||||
case 81:
|
||||
// --max-header-fields
|
||||
cmdcfgs.emplace_back(SHRPX_OPT_MAX_HEADER_FIELDS, optarg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -150,6 +150,8 @@ const char SHRPX_OPT_BACKEND_HTTP2_CONNECTIONS_PER_WORKER[] =
|
|||
const char SHRPX_OPT_FETCH_OCSP_RESPONSE_FILE[] = "fetch-ocsp-response-file";
|
||||
const char SHRPX_OPT_OCSP_UPDATE_INTERVAL[] = "ocsp-update-interval";
|
||||
const char SHRPX_OPT_NO_OCSP[] = "no-ocsp";
|
||||
const char SHRPX_OPT_HEADER_FIELD_BUFFER[] = "header-field-buffer";
|
||||
const char SHRPX_OPT_MAX_HEADER_FIELDS[] = "max-header-fields";
|
||||
|
||||
namespace {
|
||||
Config *config = nullptr;
|
||||
|
@ -1212,6 +1214,15 @@ int parse_config(const char *opt, const char *optarg) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (util::strieq(opt, SHRPX_OPT_HEADER_FIELD_BUFFER)) {
|
||||
return parse_uint_with_unit(&mod_config()->header_field_buffer, opt,
|
||||
optarg);
|
||||
}
|
||||
|
||||
if (util::strieq(opt, SHRPX_OPT_MAX_HEADER_FIELDS)) {
|
||||
return parse_uint(&mod_config()->max_header_fields, opt, optarg);
|
||||
}
|
||||
|
||||
if (util::strieq(opt, "conf")) {
|
||||
LOG(WARN) << "conf: ignored";
|
||||
|
||||
|
|
|
@ -139,6 +139,8 @@ extern const char SHRPX_OPT_BACKEND_HTTP2_CONNECTIONS_PER_WORKER[];
|
|||
extern const char SHRPX_OPT_FETCH_OCSP_RESPONSE_FILE[];
|
||||
extern const char SHRPX_OPT_OCSP_UPDATE_INTERVAL[];
|
||||
extern const char SHRPX_OPT_NO_OCSP[];
|
||||
extern const char SHRPX_OPT_HEADER_FIELD_BUFFER[];
|
||||
extern const char SHRPX_OPT_MAX_HEADER_FIELDS[];
|
||||
|
||||
union sockaddr_union {
|
||||
sockaddr_storage storage;
|
||||
|
@ -282,6 +284,8 @@ struct Config {
|
|||
size_t rlimit_nofile;
|
||||
size_t downstream_request_buffer_size;
|
||||
size_t downstream_response_buffer_size;
|
||||
size_t header_field_buffer;
|
||||
size_t max_header_fields;
|
||||
// Bit mask to disable SSL/TLS protocol versions. This will be
|
||||
// passed to SSL_CTX_set_options().
|
||||
long int tls_proto_mask;
|
||||
|
|
|
@ -286,9 +286,6 @@ public:
|
|||
// Change the priority of downstream
|
||||
int change_priority(int32_t pri);
|
||||
|
||||
// Maximum buffer size for header name/value pairs.
|
||||
static constexpr size_t MAX_HEADERS_SUM = 128 * 1024;
|
||||
|
||||
bool get_rst_stream_after_end_stream() const;
|
||||
void set_rst_stream_after_end_stream(bool f);
|
||||
|
||||
|
|
|
@ -733,10 +733,15 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
|||
auto trailer = frame->headers.cat != NGHTTP2_HCAT_RESPONSE &&
|
||||
!downstream->get_expect_final_response();
|
||||
|
||||
if (downstream->get_response_headers_sum() > Downstream::MAX_HEADERS_SUM) {
|
||||
if (downstream->get_response_headers_sum() + namelen + valuelen >
|
||||
get_config()->header_field_buffer ||
|
||||
downstream->get_response_headers().size() >=
|
||||
get_config()->max_header_fields) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DLOG(INFO, downstream) << "Too large header block size="
|
||||
<< downstream->get_response_headers_sum();
|
||||
DLOG(INFO, downstream)
|
||||
<< "Too large or many header field size="
|
||||
<< downstream->get_response_headers_sum() + namelen + valuelen
|
||||
<< ", num=" << downstream->get_response_headers().size() + 1;
|
||||
}
|
||||
|
||||
if (trailer) {
|
||||
|
|
|
@ -202,14 +202,19 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (downstream->get_request_headers_sum() > Downstream::MAX_HEADERS_SUM) {
|
||||
if (downstream->get_request_headers_sum() + namelen + valuelen >
|
||||
get_config()->header_field_buffer ||
|
||||
downstream->get_request_headers().size() >=
|
||||
get_config()->max_header_fields) {
|
||||
if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
ULOG(INFO, upstream) << "Too large header block size="
|
||||
<< downstream->get_request_headers_sum();
|
||||
ULOG(INFO, upstream) << "Too large or many header field size="
|
||||
<< downstream->get_request_headers_sum() + namelen +
|
||||
valuelen << ", num="
|
||||
<< downstream->get_request_headers().size() + 1;
|
||||
}
|
||||
|
||||
// just ignore header fields if this is trailer part.
|
||||
|
|
|
@ -582,10 +582,29 @@ int htp_hdrs_completecb(http_parser *htp) {
|
|||
namespace {
|
||||
int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
||||
auto downstream = static_cast<Downstream *>(htp->data);
|
||||
|
||||
if (downstream->get_response_headers_sum() + len >
|
||||
get_config()->header_field_buffer) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DLOG(INFO, downstream) << "Too large header block size="
|
||||
<< downstream->get_response_headers_sum() + len;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (downstream->get_response_state() == Downstream::INITIAL) {
|
||||
if (downstream->get_response_header_key_prev()) {
|
||||
downstream->append_last_response_header_key(data, len);
|
||||
} else {
|
||||
if (downstream->get_response_headers().size() >=
|
||||
get_config()->max_header_fields) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DLOG(INFO, downstream)
|
||||
<< "Too many header field num="
|
||||
<< downstream->get_response_headers().size() + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
downstream->add_response_header(std::string(data, len), "");
|
||||
}
|
||||
} else {
|
||||
|
@ -593,16 +612,18 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
|||
if (downstream->get_response_trailer_key_prev()) {
|
||||
downstream->append_last_response_trailer_key(data, len);
|
||||
} else {
|
||||
downstream->add_response_trailer(std::string(data, len), "");
|
||||
}
|
||||
}
|
||||
if (downstream->get_response_headers_sum() > Downstream::MAX_HEADERS_SUM) {
|
||||
if (downstream->get_response_headers().size() >=
|
||||
get_config()->max_header_fields) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DLOG(INFO, downstream) << "Too large header block size="
|
||||
<< downstream->get_response_headers_sum();
|
||||
DLOG(INFO, downstream)
|
||||
<< "Too many header field num="
|
||||
<< downstream->get_response_headers().size() + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
downstream->add_response_trailer(std::string(data, len), "");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
@ -610,6 +631,14 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
|||
namespace {
|
||||
int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
|
||||
auto downstream = static_cast<Downstream *>(htp->data);
|
||||
if (downstream->get_response_headers_sum() + len >
|
||||
get_config()->header_field_buffer) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DLOG(INFO, downstream) << "Too large header block size="
|
||||
<< downstream->get_response_headers_sum() + len;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (downstream->get_response_state() == Downstream::INITIAL) {
|
||||
if (downstream->get_response_header_key_prev()) {
|
||||
downstream->set_last_response_header_value(data, len);
|
||||
|
@ -623,13 +652,6 @@ int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
|
|||
downstream->append_last_response_trailer_value(data, len);
|
||||
}
|
||||
}
|
||||
if (downstream->get_response_headers_sum() > Downstream::MAX_HEADERS_SUM) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
DLOG(INFO, downstream) << "Too large header block size="
|
||||
<< downstream->get_response_headers_sum();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -87,10 +87,26 @@ namespace {
|
|||
int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
||||
auto upstream = static_cast<HttpsUpstream *>(htp->data);
|
||||
auto downstream = upstream->get_downstream();
|
||||
if (downstream->get_request_headers_sum() + len >
|
||||
get_config()->header_field_buffer) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
ULOG(INFO, upstream) << "Too large header block size="
|
||||
<< downstream->get_request_headers_sum() + len;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (downstream->get_request_state() == Downstream::INITIAL) {
|
||||
if (downstream->get_request_header_key_prev()) {
|
||||
downstream->append_last_request_header_key(data, len);
|
||||
} else {
|
||||
if (downstream->get_request_headers().size() >=
|
||||
get_config()->max_header_fields) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
ULOG(INFO, upstream) << "Too many header field num="
|
||||
<< downstream->get_request_headers().size() + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
downstream->add_request_header(std::string(data, len), "");
|
||||
}
|
||||
} else {
|
||||
|
@ -98,16 +114,17 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
|||
if (downstream->get_request_trailer_key_prev()) {
|
||||
downstream->append_last_request_trailer_key(data, len);
|
||||
} else {
|
||||
downstream->add_request_trailer(std::string(data, len), "");
|
||||
}
|
||||
}
|
||||
if (downstream->get_request_headers_sum() > Downstream::MAX_HEADERS_SUM) {
|
||||
if (downstream->get_request_headers().size() >=
|
||||
get_config()->max_header_fields) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
ULOG(INFO, upstream) << "Too large header block size="
|
||||
<< downstream->get_request_headers_sum();
|
||||
ULOG(INFO, upstream) << "Too many header field num="
|
||||
<< downstream->get_request_headers().size() + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
downstream->add_request_trailer(std::string(data, len), "");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
@ -116,6 +133,14 @@ namespace {
|
|||
int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
|
||||
auto upstream = static_cast<HttpsUpstream *>(htp->data);
|
||||
auto downstream = upstream->get_downstream();
|
||||
if (downstream->get_request_headers_sum() + len >
|
||||
get_config()->header_field_buffer) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
ULOG(INFO, upstream) << "Too large header block size="
|
||||
<< downstream->get_request_headers_sum() + len;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
if (downstream->get_request_state() == Downstream::INITIAL) {
|
||||
if (downstream->get_request_header_key_prev()) {
|
||||
downstream->set_last_request_header_value(data, len);
|
||||
|
@ -129,13 +154,6 @@ int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
|
|||
downstream->append_last_request_trailer_value(data, len);
|
||||
}
|
||||
}
|
||||
if (downstream->get_request_headers_sum() > Downstream::MAX_HEADERS_SUM) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
ULOG(INFO, upstream) << "Too large header block size="
|
||||
<< downstream->get_request_headers_sum();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
|
Loading…
Reference in New Issue