1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10
11
12 static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
13 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
14 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r,
15 ngx_chain_t *body);
16 static void ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r);
17 static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
18 static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);
19
20
21 /*
22 * on completion ngx_http_read_client_request_body() adds to
23 * r->request_body->bufs one or two bufs:
24 * *) one memory buf that was preread in r->header_in;
25 * *) one memory or file buf that contains the rest of the body
26 */
27
28 ngx_int_t
29 ngx_http_read_client_request_body(ngx_http_request_t *r,
30 ngx_http_client_body_handler_pt post_handler)
31 {
32 size_t preread;
33 ssize_t size;
34 ngx_buf_t *b;
35 ngx_chain_t *cl, **next;
36 ngx_temp_file_t *tf;
37 ngx_http_request_body_t *rb;
38 ngx_http_core_loc_conf_t *clcf;
39
40 r->main->count++;
41
42 if (r->request_body || r->discard_body) {
43 post_handler(r);
44 return NGX_OK;
45 }
46
47 if (ngx_http_test_expect(r) != NGX_OK) {
48 return NGX_HTTP_INTERNAL_SERVER_ERROR;
49 }
50
51 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
52 if (rb == NULL) {
53 return NGX_HTTP_INTERNAL_SERVER_ERROR;
54 }
55
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
103 /*
104 * set by ngx_pcalloc():
105 *
106 * rb->bufs = NULL;
107 * rb->buf = NULL;
108 * rb->rest = 0;
109 */
110
111 preread = r->header_in->last - r->header_in->pos;
112
113 if (preread) {
114
115 /* there is the pre-read part of the request body */
116
117 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
118 "http client request body preread %uz", preread);
119
120 b = ngx_calloc_buf(r->pool);
121 if (b == NULL) {
122 return NGX_HTTP_INTERNAL_SERVER_ERROR;
123 }
124
125 b->temporary = 1;
126 b->start = r->header_in->pos;
127 b->pos = r->header_in->pos;
128 b->last = r->header_in->last;
129 b->end = r->header_in->end;
130
131 rb->bufs = ngx_alloc_chain_link(r->pool);
132 if (rb->bufs == NULL) {
133 return NGX_HTTP_INTERNAL_SERVER_ERROR;
134 }
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
148 if (r->request_body_in_file_only) {
149 if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) {
150 return NGX_HTTP_INTERNAL_SERVER_ERROR;
151 }
152 }
153
154 post_handler(r);
155
156 return NGX_OK;
157 }
158
159 /*
160 * to not consider the body as pipelined request in
161 * ngx_http_set_keepalive()
162 */
163 r->header_in->pos = r->header_in->last;
164
165 r->request_length += preread;
166
167 rb->rest = r->headers_in.content_length_n - preread;
168
169 if (rb->rest <= (off_t) (b->end - b->last)) {
170
171 /* the whole request body may be placed in r->header_in */
172
173 rb->to_write = rb->bufs;
174
175 r->read_event_handler = ngx_http_read_client_request_body_handler;
176
177 return ngx_http_do_read_client_request_body(r);
178 }
179
180 next = &rb->bufs->next;
181
182 } else {
183 b = NULL;
184 rb->rest = r->headers_in.content_length_n;
185 next = &rb->bufs;
186 }
187
188 size = clcf->client_body_buffer_size;
189 size += size >> 2;
190
191 if (rb->rest < size) {
192 size = (ssize_t) rb->rest;
193
194 if (r->request_body_in_single_buf) {
195 size += preread;
196 }
197
198 } else {
199 size = clcf->client_body_buffer_size;
200
201 /* disable copying buffer for r->request_body_in_single_buf */
202 b = NULL;
203 }
204
205 rb->buf = ngx_create_temp_buf(r->pool, size);
206 if (rb->buf == NULL) {
207 return NGX_HTTP_INTERNAL_SERVER_ERROR;
208 }
209
210 cl = ngx_alloc_chain_link(r->pool);
211 if (cl == NULL) {
212 return NGX_HTTP_INTERNAL_SERVER_ERROR;
213 }
214
215 cl->buf = rb->buf;
216 cl->next = NULL;
217
218 if (b && r->request_body_in_single_buf) {
219 size = b->last - b->pos;
220 ngx_memcpy(rb->buf->pos, b->pos, size);
221 rb->buf->last += size;
222
223 next = &rb->bufs;
224 }
225
226 *next = cl;
227
228 if (r->request_body_in_file_only || r->request_body_in_single_buf) {
229 rb->to_write = rb->bufs;
230
231 } else {
232 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
233 }
234
235 r->read_event_handler = ngx_http_read_client_request_body_handler;
236
237 return ngx_http_do_read_client_request_body(r);
238 }
239
240
241 static void
242 ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
243 {
244 ngx_int_t rc;
245
246 if (r->connection->read->timedout) {
247 r->connection->timedout = 1;
248 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
249 return;
250 }
251
252 rc = ngx_http_do_read_client_request_body(r);
253
254 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
255 ngx_http_finalize_request(r, rc);
256 }
257 }
258
259
260 static ngx_int_t
261 ngx_http_do_read_client_request_body(ngx_http_request_t *r)
262 {
263 size_t size;
264 ssize_t n;
265 ngx_buf_t *b;
266 ngx_connection_t *c;
267 ngx_http_request_body_t *rb;
268 ngx_http_core_loc_conf_t *clcf;
269
270 c = r->connection;
271 rb = r->request_body;
272
273 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
274 "http read client request body");
275
276 for ( ;; ) {
277 for ( ;; ) {
278 if (rb->buf->last == rb->buf->end) {
279
280 if (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) {
281 return NGX_HTTP_INTERNAL_SERVER_ERROR;
282 }
283
284 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
285 rb->buf->last = rb->buf->start;
286 }
287
288 size = rb->buf->end - rb->buf->last;
289
290 if ((off_t) size > rb->rest) {
291 size = (size_t) rb->rest;
292 }
293
294 n = c->recv(c, rb->buf->last, size);
295
296 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
297 "http client request body recv %z", n);
298
299 if (n == NGX_AGAIN) {
300 break;
301 }
302
303 if (n == 0) {
304 ngx_log_error(NGX_LOG_INFO, c->log, 0,
305 "client closed prematurely connection");
306 }
307
308 if (n == 0 || n == NGX_ERROR) {
309 c->error = 1;
310 return NGX_HTTP_BAD_REQUEST;
311 }
312
313 rb->buf->last += n;
314 rb->rest -= n;
315 r->request_length += n;
316
317 if (rb->rest == 0) {
318 break;
319 }
320
321 if (rb->buf->last < rb->buf->end) {
322 break;
323 }
324 }
325
326 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
327 "http client request body rest %O", rb->rest);
328
329 if (rb->rest == 0) {
330 break;
331 }
332
333 if (!c->read->ready) {
334 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
335 ngx_add_timer(c->read, clcf->client_body_timeout);
336
337 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
338 return NGX_HTTP_INTERNAL_SERVER_ERROR;
339 }
340
341 return NGX_AGAIN;
342 }
343 }
344
345 if (c->read->timer_set) {
346 ngx_del_timer(c->read);
347 }
348
349 if (rb->temp_file || r->request_body_in_file_only) {
350
351 /* save the last part */
352
353 if (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) {
354 return NGX_HTTP_INTERNAL_SERVER_ERROR;
355 }
356
357 b = ngx_calloc_buf(r->pool);
358 if (b == NULL) {
359 return NGX_HTTP_INTERNAL_SERVER_ERROR;
360 }
361
362 b->in_file = 1;
363 b->file_pos = 0;
364 b->file_last = rb->temp_file->file.offset;
365 b->file = &rb->temp_file->file;
366
367 if (rb->bufs->next) {
368 rb->bufs->next->buf = b;
369
370 } else {
371 rb->bufs->buf = b;
372 }
373 }
374
375 if (r->request_body_in_file_only && rb->bufs->next) {
376 rb->bufs = rb->bufs->next;
377 }
378
379 rb->post_handler(r);
380
381 return NGX_OK;
382 }
383
384
385 static ngx_int_t
386 ngx_http_write_request_body(ngx_http_request_t *r, ngx_chain_t *body)
387 {
388 ssize_t n;
389 ngx_temp_file_t *tf;
390 ngx_http_request_body_t *rb;
391 ngx_http_core_loc_conf_t *clcf;
392
393 rb = r->request_body;
394
395 if (rb->temp_file == NULL) {
396 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
397 if (tf == NULL) {
398 return NGX_ERROR;
399 }
400
401 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
402
403 tf->file.fd = NGX_INVALID_FILE;
404 tf->file.log = r->connection->log;
405 tf->path = clcf->client_body_temp_path;
406 tf->pool = r->pool;
407 tf->warn = "a client request body is buffered to a temporary file";
408 tf->log_level = r->request_body_file_log_level;
409 tf->persistent = r->request_body_in_persistent_file;
410 tf->clean = r->request_body_in_clean_file;
411
412 if (r->request_body_file_group_access) {
413 tf->access = 0660;
414 }
415
416 rb->temp_file = tf;
417 }
418
419 n = ngx_write_chain_to_temp_file(rb->temp_file, body);
420
421 /* TODO: n == 0 or not complete and level event */
422
423 if (n == NGX_ERROR) {
424 return NGX_ERROR;
425 }
426
427 rb->temp_file->offset += n;
428
429 return NGX_OK;
430 }
431
432
433 ngx_int_t
434 ngx_http_discard_request_body(ngx_http_request_t *r)
435 {
436 ssize_t size;
437 ngx_event_t *rev;
438
439 if (r != r->main || r->discard_body) {
440 return NGX_OK;
441 }
442
443 if (ngx_http_test_expect(r) != NGX_OK) {
444 return NGX_HTTP_INTERNAL_SERVER_ERROR;
445 }
446
447 rev = r->connection->read;
448
449 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");
450
451 if (rev->timer_set) {
452 ngx_del_timer(rev);
453 }
454
455 if (r->headers_in.content_length_n <= 0 || r->request_body) {
456 return NGX_OK;
457 }
458
459 size = r->header_in->last - r->header_in->pos;
460
461 if (size) {
462 if (r->headers_in.content_length_n > size) {
463 r->headers_in.content_length_n -= size;
464
465 } else {
466 r->header_in->pos += (size_t) r->headers_in.content_length_n;
467 r->headers_in.content_length_n = 0;
468 return NGX_OK;
469 }
470 }
471
472 r->read_event_handler = ngx_http_read_discarded_request_body_handler;
473
474 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
475 return NGX_HTTP_INTERNAL_SERVER_ERROR;
476 }
477
478 if (ngx_http_read_discarded_request_body(r) == NGX_OK) {
479 r->lingering_close = 0;
480
481 } else {
482 r->count++;
483 r->discard_body = 1;
484 }
485
486 return NGX_OK;
487 }
488
489
490 static void
491 ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r)
492 {
493 ngx_int_t rc;
494 ngx_msec_t timer;
495 ngx_event_t *rev;
496 ngx_connection_t *c;
497 ngx_http_core_loc_conf_t *clcf;
498
499 c = r->connection;
500 rev = c->read;
501
502 if (rev->timedout) {
503 c->timedout = 1;
504 c->error = 1;
505 ngx_http_finalize_request(r, 0);
506 return;
507 }
508
509 if (r->lingering_time) {
510 timer = (ngx_msec_t) (r->lingering_time - ngx_time());
511
512 if (timer <= 0) {
513 r->discard_body = 0;
514 r->lingering_close = 0;
515 ngx_http_finalize_request(r, 0);
516 return;
517 }
518
519 } else {
520 timer = 0;
521 }
522
523 rc = ngx_http_read_discarded_request_body(r);
524
525 if (rc == NGX_OK) {
526
527 r->discard_body = 0;
528 r->lingering_close = 0;
529
530 if (r->done) {
531 ngx_http_finalize_request(r, 0);
532 }
533
534 return;
535 }
536
537 /* rc == NGX_AGAIN */
538
539 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
540 c->error = 1;
541 ngx_http_finalize_request(r, rc);
542 return;
543 }
544
545 if (timer) {
546
547 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
548
549 timer *= 1000;
550
551 if (timer > clcf->lingering_timeout) {
552 timer = clcf->lingering_timeout;
553 }
554
555 ngx_add_timer(rev, timer);
556 }
557 }
558
559
560 static ngx_int_t
561 ngx_http_read_discarded_request_body(ngx_http_request_t *r)
562 {
563 size_t size;
564 ssize_t n;
565 u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];
566
567 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
568 "http read discarded body");
569
570 for ( ;; ) {
571 if (r->headers_in.content_length_n == 0) {
572 r->read_event_handler = ngx_http_block_reading;
573 return NGX_OK;
574 }
575
576 if (!r->connection->read->ready) {
577 return NGX_AGAIN;
578 }
579
580 size = (r->headers_in.content_length_n > NGX_HTTP_DISCARD_BUFFER_SIZE) ?
581 NGX_HTTP_DISCARD_BUFFER_SIZE:
582 (size_t) r->headers_in.content_length_n;
583
584 n = r->connection->recv(r->connection, buffer, size);
585
586 if (n == NGX_ERROR) {
587 r->connection->error = 1;
588 return NGX_OK;
589 }
590
591 if (n == NGX_AGAIN) {
592 return NGX_AGAIN;
593 }
594
595 if (n == 0) {
596 return NGX_OK;
597 }
598
599 r->headers_in.content_length_n -= n;
600 }
601 }
602
603
604 static ngx_int_t
605 ngx_http_test_expect(ngx_http_request_t *r)
606 {
607 ngx_int_t n;
608 ngx_str_t *expect;
609
610 if (r->expect_tested
611 || r->headers_in.expect == NULL
612 || r->http_version < NGX_HTTP_VERSION_11)
613 {
614 return NGX_OK;
615 }
616
617 r->expect_tested = 1;
618
619 expect = &r->headers_in.expect->value;
620
621 if (expect->len != sizeof("100-continue") - 1
622 || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
623 sizeof("100-continue") - 1)
624 != 0)
625 {
626 return NGX_OK;
627 }
628
629 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
630 "send 100 Continue");
631
632 n = r->connection->send(r->connection,
633 (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
634 sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);
635
636 if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
637 return NGX_OK;
638 }
639
640 /* we assume that such small packet should be send successfully */
641
642 return NGX_ERROR;
643 }
644
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.