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