Merge of r4921, r4922, r4923, r4924, r4925: request body fixes.

*) Request body: fixed "501 Not Implemented" error handling.

   It is not about "Method" but a generic message, and is expected to be used
   e.g. if specified Transfer-Encoding is not supported.  Fixed message to
   match RFC 2616.

   Additionally, disable keepalive on such errors as we won't be able to read
   request body correctly if we don't understand Transfer-Encoding used.

*) Request body: $request_body variable generalization.

   The $request_body variable was assuming there can't be more than two
   buffers.  While this is currently true due to request body reading
   implementation details, this is not a good thing to depend on and may
   change in the future.

*) Request body: code duplication reduced, no functional changes.

   The r->request_body_in_file_only with empty body case is now handled in
   ngx_http_write_request_body().

*) Request body: fixed socket leak on errors.

   The r->main->count reference counter was always incremented in
   ngx_http_read_client_request_body(), while it is only needs to be
   incremented on positive returns.

*) Request body: properly handle events while discarding body.

   An attempt to call ngx_handle_read_event() before actually reading
   data from a socket might result in read event being disabled, which is
   wrong.  Catched by body.t test on Solaris.
This commit is contained in:
Maxim Dounin 2012-12-11 13:18:50 +00:00
parent 3428ae9ab1
commit 089dd2f9ba
4 changed files with 68 additions and 50 deletions

View File

@ -112,7 +112,7 @@ static ngx_str_t ngx_http_status_lines[] = {
#define NGX_HTTP_OFF_5XX (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)
ngx_string("500 Internal Server Error"),
ngx_string("501 Method Not Implemented"),
ngx_string("501 Not Implemented"),
ngx_string("502 Bad Gateway"),
ngx_string("503 Service Temporarily Unavailable"),
ngx_string("504 Gateway Time-out"),

View File

@ -31,9 +31,9 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
{
size_t preread;
ssize_t size;
ngx_int_t rc;
ngx_buf_t *b;
ngx_chain_t *cl, **next;
ngx_temp_file_t *tf;
ngx_http_request_body_t *rb;
ngx_http_core_loc_conf_t *clcf;
@ -45,12 +45,14 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
}
if (ngx_http_test_expect(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
goto done;
}
rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
if (rb == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
goto done;
}
r->request_body = rb;
@ -65,31 +67,9 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
if (r->headers_in.content_length_n == 0) {
if (r->request_body_in_file_only) {
tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
if (tf == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
tf->file.fd = NGX_INVALID_FILE;
tf->file.log = r->connection->log;
tf->path = clcf->client_body_temp_path;
tf->pool = r->pool;
tf->warn = "a client request body is buffered to a temporary file";
tf->log_level = r->request_body_file_log_level;
tf->persistent = r->request_body_in_persistent_file;
tf->clean = r->request_body_in_clean_file;
if (r->request_body_file_group_access) {
tf->access = 0660;
}
rb->temp_file = tf;
if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
tf->persistent, tf->clean, tf->access)
!= NGX_OK)
{
return NGX_HTTP_INTERNAL_SERVER_ERROR;
if (ngx_http_write_request_body(r, NULL) != NGX_OK) {
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
goto done;
}
}
@ -119,7 +99,8 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
goto done;
}
b->temporary = 1;
@ -130,7 +111,8 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
rb->bufs = ngx_alloc_chain_link(r->pool);
if (rb->bufs == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
goto done;
}
rb->bufs->buf = b;
@ -148,7 +130,8 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
if (r->request_body_in_file_only) {
if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
goto done;
}
}
@ -175,7 +158,8 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
r->read_event_handler = ngx_http_read_client_request_body_handler;
return ngx_http_do_read_client_request_body(r);
rc = ngx_http_do_read_client_request_body(r);
goto done;
}
next = &rb->bufs->next;
@ -205,12 +189,14 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
rb->buf = ngx_create_temp_buf(r->pool, size);
if (rb->buf == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
goto done;
}
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
goto done;
}
cl->buf = rb->buf;
@ -235,7 +221,15 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
r->read_event_handler = ngx_http_read_client_request_body_handler;
return ngx_http_do_read_client_request_body(r);
rc = ngx_http_do_read_client_request_body(r);
done:
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
r->main->count--;
}
return rc;
}
@ -419,6 +413,19 @@ ngx_http_write_request_body(ngx_http_request_t *r, ngx_chain_t *body)
}
rb->temp_file = tf;
if (body == NULL) {
/* empty body with r->request_body_in_file_only */
if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
tf->persistent, tf->clean, tf->access)
!= NGX_OK)
{
return NGX_ERROR;
}
return NGX_OK;
}
}
n = ngx_write_chain_to_temp_file(rb->temp_file, body);
@ -475,19 +482,21 @@ ngx_http_discard_request_body(ngx_http_request_t *r)
}
}
if (ngx_http_read_discarded_request_body(r) == NGX_OK) {
r->lingering_close = 0;
return NGX_OK;
}
/* == NGX_AGAIN */
r->read_event_handler = ngx_http_discarded_request_body_handler;
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (ngx_http_read_discarded_request_body(r) == NGX_OK) {
r->lingering_close = 0;
} else {
r->count++;
r->discard_body = 1;
}
r->count++;
r->discard_body = 1;
return NGX_OK;
}

View File

@ -260,9 +260,9 @@ static char ngx_http_error_500_page[] =
static char ngx_http_error_501_page[] =
"<html>" CRLF
"<head><title>501 Method Not Implemented</title></head>" CRLF
"<head><title>501 Not Implemented</title></head>" CRLF
"<body bgcolor=\"white\">" CRLF
"<center><h1>501 Method Not Implemented</h1></center>" CRLF
"<center><h1>501 Not Implemented</h1></center>" CRLF
;
@ -384,6 +384,7 @@ ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error)
case NGX_HTTPS_CERT_ERROR:
case NGX_HTTPS_NO_CERT:
case NGX_HTTP_INTERNAL_SERVER_ERROR:
case NGX_HTTP_NOT_IMPLEMENTED:
r->keepalive = 0;
}
}

View File

@ -1767,7 +1767,7 @@ ngx_http_variable_request_body(ngx_http_request_t *r,
{
u_char *p;
size_t len;
ngx_buf_t *buf, *next;
ngx_buf_t *buf;
ngx_chain_t *cl;
if (r->request_body == NULL
@ -1792,8 +1792,13 @@ ngx_http_variable_request_body(ngx_http_request_t *r,
return NGX_OK;
}
next = cl->next->buf;
len = (buf->last - buf->pos) + (next->last - next->pos);
len = buf->last - buf->pos;
cl = cl->next;
for ( /* void */ ; cl; cl = cl->next) {
buf = cl->buf;
len += buf->last - buf->pos;
}
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
@ -1801,9 +1806,12 @@ ngx_http_variable_request_body(ngx_http_request_t *r,
}
v->data = p;
cl = r->request_body->bufs;
p = ngx_cpymem(p, buf->pos, buf->last - buf->pos);
ngx_memcpy(p, next->pos, next->last - next->pos);
for ( /* void */ ; cl; cl = cl->next) {
buf = cl->buf;
p = ngx_cpymem(p, buf->pos, buf->last - buf->pos);
}
v->len = len;
v->valid = 1;