~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/http/ngx_http_request_body.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.