comparison src/http/ngx_http_request_body.c @ 692:6db6e93f55ee NGINX_1_3_9

nginx 1.3.9 *) Feature: support for chunked transfer encoding while reading client request body. *) Feature: the $request_time and $msec variables can now be used not only in the "log_format" directive. *) Bugfix: cache manager and cache loader processes might not be able to start if more than 512 listen sockets were used. *) Bugfix: in the ngx_http_dav_module.
author Igor Sysoev <http://sysoev.ru>
date Tue, 27 Nov 2012 00:00:00 +0400
parents f41d4b305d22
children
comparison
equal deleted inserted replaced
691:acfd484db0ca 692:6db6e93f55ee
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11 11
12 12
13 static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r); 13 static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
14 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); 14 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
15 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r, 15 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r);
16 ngx_chain_t *body);
17 static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r); 16 static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
17 static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r,
18 ngx_buf_t *b);
18 static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r); 19 static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);
19 20
20 21 static ngx_int_t ngx_http_request_body_filter(ngx_http_request_t *r,
21 /* 22 ngx_chain_t *in);
22 * on completion ngx_http_read_client_request_body() adds to 23 static ngx_int_t ngx_http_request_body_length_filter(ngx_http_request_t *r,
23 * r->request_body->bufs one or two bufs: 24 ngx_chain_t *in);
24 * *) one memory buf that was preread in r->header_in; 25 static ngx_int_t ngx_http_request_body_chunked_filter(ngx_http_request_t *r,
25 * *) one memory or file buf that contains the rest of the body 26 ngx_chain_t *in);
26 */ 27 static ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r,
28 ngx_chain_t *in);
29
27 30
28 ngx_int_t 31 ngx_int_t
29 ngx_http_read_client_request_body(ngx_http_request_t *r, 32 ngx_http_read_client_request_body(ngx_http_request_t *r,
30 ngx_http_client_body_handler_pt post_handler) 33 ngx_http_client_body_handler_pt post_handler)
31 { 34 {
32 size_t preread; 35 size_t preread;
33 ssize_t size; 36 ssize_t size;
34 ngx_buf_t *b; 37 ngx_int_t rc;
35 ngx_chain_t *cl, **next; 38 ngx_chain_t out;
36 ngx_temp_file_t *tf;
37 ngx_http_request_body_t *rb; 39 ngx_http_request_body_t *rb;
38 ngx_http_core_loc_conf_t *clcf; 40 ngx_http_core_loc_conf_t *clcf;
39 41
40 r->main->count++; 42 r->main->count++;
41 43
43 post_handler(r); 45 post_handler(r);
44 return NGX_OK; 46 return NGX_OK;
45 } 47 }
46 48
47 if (ngx_http_test_expect(r) != NGX_OK) { 49 if (ngx_http_test_expect(r) != NGX_OK) {
48 return NGX_HTTP_INTERNAL_SERVER_ERROR; 50 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
51 goto done;
49 } 52 }
50 53
51 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); 54 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
52 if (rb == NULL) { 55 if (rb == NULL) {
53 return NGX_HTTP_INTERNAL_SERVER_ERROR; 56 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
54 } 57 goto done;
55 58 }
56 r->request_body = rb;
57
58 if (r->headers_in.content_length_n < 0) {
59 post_handler(r);
60 return NGX_OK;
61 }
62
63 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
64
65 if (r->headers_in.content_length_n == 0) {
66
67 if (r->request_body_in_file_only) {
68 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
69 if (tf == NULL) {
70 return NGX_HTTP_INTERNAL_SERVER_ERROR;
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 }
94 }
95
96 post_handler(r);
97
98 return NGX_OK;
99 }
100
101 rb->post_handler = post_handler;
102 59
103 /* 60 /*
104 * set by ngx_pcalloc(): 61 * set by ngx_pcalloc():
105 * 62 *
106 * rb->bufs = NULL; 63 * rb->bufs = NULL;
107 * rb->buf = NULL; 64 * rb->buf = NULL;
108 * rb->rest = 0; 65 * rb->free = NULL;
66 * rb->busy = NULL;
67 * rb->chunked = NULL;
109 */ 68 */
69
70 rb->rest = -1;
71 rb->post_handler = post_handler;
72
73 r->request_body = rb;
74
75 if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
76 post_handler(r);
77 return NGX_OK;
78 }
110 79
111 preread = r->header_in->last - r->header_in->pos; 80 preread = r->header_in->last - r->header_in->pos;
112 81
113 if (preread) { 82 if (preread) {
114 83
115 /* there is the pre-read part of the request body */ 84 /* there is the pre-read part of the request body */
116 85
117 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 86 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
118 "http client request body preread %uz", preread); 87 "http client request body preread %uz", preread);
119 88
120 b = ngx_calloc_buf(r->pool); 89 out.buf = r->header_in;
121 if (b == NULL) { 90 out.next = NULL;
122 return NGX_HTTP_INTERNAL_SERVER_ERROR; 91
123 } 92 rc = ngx_http_request_body_filter(r, &out);
124 93
125 b->temporary = 1; 94 if (rc != NGX_OK) {
126 b->start = r->header_in->pos; 95 goto done;
127 b->pos = r->header_in->pos; 96 }
128 b->last = r->header_in->last; 97
129 b->end = r->header_in->end; 98 r->request_length += preread - (r->header_in->last - r->header_in->pos);
130 99
131 rb->bufs = ngx_alloc_chain_link(r->pool); 100 if (!r->headers_in.chunked
132 if (rb->bufs == NULL) { 101 && rb->rest > 0
133 return NGX_HTTP_INTERNAL_SERVER_ERROR; 102 && rb->rest <= (off_t) (r->header_in->end - r->header_in->last))
134 } 103 {
135
136 rb->bufs->buf = b;
137 rb->bufs->next = NULL;
138
139 rb->buf = b;
140
141 if ((off_t) preread >= r->headers_in.content_length_n) {
142
143 /* the whole request body was pre-read */
144
145 r->header_in->pos += (size_t) r->headers_in.content_length_n;
146 r->request_length += r->headers_in.content_length_n;
147 b->last = r->header_in->pos;
148
149 if (r->request_body_in_file_only) {
150 if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) {
151 return NGX_HTTP_INTERNAL_SERVER_ERROR;
152 }
153 }
154
155 post_handler(r);
156
157 return NGX_OK;
158 }
159
160 /*
161 * to not consider the body as pipelined request in
162 * ngx_http_set_keepalive()
163 */
164 r->header_in->pos = r->header_in->last;
165
166 r->request_length += preread;
167
168 rb->rest = r->headers_in.content_length_n - preread;
169
170 if (rb->rest <= (off_t) (b->end - b->last)) {
171
172 /* the whole request body may be placed in r->header_in */ 104 /* the whole request body may be placed in r->header_in */
173 105
174 rb->to_write = rb->bufs; 106 rb->buf = r->header_in;
175
176 r->read_event_handler = ngx_http_read_client_request_body_handler; 107 r->read_event_handler = ngx_http_read_client_request_body_handler;
177 108 r->write_event_handler = ngx_http_request_empty_handler;
178 return ngx_http_do_read_client_request_body(r); 109
179 } 110 rc = ngx_http_do_read_client_request_body(r);
180 111 goto done;
181 next = &rb->bufs->next; 112 }
182 113
183 } else { 114 } else {
184 b = NULL; 115 /* set rb->rest */
185 rb->rest = r->headers_in.content_length_n; 116
186 next = &rb->bufs; 117 if (ngx_http_request_body_filter(r, NULL) != NGX_OK) {
187 } 118 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
119 goto done;
120 }
121 }
122
123 if (rb->rest == 0) {
124 /* the whole request body was pre-read */
125
126 if (r->request_body_in_file_only) {
127 if (ngx_http_write_request_body(r) != NGX_OK) {
128 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
129 goto done;
130 }
131 }
132
133 post_handler(r);
134
135 return NGX_OK;
136 }
137
138 if (rb->rest < 0) {
139 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
140 "negative request body rest");
141 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
142 goto done;
143 }
144
145 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
188 146
189 size = clcf->client_body_buffer_size; 147 size = clcf->client_body_buffer_size;
190 size += size >> 2; 148 size += size >> 2;
191 149
192 if (rb->rest < size) { 150 /* TODO: honor r->request_body_in_single_buf */
151
152 if (!r->headers_in.chunked && rb->rest < size) {
193 size = (ssize_t) rb->rest; 153 size = (ssize_t) rb->rest;
194 154
195 if (r->request_body_in_single_buf) { 155 if (r->request_body_in_single_buf) {
196 size += preread; 156 size += preread;
197 } 157 }
198 158
199 } else { 159 } else {
200 size = clcf->client_body_buffer_size; 160 size = clcf->client_body_buffer_size;
201
202 /* disable copying buffer for r->request_body_in_single_buf */
203 b = NULL;
204 } 161 }
205 162
206 rb->buf = ngx_create_temp_buf(r->pool, size); 163 rb->buf = ngx_create_temp_buf(r->pool, size);
207 if (rb->buf == NULL) { 164 if (rb->buf == NULL) {
208 return NGX_HTTP_INTERNAL_SERVER_ERROR; 165 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
209 } 166 goto done;
210
211 cl = ngx_alloc_chain_link(r->pool);
212 if (cl == NULL) {
213 return NGX_HTTP_INTERNAL_SERVER_ERROR;
214 }
215
216 cl->buf = rb->buf;
217 cl->next = NULL;
218
219 if (b && r->request_body_in_single_buf) {
220 size = b->last - b->pos;
221 ngx_memcpy(rb->buf->pos, b->pos, size);
222 rb->buf->last += size;
223
224 next = &rb->bufs;
225 }
226
227 *next = cl;
228
229 if (r->request_body_in_file_only || r->request_body_in_single_buf) {
230 rb->to_write = rb->bufs;
231
232 } else {
233 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
234 } 167 }
235 168
236 r->read_event_handler = ngx_http_read_client_request_body_handler; 169 r->read_event_handler = ngx_http_read_client_request_body_handler;
237 170 r->write_event_handler = ngx_http_request_empty_handler;
238 return ngx_http_do_read_client_request_body(r); 171
172 rc = ngx_http_do_read_client_request_body(r);
173
174 done:
175
176 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
177 r->main->count--;
178 }
179
180 return rc;
239 } 181 }
240 182
241 183
242 static void 184 static void
243 ngx_http_read_client_request_body_handler(ngx_http_request_t *r) 185 ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
259 201
260 202
261 static ngx_int_t 203 static ngx_int_t
262 ngx_http_do_read_client_request_body(ngx_http_request_t *r) 204 ngx_http_do_read_client_request_body(ngx_http_request_t *r)
263 { 205 {
206 off_t rest;
264 size_t size; 207 size_t size;
265 ssize_t n; 208 ssize_t n;
209 ngx_int_t rc;
266 ngx_buf_t *b; 210 ngx_buf_t *b;
211 ngx_chain_t *cl, out;
267 ngx_connection_t *c; 212 ngx_connection_t *c;
268 ngx_http_request_body_t *rb; 213 ngx_http_request_body_t *rb;
269 ngx_http_core_loc_conf_t *clcf; 214 ngx_http_core_loc_conf_t *clcf;
270 215
271 c = r->connection; 216 c = r->connection;
276 221
277 for ( ;; ) { 222 for ( ;; ) {
278 for ( ;; ) { 223 for ( ;; ) {
279 if (rb->buf->last == rb->buf->end) { 224 if (rb->buf->last == rb->buf->end) {
280 225
281 if (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) { 226 /* pass buffer to request body filter chain */
227
228 out.buf = rb->buf;
229 out.next = NULL;
230
231 rc = ngx_http_request_body_filter(r, &out);
232
233 if (rc != NGX_OK) {
234 return rc;
235 }
236
237 /* write to file */
238
239 if (ngx_http_write_request_body(r) != NGX_OK) {
282 return NGX_HTTP_INTERNAL_SERVER_ERROR; 240 return NGX_HTTP_INTERNAL_SERVER_ERROR;
283 } 241 }
284 242
285 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs; 243 /* update chains */
244
245 rc = ngx_http_request_body_filter(r, NULL);
246
247 if (rc != NGX_OK) {
248 return rc;
249 }
250
251 if (rb->busy != NULL) {
252 return NGX_HTTP_INTERNAL_SERVER_ERROR;
253 }
254
255 rb->buf->pos = rb->buf->start;
286 rb->buf->last = rb->buf->start; 256 rb->buf->last = rb->buf->start;
287 } 257 }
288 258
289 size = rb->buf->end - rb->buf->last; 259 size = rb->buf->end - rb->buf->last;
290 260 rest = rb->rest - (rb->buf->last - rb->buf->pos);
291 if ((off_t) size > rb->rest) { 261
292 size = (size_t) rb->rest; 262 if ((off_t) size > rest) {
263 size = (size_t) rest;
293 } 264 }
294 265
295 n = c->recv(c, rb->buf->last, size); 266 n = c->recv(c, rb->buf->last, size);
296 267
297 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, 268 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
310 c->error = 1; 281 c->error = 1;
311 return NGX_HTTP_BAD_REQUEST; 282 return NGX_HTTP_BAD_REQUEST;
312 } 283 }
313 284
314 rb->buf->last += n; 285 rb->buf->last += n;
315 rb->rest -= n;
316 r->request_length += n; 286 r->request_length += n;
287
288 if (n == rest) {
289 /* pass buffer to request body filter chain */
290
291 out.buf = rb->buf;
292 out.next = NULL;
293
294 rc = ngx_http_request_body_filter(r, &out);
295
296 if (rc != NGX_OK) {
297 return rc;
298 }
299 }
317 300
318 if (rb->rest == 0) { 301 if (rb->rest == 0) {
319 break; 302 break;
320 } 303 }
321 304
349 332
350 if (rb->temp_file || r->request_body_in_file_only) { 333 if (rb->temp_file || r->request_body_in_file_only) {
351 334
352 /* save the last part */ 335 /* save the last part */
353 336
354 if (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) { 337 if (ngx_http_write_request_body(r) != NGX_OK) {
355 return NGX_HTTP_INTERNAL_SERVER_ERROR; 338 return NGX_HTTP_INTERNAL_SERVER_ERROR;
356 } 339 }
357 340
358 b = ngx_calloc_buf(r->pool); 341 cl = ngx_chain_get_free_buf(r->pool, &rb->free);
359 if (b == NULL) { 342 if (cl == NULL) {
360 return NGX_HTTP_INTERNAL_SERVER_ERROR; 343 return NGX_HTTP_INTERNAL_SERVER_ERROR;
361 } 344 }
362 345
346 b = cl->buf;
347
348 ngx_memzero(b, sizeof(ngx_buf_t));
349
363 b->in_file = 1; 350 b->in_file = 1;
364 b->file_pos = 0;
365 b->file_last = rb->temp_file->file.offset; 351 b->file_last = rb->temp_file->file.offset;
366 b->file = &rb->temp_file->file; 352 b->file = &rb->temp_file->file;
367 353
368 if (rb->bufs->next) { 354 rb->bufs = cl;
369 rb->bufs->next->buf = b;
370
371 } else {
372 rb->bufs->buf = b;
373 }
374 }
375
376 if (rb->bufs->next
377 && (r->request_body_in_file_only || r->request_body_in_single_buf))
378 {
379 rb->bufs = rb->bufs->next;
380 } 355 }
381 356
382 r->read_event_handler = ngx_http_block_reading; 357 r->read_event_handler = ngx_http_block_reading;
383 358
384 rb->post_handler(r); 359 rb->post_handler(r);
386 return NGX_OK; 361 return NGX_OK;
387 } 362 }
388 363
389 364
390 static ngx_int_t 365 static ngx_int_t
391 ngx_http_write_request_body(ngx_http_request_t *r, ngx_chain_t *body) 366 ngx_http_write_request_body(ngx_http_request_t *r)
392 { 367 {
393 ssize_t n; 368 ssize_t n;
369 ngx_chain_t *cl;
394 ngx_temp_file_t *tf; 370 ngx_temp_file_t *tf;
395 ngx_http_request_body_t *rb; 371 ngx_http_request_body_t *rb;
396 ngx_http_core_loc_conf_t *clcf; 372 ngx_http_core_loc_conf_t *clcf;
397 373
398 rb = r->request_body; 374 rb = r->request_body;
375
376 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
377 "http write client request body, bufs %p", rb->bufs);
399 378
400 if (rb->temp_file == NULL) { 379 if (rb->temp_file == NULL) {
401 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); 380 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
402 if (tf == NULL) { 381 if (tf == NULL) {
403 return NGX_ERROR; 382 return NGX_ERROR;
417 if (r->request_body_file_group_access) { 396 if (r->request_body_file_group_access) {
418 tf->access = 0660; 397 tf->access = 0660;
419 } 398 }
420 399
421 rb->temp_file = tf; 400 rb->temp_file = tf;
422 } 401
423 402 if (rb->bufs == NULL) {
424 n = ngx_write_chain_to_temp_file(rb->temp_file, body); 403 /* empty body with r->request_body_in_file_only */
404
405 if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
406 tf->persistent, tf->clean, tf->access)
407 != NGX_OK)
408 {
409 return NGX_ERROR;
410 }
411
412 return NGX_OK;
413 }
414 }
415
416 if (rb->bufs == NULL) {
417 return NGX_OK;
418 }
419
420 n = ngx_write_chain_to_temp_file(rb->temp_file, rb->bufs);
425 421
426 /* TODO: n == 0 or not complete and level event */ 422 /* TODO: n == 0 or not complete and level event */
427 423
428 if (n == NGX_ERROR) { 424 if (n == NGX_ERROR) {
429 return NGX_ERROR; 425 return NGX_ERROR;
430 } 426 }
431 427
432 rb->temp_file->offset += n; 428 rb->temp_file->offset += n;
433 429
430 /* mark all buffers as written */
431
432 for (cl = rb->bufs; cl; cl = cl->next) {
433 cl->buf->pos = cl->buf->last;
434 }
435
436 rb->bufs = NULL;
437
434 return NGX_OK; 438 return NGX_OK;
435 } 439 }
436 440
437 441
438 ngx_int_t 442 ngx_int_t
439 ngx_http_discard_request_body(ngx_http_request_t *r) 443 ngx_http_discard_request_body(ngx_http_request_t *r)
440 { 444 {
441 ssize_t size; 445 ssize_t size;
446 ngx_int_t rc;
442 ngx_event_t *rev; 447 ngx_event_t *rev;
443 448
444 if (r != r->main || r->discard_body) { 449 if (r != r->main || r->discard_body || r->request_body) {
445 return NGX_OK; 450 return NGX_OK;
446 } 451 }
447 452
448 if (ngx_http_test_expect(r) != NGX_OK) { 453 if (ngx_http_test_expect(r) != NGX_OK) {
449 return NGX_HTTP_INTERNAL_SERVER_ERROR; 454 return NGX_HTTP_INTERNAL_SERVER_ERROR;
455 460
456 if (rev->timer_set) { 461 if (rev->timer_set) {
457 ngx_del_timer(rev); 462 ngx_del_timer(rev);
458 } 463 }
459 464
460 if (r->headers_in.content_length_n <= 0 || r->request_body) { 465 if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
461 return NGX_OK; 466 return NGX_OK;
462 } 467 }
463 468
464 size = r->header_in->last - r->header_in->pos; 469 size = r->header_in->last - r->header_in->pos;
465 470
466 if (size) { 471 if (size || r->headers_in.chunked) {
467 if (r->headers_in.content_length_n > size) { 472 rc = ngx_http_discard_request_body_filter(r, r->header_in);
468 r->header_in->pos += size; 473
469 r->headers_in.content_length_n -= size; 474 if (rc != NGX_OK) {
470 475 return rc;
471 } else { 476 }
472 r->header_in->pos += (size_t) r->headers_in.content_length_n; 477
473 r->headers_in.content_length_n = 0; 478 if (r->headers_in.content_length_n == 0) {
474 return NGX_OK; 479 return NGX_OK;
475 } 480 }
476 } 481 }
482
483 rc = ngx_http_read_discarded_request_body(r);
484
485 if (rc == NGX_OK) {
486 r->lingering_close = 0;
487 return NGX_OK;
488 }
489
490 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
491 return rc;
492 }
493
494 /* rc == NGX_AGAIN */
477 495
478 r->read_event_handler = ngx_http_discarded_request_body_handler; 496 r->read_event_handler = ngx_http_discarded_request_body_handler;
479 497
480 if (ngx_handle_read_event(rev, 0) != NGX_OK) { 498 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
481 return NGX_HTTP_INTERNAL_SERVER_ERROR; 499 return NGX_HTTP_INTERNAL_SERVER_ERROR;
482 } 500 }
483 501
484 if (ngx_http_read_discarded_request_body(r) == NGX_OK) { 502 r->count++;
485 r->lingering_close = 0; 503 r->discard_body = 1;
486
487 } else {
488 r->count++;
489 r->discard_body = 1;
490 }
491 504
492 return NGX_OK; 505 return NGX_OK;
493 } 506 }
494 507
495 508
533 r->lingering_close = 0; 546 r->lingering_close = 0;
534 ngx_http_finalize_request(r, NGX_DONE); 547 ngx_http_finalize_request(r, NGX_DONE);
535 return; 548 return;
536 } 549 }
537 550
551 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
552 c->error = 1;
553 ngx_http_finalize_request(r, NGX_ERROR);
554 return;
555 }
556
538 /* rc == NGX_AGAIN */ 557 /* rc == NGX_AGAIN */
539 558
540 if (ngx_handle_read_event(rev, 0) != NGX_OK) { 559 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
541 c->error = 1; 560 c->error = 1;
542 ngx_http_finalize_request(r, NGX_ERROR); 561 ngx_http_finalize_request(r, NGX_ERROR);
559 578
560 579
561 static ngx_int_t 580 static ngx_int_t
562 ngx_http_read_discarded_request_body(ngx_http_request_t *r) 581 ngx_http_read_discarded_request_body(ngx_http_request_t *r)
563 { 582 {
564 size_t size; 583 size_t size;
565 ssize_t n; 584 ssize_t n;
566 u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE]; 585 ngx_int_t rc;
586 ngx_buf_t b;
587 u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];
567 588
568 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 589 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
569 "http read discarded body"); 590 "http read discarded body");
591
592 ngx_memzero(&b, sizeof(ngx_buf_t));
593
594 b.temporary = 1;
570 595
571 for ( ;; ) { 596 for ( ;; ) {
572 if (r->headers_in.content_length_n == 0) { 597 if (r->headers_in.content_length_n == 0) {
573 r->read_event_handler = ngx_http_block_reading; 598 r->read_event_handler = ngx_http_block_reading;
574 return NGX_OK; 599 return NGX_OK;
576 601
577 if (!r->connection->read->ready) { 602 if (!r->connection->read->ready) {
578 return NGX_AGAIN; 603 return NGX_AGAIN;
579 } 604 }
580 605
581 size = (r->headers_in.content_length_n > NGX_HTTP_DISCARD_BUFFER_SIZE) ? 606 size = (size_t) ngx_min(r->headers_in.content_length_n,
582 NGX_HTTP_DISCARD_BUFFER_SIZE: 607 NGX_HTTP_DISCARD_BUFFER_SIZE);
583 (size_t) r->headers_in.content_length_n;
584 608
585 n = r->connection->recv(r->connection, buffer, size); 609 n = r->connection->recv(r->connection, buffer, size);
586 610
587 if (n == NGX_ERROR) { 611 if (n == NGX_ERROR) {
588 r->connection->error = 1; 612 r->connection->error = 1;
595 619
596 if (n == 0) { 620 if (n == 0) {
597 return NGX_OK; 621 return NGX_OK;
598 } 622 }
599 623
600 r->headers_in.content_length_n -= n; 624 b.pos = buffer;
601 } 625 b.last = buffer + n;
626
627 rc = ngx_http_discard_request_body_filter(r, &b);
628
629 if (rc != NGX_OK) {
630 return rc;
631 }
632 }
633 }
634
635
636 static ngx_int_t
637 ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
638 {
639 size_t size;
640 ngx_int_t rc;
641 ngx_http_request_body_t *rb;
642
643 if (r->headers_in.chunked) {
644
645 rb = r->request_body;
646
647 if (rb == NULL) {
648
649 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
650 if (rb == NULL) {
651 return NGX_HTTP_INTERNAL_SERVER_ERROR;
652 }
653
654 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
655 if (rb->chunked == NULL) {
656 return NGX_HTTP_INTERNAL_SERVER_ERROR;
657 }
658
659 r->request_body = rb;
660 }
661
662 for ( ;; ) {
663
664 rc = ngx_http_parse_chunked(r, b, rb->chunked);
665
666 if (rc == NGX_OK) {
667
668 /* a chunk has been parsed successfully */
669
670 size = b->last - b->pos;
671
672 if ((off_t) size > rb->chunked->size) {
673 b->pos += rb->chunked->size;
674 rb->chunked->size = 0;
675
676 } else {
677 rb->chunked->size -= size;
678 b->pos = b->last;
679 }
680
681 continue;
682 }
683
684 if (rc == NGX_DONE) {
685
686 /* a whole response has been parsed successfully */
687
688 r->headers_in.content_length_n = 0;
689 break;
690 }
691
692 if (rc == NGX_AGAIN) {
693
694 /* set amount of data we want to see next time */
695
696 r->headers_in.content_length_n = rb->chunked->length;
697 break;
698 }
699
700 /* invalid */
701
702 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
703 "client sent invalid chunked body");
704
705 return NGX_HTTP_BAD_REQUEST;
706 }
707
708 } else {
709 size = b->last - b->pos;
710
711 if ((off_t) size > r->headers_in.content_length_n) {
712 b->pos += r->headers_in.content_length_n;
713 r->headers_in.content_length_n = 0;
714
715 } else {
716 b->pos = b->last;
717 r->headers_in.content_length_n -= size;
718 }
719 }
720
721 return NGX_OK;
602 } 722 }
603 723
604 724
605 static ngx_int_t 725 static ngx_int_t
606 ngx_http_test_expect(ngx_http_request_t *r) 726 ngx_http_test_expect(ngx_http_request_t *r)
640 760
641 /* we assume that such small packet should be send successfully */ 761 /* we assume that such small packet should be send successfully */
642 762
643 return NGX_ERROR; 763 return NGX_ERROR;
644 } 764 }
765
766
767 static ngx_int_t
768 ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
769 {
770 if (r->headers_in.chunked) {
771 return ngx_http_request_body_chunked_filter(r, in);
772
773 } else {
774 return ngx_http_request_body_length_filter(r, in);
775 }
776 }
777
778
779 static ngx_int_t
780 ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
781 {
782 size_t size;
783 ngx_int_t rc;
784 ngx_buf_t *b;
785 ngx_chain_t *cl, *tl, *out, **ll;
786 ngx_http_request_body_t *rb;
787
788 rb = r->request_body;
789
790 if (rb->rest == -1) {
791 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
792 "http request body content length filter");
793
794 rb->rest = r->headers_in.content_length_n;
795 }
796
797 out = NULL;
798 ll = &out;
799
800 for (cl = in; cl; cl = cl->next) {
801
802 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
803 if (tl == NULL) {
804 return NGX_HTTP_INTERNAL_SERVER_ERROR;
805 }
806
807 b = tl->buf;
808
809 ngx_memzero(b, sizeof(ngx_buf_t));
810
811 b->temporary = 1;
812 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
813 b->start = cl->buf->start;
814 b->pos = cl->buf->pos;
815 b->last = cl->buf->last;
816 b->end = cl->buf->end;
817
818 size = cl->buf->last - cl->buf->pos;
819
820 if ((off_t) size < rb->rest) {
821 cl->buf->pos = cl->buf->last;
822 rb->rest -= size;
823
824 } else {
825 cl->buf->pos += rb->rest;
826 rb->rest = 0;
827 b->last = cl->buf->pos;
828 b->last_buf = 1;
829 }
830
831 *ll = tl;
832 ll = &tl->next;
833 }
834
835 rc = ngx_http_request_body_save_filter(r, out);
836
837 ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
838 (ngx_buf_tag_t) &ngx_http_read_client_request_body);
839
840 return rc;
841 }
842
843
844 static ngx_int_t
845 ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
846 {
847 size_t size;
848 ngx_int_t rc;
849 ngx_buf_t *b;
850 ngx_chain_t *cl, *out, *tl, **ll;
851 ngx_http_request_body_t *rb;
852 ngx_http_core_loc_conf_t *clcf;
853
854 rb = r->request_body;
855
856 if (rb->rest == -1) {
857
858 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
859 "http request body chunked filter");
860
861 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
862 if (rb->chunked == NULL) {
863 return NGX_HTTP_INTERNAL_SERVER_ERROR;
864 }
865
866 r->headers_in.content_length_n = 0;
867 rb->rest = 3;
868 }
869
870 out = NULL;
871 ll = &out;
872
873 for (cl = in; cl; cl = cl->next) {
874
875 for ( ;; ) {
876
877 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
878 "http body chunked buf "
879 "t:%d f:%d %p, pos %p, size: %z file: %O, size: %z",
880 cl->buf->temporary, cl->buf->in_file,
881 cl->buf->start, cl->buf->pos,
882 cl->buf->last - cl->buf->pos,
883 cl->buf->file_pos,
884 cl->buf->file_last - cl->buf->file_pos);
885
886 rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked);
887
888 if (rc == NGX_OK) {
889
890 /* a chunk has been parsed successfully */
891
892 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
893
894 if (clcf->client_max_body_size
895 && clcf->client_max_body_size
896 < r->headers_in.content_length_n + rb->chunked->size)
897 {
898 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
899 "client intended to send too large chunked "
900 "body: %O bytes",
901 r->headers_in.content_length_n
902 + rb->chunked->size);
903
904 r->lingering_close = 1;
905
906 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
907 }
908
909 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
910 if (tl == NULL) {
911 return NGX_HTTP_INTERNAL_SERVER_ERROR;
912 }
913
914 b = tl->buf;
915
916 ngx_memzero(b, sizeof(ngx_buf_t));
917
918 b->temporary = 1;
919 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
920 b->start = cl->buf->start;
921 b->pos = cl->buf->pos;
922 b->last = cl->buf->last;
923 b->end = cl->buf->end;
924
925 *ll = tl;
926 ll = &tl->next;
927
928 size = cl->buf->last - cl->buf->pos;
929
930 if ((off_t) size > rb->chunked->size) {
931 cl->buf->pos += rb->chunked->size;
932 r->headers_in.content_length_n += rb->chunked->size;
933 rb->chunked->size = 0;
934
935 } else {
936 rb->chunked->size -= size;
937 r->headers_in.content_length_n += size;
938 cl->buf->pos = cl->buf->last;
939 }
940
941 b->last = cl->buf->pos;
942
943 continue;
944 }
945
946 if (rc == NGX_DONE) {
947
948 /* a whole response has been parsed successfully */
949
950 rb->rest = 0;
951
952 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
953 if (tl == NULL) {
954 return NGX_HTTP_INTERNAL_SERVER_ERROR;
955 }
956
957 b = tl->buf;
958
959 ngx_memzero(b, sizeof(ngx_buf_t));
960
961 b->last_buf = 1;
962
963 *ll = tl;
964 ll = &tl->next;
965
966 break;
967 }
968
969 if (rc == NGX_AGAIN) {
970
971 /* set rb->rest, amount of data we want to see next time */
972
973 rb->rest = rb->chunked->length;
974
975 break;
976 }
977
978 /* invalid */
979
980 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
981 "client sent invalid chunked body");
982
983 return NGX_HTTP_BAD_REQUEST;
984 }
985 }
986
987 rc = ngx_http_request_body_save_filter(r, out);
988
989 ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
990 (ngx_buf_tag_t) &ngx_http_read_client_request_body);
991
992 return rc;
993 }
994
995
996 static ngx_int_t
997 ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
998 {
999 #if (NGX_DEBUG)
1000 ngx_chain_t *cl;
1001 #endif
1002 ngx_http_request_body_t *rb;
1003
1004 rb = r->request_body;
1005
1006 #if (NGX_DEBUG)
1007
1008 for (cl = rb->bufs; cl; cl = cl->next) {
1009 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1010 "http body old buf t:%d f:%d %p, pos %p, size: %z "
1011 "file: %O, size: %z",
1012 cl->buf->temporary, cl->buf->in_file,
1013 cl->buf->start, cl->buf->pos,
1014 cl->buf->last - cl->buf->pos,
1015 cl->buf->file_pos,
1016 cl->buf->file_last - cl->buf->file_pos);
1017 }
1018
1019 for (cl = in; cl; cl = cl->next) {
1020 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1021 "http body new buf t:%d f:%d %p, pos %p, size: %z "
1022 "file: %O, size: %z",
1023 cl->buf->temporary, cl->buf->in_file,
1024 cl->buf->start, cl->buf->pos,
1025 cl->buf->last - cl->buf->pos,
1026 cl->buf->file_pos,
1027 cl->buf->file_last - cl->buf->file_pos);
1028 }
1029
1030 #endif
1031
1032 /* TODO: coalesce neighbouring buffers */
1033
1034 if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) {
1035 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1036 }
1037
1038 return NGX_OK;
1039 }