comparison src/http/ngx_http_request_body.c @ 4957:7556a7acb14f stable-1.2

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.
author Maxim Dounin <mdounin@mdounin.ru>
date Tue, 11 Dec 2012 13:18:50 +0000
parents 834049edae24
children
comparison
equal deleted inserted replaced
4956:bbcaeccbd928 4957:7556a7acb14f
29 ngx_http_read_client_request_body(ngx_http_request_t *r, 29 ngx_http_read_client_request_body(ngx_http_request_t *r,
30 ngx_http_client_body_handler_pt post_handler) 30 ngx_http_client_body_handler_pt post_handler)
31 { 31 {
32 size_t preread; 32 size_t preread;
33 ssize_t size; 33 ssize_t size;
34 ngx_int_t rc;
34 ngx_buf_t *b; 35 ngx_buf_t *b;
35 ngx_chain_t *cl, **next; 36 ngx_chain_t *cl, **next;
36 ngx_temp_file_t *tf;
37 ngx_http_request_body_t *rb; 37 ngx_http_request_body_t *rb;
38 ngx_http_core_loc_conf_t *clcf; 38 ngx_http_core_loc_conf_t *clcf;
39 39
40 r->main->count++; 40 r->main->count++;
41 41
43 post_handler(r); 43 post_handler(r);
44 return NGX_OK; 44 return NGX_OK;
45 } 45 }
46 46
47 if (ngx_http_test_expect(r) != NGX_OK) { 47 if (ngx_http_test_expect(r) != NGX_OK) {
48 return NGX_HTTP_INTERNAL_SERVER_ERROR; 48 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
49 goto done;
49 } 50 }
50 51
51 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); 52 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
52 if (rb == NULL) { 53 if (rb == NULL) {
53 return NGX_HTTP_INTERNAL_SERVER_ERROR; 54 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
55 goto done;
54 } 56 }
55 57
56 r->request_body = rb; 58 r->request_body = rb;
57 59
58 if (r->headers_in.content_length_n < 0) { 60 if (r->headers_in.content_length_n < 0) {
63 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 65 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
64 66
65 if (r->headers_in.content_length_n == 0) { 67 if (r->headers_in.content_length_n == 0) {
66 68
67 if (r->request_body_in_file_only) { 69 if (r->request_body_in_file_only) {
68 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); 70 if (ngx_http_write_request_body(r, NULL) != NGX_OK) {
69 if (tf == NULL) { 71 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
70 return NGX_HTTP_INTERNAL_SERVER_ERROR; 72 goto done;
71 }
72
73 tf->file.fd = NGX_INVALID_FILE;
74 tf->file.log = r->connection->log;
75 tf->path = clcf->client_body_temp_path;
76 tf->pool = r->pool;
77 tf->warn = "a client request body is buffered to a temporary file";
78 tf->log_level = r->request_body_file_log_level;
79 tf->persistent = r->request_body_in_persistent_file;
80 tf->clean = r->request_body_in_clean_file;
81
82 if (r->request_body_file_group_access) {
83 tf->access = 0660;
84 }
85
86 rb->temp_file = tf;
87
88 if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
89 tf->persistent, tf->clean, tf->access)
90 != NGX_OK)
91 {
92 return NGX_HTTP_INTERNAL_SERVER_ERROR;
93 } 73 }
94 } 74 }
95 75
96 post_handler(r); 76 post_handler(r);
97 77
117 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 97 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
118 "http client request body preread %uz", preread); 98 "http client request body preread %uz", preread);
119 99
120 b = ngx_calloc_buf(r->pool); 100 b = ngx_calloc_buf(r->pool);
121 if (b == NULL) { 101 if (b == NULL) {
122 return NGX_HTTP_INTERNAL_SERVER_ERROR; 102 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
103 goto done;
123 } 104 }
124 105
125 b->temporary = 1; 106 b->temporary = 1;
126 b->start = r->header_in->pos; 107 b->start = r->header_in->pos;
127 b->pos = r->header_in->pos; 108 b->pos = r->header_in->pos;
128 b->last = r->header_in->last; 109 b->last = r->header_in->last;
129 b->end = r->header_in->end; 110 b->end = r->header_in->end;
130 111
131 rb->bufs = ngx_alloc_chain_link(r->pool); 112 rb->bufs = ngx_alloc_chain_link(r->pool);
132 if (rb->bufs == NULL) { 113 if (rb->bufs == NULL) {
133 return NGX_HTTP_INTERNAL_SERVER_ERROR; 114 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
115 goto done;
134 } 116 }
135 117
136 rb->bufs->buf = b; 118 rb->bufs->buf = b;
137 rb->bufs->next = NULL; 119 rb->bufs->next = NULL;
138 120
146 r->request_length += r->headers_in.content_length_n; 128 r->request_length += r->headers_in.content_length_n;
147 b->last = r->header_in->pos; 129 b->last = r->header_in->pos;
148 130
149 if (r->request_body_in_file_only) { 131 if (r->request_body_in_file_only) {
150 if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) { 132 if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) {
151 return NGX_HTTP_INTERNAL_SERVER_ERROR; 133 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
134 goto done;
152 } 135 }
153 } 136 }
154 137
155 post_handler(r); 138 post_handler(r);
156 139
173 156
174 rb->to_write = rb->bufs; 157 rb->to_write = rb->bufs;
175 158
176 r->read_event_handler = ngx_http_read_client_request_body_handler; 159 r->read_event_handler = ngx_http_read_client_request_body_handler;
177 160
178 return ngx_http_do_read_client_request_body(r); 161 rc = ngx_http_do_read_client_request_body(r);
162 goto done;
179 } 163 }
180 164
181 next = &rb->bufs->next; 165 next = &rb->bufs->next;
182 166
183 } else { 167 } else {
203 b = NULL; 187 b = NULL;
204 } 188 }
205 189
206 rb->buf = ngx_create_temp_buf(r->pool, size); 190 rb->buf = ngx_create_temp_buf(r->pool, size);
207 if (rb->buf == NULL) { 191 if (rb->buf == NULL) {
208 return NGX_HTTP_INTERNAL_SERVER_ERROR; 192 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
193 goto done;
209 } 194 }
210 195
211 cl = ngx_alloc_chain_link(r->pool); 196 cl = ngx_alloc_chain_link(r->pool);
212 if (cl == NULL) { 197 if (cl == NULL) {
213 return NGX_HTTP_INTERNAL_SERVER_ERROR; 198 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
199 goto done;
214 } 200 }
215 201
216 cl->buf = rb->buf; 202 cl->buf = rb->buf;
217 cl->next = NULL; 203 cl->next = NULL;
218 204
233 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs; 219 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
234 } 220 }
235 221
236 r->read_event_handler = ngx_http_read_client_request_body_handler; 222 r->read_event_handler = ngx_http_read_client_request_body_handler;
237 223
238 return ngx_http_do_read_client_request_body(r); 224 rc = ngx_http_do_read_client_request_body(r);
225
226 done:
227
228 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
229 r->main->count--;
230 }
231
232 return rc;
239 } 233 }
240 234
241 235
242 static void 236 static void
243 ngx_http_read_client_request_body_handler(ngx_http_request_t *r) 237 ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
417 if (r->request_body_file_group_access) { 411 if (r->request_body_file_group_access) {
418 tf->access = 0660; 412 tf->access = 0660;
419 } 413 }
420 414
421 rb->temp_file = tf; 415 rb->temp_file = tf;
416
417 if (body == NULL) {
418 /* empty body with r->request_body_in_file_only */
419
420 if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
421 tf->persistent, tf->clean, tf->access)
422 != NGX_OK)
423 {
424 return NGX_ERROR;
425 }
426
427 return NGX_OK;
428 }
422 } 429 }
423 430
424 n = ngx_write_chain_to_temp_file(rb->temp_file, body); 431 n = ngx_write_chain_to_temp_file(rb->temp_file, body);
425 432
426 /* TODO: n == 0 or not complete and level event */ 433 /* TODO: n == 0 or not complete and level event */
473 r->headers_in.content_length_n = 0; 480 r->headers_in.content_length_n = 0;
474 return NGX_OK; 481 return NGX_OK;
475 } 482 }
476 } 483 }
477 484
485 if (ngx_http_read_discarded_request_body(r) == NGX_OK) {
486 r->lingering_close = 0;
487 return NGX_OK;
488 }
489
490 /* == NGX_AGAIN */
491
478 r->read_event_handler = ngx_http_discarded_request_body_handler; 492 r->read_event_handler = ngx_http_discarded_request_body_handler;
479 493
480 if (ngx_handle_read_event(rev, 0) != NGX_OK) { 494 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
481 return NGX_HTTP_INTERNAL_SERVER_ERROR; 495 return NGX_HTTP_INTERNAL_SERVER_ERROR;
482 } 496 }
483 497
484 if (ngx_http_read_discarded_request_body(r) == NGX_OK) { 498 r->count++;
485 r->lingering_close = 0; 499 r->discard_body = 1;
486
487 } else {
488 r->count++;
489 r->discard_body = 1;
490 }
491 500
492 return NGX_OK; 501 return NGX_OK;
493 } 502 }
494 503
495 504