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

Linux Cross Reference
Nginx/http/ngx_http_request_body.c

Version: ~ [ nginx-0.6.26 ] ~ [ nginx-0.5.35 ] ~ [ nginx-0.5.20 ] ~ [ nginx-0.5.19 ] ~

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

~ [ 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.