Commit 8288f571 authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

nghttpx: Add --api-max-request-body option to set maximum API request body size

parent 951ef0c6
...@@ -132,6 +132,7 @@ OPTIONS = [ ...@@ -132,6 +132,7 @@ OPTIONS = [
"no-kqueue", "no-kqueue",
"frontend-http2-settings-timeout", "frontend-http2-settings-timeout",
"backend-http2-settings-timeout", "backend-http2-settings-timeout",
"api-max-request-body",
] ]
LOGVARS = [ LOGVARS = [
......
...@@ -1183,6 +1183,9 @@ void fill_default_config() { ...@@ -1183,6 +1183,9 @@ void fill_default_config() {
downstreamconf.response_buffer_size = 128_k; downstreamconf.response_buffer_size = 128_k;
downstreamconf.family = AF_UNSPEC; downstreamconf.family = AF_UNSPEC;
} }
auto &apiconf = mod_config()->api;
apiconf.max_request_body = 16_k;
} }
} // namespace } // namespace
...@@ -1914,6 +1917,12 @@ HTTP: ...@@ -1914,6 +1917,12 @@ HTTP:
HTTP status code. If error status code comes from HTTP status code. If error status code comes from
backend server, the custom error pages are not used. backend server, the custom error pages are not used.
API:
--api-max-request-body=<SIZE>
Set the maximum size of request body for API request.
Default: )" << util::utos_unit(get_config()->api.max_request_body)
<< R"(
Debug: Debug:
--frontend-http2-dump-request-header=<PATH> --frontend-http2-dump-request-header=<PATH>
Dumps request headers received by HTTP/2 frontend to the Dumps request headers received by HTTP/2 frontend to the
...@@ -2447,6 +2456,7 @@ int main(int argc, char **argv) { ...@@ -2447,6 +2456,7 @@ int main(int argc, char **argv) {
&flag, 124}, &flag, 124},
{SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT.c_str(), required_argument, {SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT.c_str(), required_argument,
&flag, 125}, &flag, 125},
{SHRPX_OPT_API_MAX_REQUEST_BODY.c_str(), required_argument, &flag, 126},
{nullptr, 0, nullptr, 0}}; {nullptr, 0, nullptr, 0}};
int option_index = 0; int option_index = 0;
...@@ -3036,6 +3046,10 @@ int main(int argc, char **argv) { ...@@ -3036,6 +3046,10 @@ int main(int argc, char **argv) {
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT, cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT,
StringRef{optarg}); StringRef{optarg});
break; break;
case 126:
// --api-max-request-body
cmdcfgs.emplace_back(SHRPX_OPT_API_MAX_REQUEST_BODY, StringRef{optarg});
break;
default: default:
break; break;
} }
......
...@@ -87,6 +87,15 @@ int APIDownstreamConnection::push_request_headers() { ...@@ -87,6 +87,15 @@ int APIDownstreamConnection::push_request_headers() {
return 0; return 0;
} }
// This works with req.fs.content_length == -1
if (req.fs.content_length >
static_cast<int64_t>(get_config()->api.max_request_body)) {
send_reply(
413, http2::get_status_string(downstream_->get_block_allocator(), 413));
return 0;
}
return 0; return 0;
} }
...@@ -98,7 +107,15 @@ int APIDownstreamConnection::push_upload_data_chunk(const uint8_t *data, ...@@ -98,7 +107,15 @@ int APIDownstreamConnection::push_upload_data_chunk(const uint8_t *data,
auto output = downstream_->get_request_buf(); auto output = downstream_->get_request_buf();
// TODO limit the maximum payload size auto &apiconf = get_config()->api;
if (output->rleft() + datalen > apiconf.max_request_body) {
send_reply(
413, http2::get_status_string(downstream_->get_block_allocator(), 413));
return 0;
}
output->append(data, datalen); output->append(data, datalen);
// We don't have to call Upstream::resume_read() here, because // We don't have to call Upstream::resume_read() here, because
...@@ -116,7 +133,7 @@ int APIDownstreamConnection::end_upload_data() { ...@@ -116,7 +133,7 @@ int APIDownstreamConnection::end_upload_data() {
auto output = downstream_->get_request_buf(); auto output = downstream_->get_request_buf();
struct iovec iov; struct iovec iov;
auto iovcnt = output->riovec(&iov, 1); auto iovcnt = output->riovec(&iov, 2);
constexpr auto body = StringRef::from_lit("200 OK"); constexpr auto body = StringRef::from_lit("200 OK");
constexpr auto error_body = StringRef::from_lit("400 Bad Request"); constexpr auto error_body = StringRef::from_lit("400 Bad Request");
...@@ -127,6 +144,19 @@ int APIDownstreamConnection::end_upload_data() { ...@@ -127,6 +144,19 @@ int APIDownstreamConnection::end_upload_data() {
return 0; return 0;
} }
std::unique_ptr<uint8_t[]> large_buf;
// If data spans in multiple chunks, pull them up into one
// contiguous buffer.
if (iovcnt > 1) {
large_buf = make_unique<uint8_t[]>(output->rleft());
auto len = output->rleft();
output->remove(large_buf.get(), len);
iov.iov_base = large_buf.get();
iov.iov_len = len;
}
Config config{}; Config config{};
config.conn.downstream = std::make_shared<DownstreamConfig>(); config.conn.downstream = std::make_shared<DownstreamConfig>();
const auto &downstreamconf = config.conn.downstream; const auto &downstreamconf = config.conn.downstream;
......
...@@ -915,6 +915,7 @@ enum { ...@@ -915,6 +915,7 @@ enum {
SHRPX_OPTID_ADD_RESPONSE_HEADER, SHRPX_OPTID_ADD_RESPONSE_HEADER,
SHRPX_OPTID_ADD_X_FORWARDED_FOR, SHRPX_OPTID_ADD_X_FORWARDED_FOR,
SHRPX_OPTID_ALTSVC, SHRPX_OPTID_ALTSVC,
SHRPX_OPTID_API_MAX_REQUEST_BODY,
SHRPX_OPTID_BACKEND, SHRPX_OPTID_BACKEND,
SHRPX_OPTID_BACKEND_ADDRESS_FAMILY, SHRPX_OPTID_BACKEND_ADDRESS_FAMILY,
SHRPX_OPTID_BACKEND_CONNECTIONS_PER_FRONTEND, SHRPX_OPTID_BACKEND_CONNECTIONS_PER_FRONTEND,
...@@ -1429,6 +1430,11 @@ int option_lookup_token(const char *name, size_t namelen) { ...@@ -1429,6 +1430,11 @@ int option_lookup_token(const char *name, size_t namelen) {
return SHRPX_OPTID_VERIFY_CLIENT_CACERT; return SHRPX_OPTID_VERIFY_CLIENT_CACERT;
} }
break; break;
case 'y':
if (util::strieq_l("api-max-request-bod", name, 19)) {
return SHRPX_OPTID_API_MAX_REQUEST_BODY;
}
break;
} }
break; break;
case 21: case 21:
...@@ -2712,6 +2718,8 @@ int parse_config(Config *config, const StringRef &opt, const StringRef &optarg, ...@@ -2712,6 +2718,8 @@ int parse_config(Config *config, const StringRef &opt, const StringRef &optarg,
case SHRPX_OPTID_BACKEND_HTTP2_SETTINGS_TIMEOUT: case SHRPX_OPTID_BACKEND_HTTP2_SETTINGS_TIMEOUT:
return parse_duration(&config->http2.downstream.timeout.settings, opt, return parse_duration(&config->http2.downstream.timeout.settings, opt,
optarg); optarg);
case SHRPX_OPTID_API_MAX_REQUEST_BODY:
return parse_uint_with_unit(&config->api.max_request_body, opt, optarg);
case SHRPX_OPTID_CONF: case SHRPX_OPTID_CONF:
LOG(WARN) << "conf: ignored"; LOG(WARN) << "conf: ignored";
......
...@@ -280,6 +280,8 @@ constexpr auto SHRPX_OPT_FRONTEND_HTTP2_SETTINGS_TIMEOUT = ...@@ -280,6 +280,8 @@ constexpr auto SHRPX_OPT_FRONTEND_HTTP2_SETTINGS_TIMEOUT =
StringRef::from_lit("frontend-http2-settings-timeout"); StringRef::from_lit("frontend-http2-settings-timeout");
constexpr auto SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT = constexpr auto SHRPX_OPT_BACKEND_HTTP2_SETTINGS_TIMEOUT =
StringRef::from_lit("backend-http2-settings-timeout"); StringRef::from_lit("backend-http2-settings-timeout");
constexpr auto SHRPX_OPT_API_MAX_REQUEST_BODY =
StringRef::from_lit("api-max-request-body");
constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8;
...@@ -649,6 +651,11 @@ struct ConnectionConfig { ...@@ -649,6 +651,11 @@ struct ConnectionConfig {
std::shared_ptr<DownstreamConfig> downstream; std::shared_ptr<DownstreamConfig> downstream;
}; };
struct APIConfig {
// Maximum request body size for one API request
size_t max_request_body;
};
struct Config { struct Config {
HttpProxy downstream_http_proxy; HttpProxy downstream_http_proxy;
HttpConfig http; HttpConfig http;
...@@ -656,6 +663,7 @@ struct Config { ...@@ -656,6 +663,7 @@ struct Config {
TLSConfig tls; TLSConfig tls;
LoggingConfig logging; LoggingConfig logging;
ConnectionConfig conn; ConnectionConfig conn;
APIConfig api;
ImmutableString pid_file; ImmutableString pid_file;
ImmutableString conf_path; ImmutableString conf_path;
ImmutableString user; ImmutableString user;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment