mirror of
https://github.com/nginx/nginx.git
synced 2026-09-03 20:53:04 -05:00
Added client_body_early_read directive
The directive accepts predicates. When enabled, request body is read
immediately after the headers and before choosing a location.
Body read settings from the server block are used in this case.
Example:
http {
map $http_content_type $is_json {
application/json 1;
}
server {
listen 8000;
client_body_early_read $is_json;
client_max_body_size 256;
client_body_buffer_size 256;
return 200 $request_body;
}
}
This commit is contained in:
committed by
Roman Arutyunyan
parent
bc7c3424c3
commit
3f6f7824d4
@@ -394,6 +394,13 @@ static ngx_command_t ngx_http_core_commands[] = {
|
||||
offsetof(ngx_http_core_loc_conf_t, client_body_in_single_buffer),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("client_body_early_read"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
|
||||
ngx_http_set_predicate_slot,
|
||||
NGX_HTTP_SRV_CONF_OFFSET,
|
||||
offsetof(ngx_http_core_srv_conf_t, client_body_early_read),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("sendfile"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|
||||
|NGX_CONF_FLAG,
|
||||
@@ -3550,6 +3557,7 @@ ngx_http_core_create_srv_conf(ngx_conf_t *cf)
|
||||
cscf->ignore_invalid_headers = NGX_CONF_UNSET;
|
||||
cscf->merge_slashes = NGX_CONF_UNSET;
|
||||
cscf->underscores_in_headers = NGX_CONF_UNSET;
|
||||
cscf->client_body_early_read = NGX_CONF_UNSET_PTR;
|
||||
|
||||
cscf->file_name = cf->conf_file->file.name.data;
|
||||
cscf->line = cf->conf_file->line;
|
||||
@@ -3598,6 +3606,9 @@ ngx_http_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
ngx_conf_merge_value(conf->underscores_in_headers,
|
||||
prev->underscores_in_headers, 0);
|
||||
|
||||
ngx_conf_merge_ptr_value(conf->client_body_early_read,
|
||||
prev->client_body_early_read, NULL);
|
||||
|
||||
if (conf->server_names.nelts == 0) {
|
||||
/* the array has 4 empty preallocated elements, so push cannot fail */
|
||||
sn = ngx_array_push(&conf->server_names);
|
||||
|
||||
@@ -205,6 +205,8 @@ typedef struct {
|
||||
ngx_flag_t merge_slashes;
|
||||
ngx_flag_t underscores_in_headers;
|
||||
|
||||
ngx_array_t *client_body_early_read;
|
||||
|
||||
unsigned listen:1;
|
||||
#if (NGX_PCRE)
|
||||
unsigned captures:1;
|
||||
|
||||
@@ -32,6 +32,7 @@ static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r,
|
||||
ngx_table_elt_t *h, ngx_uint_t offset);
|
||||
|
||||
static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r);
|
||||
static ngx_int_t ngx_http_read_early_body(ngx_http_request_t *r);
|
||||
static ngx_int_t ngx_http_find_virtual_server(ngx_connection_t *c,
|
||||
ngx_http_virtual_names_t *virtual_names, ngx_str_t *host,
|
||||
ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp);
|
||||
@@ -2209,10 +2210,69 @@ ngx_http_process_request(ngx_http_request_t *r)
|
||||
c->write->handler = ngx_http_request_handler;
|
||||
r->read_event_handler = ngx_http_block_reading;
|
||||
|
||||
if (ngx_http_read_early_body(r) != NGX_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_http_handler(r);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_read_early_body(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
ngx_http_core_srv_conf_t *cscf;
|
||||
|
||||
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
|
||||
|
||||
rc = ngx_http_test_predicates(r, cscf->client_body_early_read);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/* rc == NGX_DECLINED */
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"http client request body early read");
|
||||
|
||||
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
|
||||
|
||||
if (r->headers_in.content_length_n != -1
|
||||
&& !r->discard_body
|
||||
&& clcf->client_max_body_size
|
||||
&& clcf->client_max_body_size < r->headers_in.content_length_n)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"client intended to send too large body: %O bytes",
|
||||
r->headers_in.content_length_n);
|
||||
|
||||
r->expect_tested = 1;
|
||||
(void) ngx_http_discard_request_body(r);
|
||||
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
rc = ngx_http_read_client_request_body(r, ngx_http_handler);
|
||||
|
||||
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
ngx_http_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_validate_host(ngx_str_t *host, in_port_t *portp, ngx_pool_t *pool,
|
||||
ngx_uint_t alloc)
|
||||
|
||||
Reference in New Issue
Block a user