src/http/ngx_http_request_body.c - nginx-1.7.10

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
  9. static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
  10. static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r);
  11. static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
  12. static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r,
  13.     ngx_buf_t *b);
  14. static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);

  15. static ngx_int_t ngx_http_request_body_filter(ngx_http_request_t *r,
  16.     ngx_chain_t *in);
  17. static ngx_int_t ngx_http_request_body_length_filter(ngx_http_request_t *r,
  18.     ngx_chain_t *in);
  19. static ngx_int_t ngx_http_request_body_chunked_filter(ngx_http_request_t *r,
  20.     ngx_chain_t *in);
  21. static ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r,
  22.     ngx_chain_t *in);


  23. ngx_int_t
  24. ngx_http_read_client_request_body(ngx_http_request_t *r,
  25.     ngx_http_client_body_handler_pt post_handler)
  26. {
  27.     size_t                     preread;
  28.     ssize_t                    size;
  29.     ngx_int_t                  rc;
  30.     ngx_buf_t                 *b;
  31.     ngx_chain_t                out, *cl;
  32.     ngx_http_request_body_t   *rb;
  33.     ngx_http_core_loc_conf_t  *clcf;

  34.     r->main->count++;

  35. #if (NGX_HTTP_SPDY)
  36.     if (r->spdy_stream && r == r->main) {
  37.         rc = ngx_http_spdy_read_request_body(r, post_handler);
  38.         goto done;
  39.     }
  40. #endif

  41.     if (r != r->main || r->request_body || r->discard_body) {
  42.         post_handler(r);
  43.         return NGX_OK;
  44.     }

  45.     if (ngx_http_test_expect(r) != NGX_OK) {
  46.         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  47.         goto done;
  48.     }

  49.     rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
  50.     if (rb == NULL) {
  51.         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  52.         goto done;
  53.     }

  54.     /*
  55.      * set by ngx_pcalloc():
  56.      *
  57.      *     rb->bufs = NULL;
  58.      *     rb->buf = NULL;
  59.      *     rb->free = NULL;
  60.      *     rb->busy = NULL;
  61.      *     rb->chunked = NULL;
  62.      */

  63.     rb->rest = -1;
  64.     rb->post_handler = post_handler;

  65.     r->request_body = rb;

  66.     if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
  67.         post_handler(r);
  68.         return NGX_OK;
  69.     }

  70.     preread = r->header_in->last - r->header_in->pos;

  71.     if (preread) {

  72.         /* there is the pre-read part of the request body */

  73.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  74.                        "http client request body preread %uz", preread);

  75.         out.buf = r->header_in;
  76.         out.next = NULL;

  77.         rc = ngx_http_request_body_filter(r, &out);

  78.         if (rc != NGX_OK) {
  79.             goto done;
  80.         }

  81.         r->request_length += preread - (r->header_in->last - r->header_in->pos);

  82.         if (!r->headers_in.chunked
  83.             && rb->rest > 0
  84.             && rb->rest <= (off_t) (r->header_in->end - r->header_in->last))
  85.         {
  86.             /* the whole request body may be placed in r->header_in */

  87.             b = ngx_calloc_buf(r->pool);
  88.             if (b == NULL) {
  89.                 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  90.                 goto done;
  91.             }

  92.             b->temporary = 1;
  93.             b->start = r->header_in->pos;
  94.             b->pos = r->header_in->pos;
  95.             b->last = r->header_in->last;
  96.             b->end = r->header_in->end;

  97.             rb->buf = b;

  98.             r->read_event_handler = ngx_http_read_client_request_body_handler;
  99.             r->write_event_handler = ngx_http_request_empty_handler;

  100.             rc = ngx_http_do_read_client_request_body(r);
  101.             goto done;
  102.         }

  103.     } else {
  104.         /* set rb->rest */

  105.         if (ngx_http_request_body_filter(r, NULL) != NGX_OK) {
  106.             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  107.             goto done;
  108.         }
  109.     }

  110.     if (rb->rest == 0) {
  111.         /* the whole request body was pre-read */

  112.         if (r->request_body_in_file_only) {
  113.             if (ngx_http_write_request_body(r) != NGX_OK) {
  114.                 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  115.                 goto done;
  116.             }

  117.             if (rb->temp_file->file.offset != 0) {

  118.                 cl = ngx_chain_get_free_buf(r->pool, &rb->free);
  119.                 if (cl == NULL) {
  120.                     rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  121.                     goto done;
  122.                 }

  123.                 b = cl->buf;

  124.                 ngx_memzero(b, sizeof(ngx_buf_t));

  125.                 b->in_file = 1;
  126.                 b->file_last = rb->temp_file->file.offset;
  127.                 b->file = &rb->temp_file->file;

  128.                 rb->bufs = cl;

  129.             } else {
  130.                 rb->bufs = NULL;
  131.             }
  132.         }

  133.         post_handler(r);

  134.         return NGX_OK;
  135.     }

  136.     if (rb->rest < 0) {
  137.         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  138.                       "negative request body rest");
  139.         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  140.         goto done;
  141.     }

  142.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  143.     size = clcf->client_body_buffer_size;
  144.     size += size >> 2;

  145.     /* TODO: honor r->request_body_in_single_buf */

  146.     if (!r->headers_in.chunked && rb->rest < size) {
  147.         size = (ssize_t) rb->rest;

  148.         if (r->request_body_in_single_buf) {
  149.             size += preread;
  150.         }

  151.     } else {
  152.         size = clcf->client_body_buffer_size;
  153.     }

  154.     rb->buf = ngx_create_temp_buf(r->pool, size);
  155.     if (rb->buf == NULL) {
  156.         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  157.         goto done;
  158.     }

  159.     r->read_event_handler = ngx_http_read_client_request_body_handler;
  160.     r->write_event_handler = ngx_http_request_empty_handler;

  161.     rc = ngx_http_do_read_client_request_body(r);

  162. done:

  163.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  164.         r->main->count--;
  165.     }

  166.     return rc;
  167. }


  168. static void
  169. ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
  170. {
  171.     ngx_int_t  rc;

  172.     if (r->connection->read->timedout) {
  173.         r->connection->timedout = 1;
  174.         ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
  175.         return;
  176.     }

  177.     rc = ngx_http_do_read_client_request_body(r);

  178.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  179.         ngx_http_finalize_request(r, rc);
  180.     }
  181. }


  182. static ngx_int_t
  183. ngx_http_do_read_client_request_body(ngx_http_request_t *r)
  184. {
  185.     off_t                      rest;
  186.     size_t                     size;
  187.     ssize_t                    n;
  188.     ngx_int_t                  rc;
  189.     ngx_buf_t                 *b;
  190.     ngx_chain_t               *cl, out;
  191.     ngx_connection_t          *c;
  192.     ngx_http_request_body_t   *rb;
  193.     ngx_http_core_loc_conf_t  *clcf;

  194.     c = r->connection;
  195.     rb = r->request_body;

  196.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
  197.                    "http read client request body");

  198.     for ( ;; ) {
  199.         for ( ;; ) {
  200.             if (rb->buf->last == rb->buf->end) {

  201.                 /* pass buffer to request body filter chain */

  202.                 out.buf = rb->buf;
  203.                 out.next = NULL;

  204.                 rc = ngx_http_request_body_filter(r, &out);

  205.                 if (rc != NGX_OK) {
  206.                     return rc;
  207.                 }

  208.                 /* write to file */

  209.                 if (ngx_http_write_request_body(r) != NGX_OK) {
  210.                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
  211.                 }

  212.                 /* update chains */

  213.                 rc = ngx_http_request_body_filter(r, NULL);

  214.                 if (rc != NGX_OK) {
  215.                     return rc;
  216.                 }

  217.                 if (rb->busy != NULL) {
  218.                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
  219.                 }

  220.                 rb->buf->pos = rb->buf->start;
  221.                 rb->buf->last = rb->buf->start;
  222.             }

  223.             size = rb->buf->end - rb->buf->last;
  224.             rest = rb->rest - (rb->buf->last - rb->buf->pos);

  225.             if ((off_t) size > rest) {
  226.                 size = (size_t) rest;
  227.             }

  228.             n = c->recv(c, rb->buf->last, size);

  229.             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  230.                            "http client request body recv %z", n);

  231.             if (n == NGX_AGAIN) {
  232.                 break;
  233.             }

  234.             if (n == 0) {
  235.                 ngx_log_error(NGX_LOG_INFO, c->log, 0,
  236.                               "client prematurely closed connection");
  237.             }

  238.             if (n == 0 || n == NGX_ERROR) {
  239.                 c->error = 1;
  240.                 return NGX_HTTP_BAD_REQUEST;
  241.             }

  242.             rb->buf->last += n;
  243.             r->request_length += n;

  244.             if (n == rest) {
  245.                 /* pass buffer to request body filter chain */

  246.                 out.buf = rb->buf;
  247.                 out.next = NULL;

  248.                 rc = ngx_http_request_body_filter(r, &out);

  249.                 if (rc != NGX_OK) {
  250.                     return rc;
  251.                 }
  252.             }

  253.             if (rb->rest == 0) {
  254.                 break;
  255.             }

  256.             if (rb->buf->last < rb->buf->end) {
  257.                 break;
  258.             }
  259.         }

  260.         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
  261.                        "http client request body rest %O", rb->rest);

  262.         if (rb->rest == 0) {
  263.             break;
  264.         }

  265.         if (!c->read->ready) {
  266.             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
  267.             ngx_add_timer(c->read, clcf->client_body_timeout);

  268.             if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  269.                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
  270.             }

  271.             return NGX_AGAIN;
  272.         }
  273.     }

  274.     if (c->read->timer_set) {
  275.         ngx_del_timer(c->read);
  276.     }

  277.     if (rb->temp_file || r->request_body_in_file_only) {

  278.         /* save the last part */

  279.         if (ngx_http_write_request_body(r) != NGX_OK) {
  280.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  281.         }

  282.         if (rb->temp_file->file.offset != 0) {

  283.             cl = ngx_chain_get_free_buf(r->pool, &rb->free);
  284.             if (cl == NULL) {
  285.                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
  286.             }

  287.             b = cl->buf;

  288.             ngx_memzero(b, sizeof(ngx_buf_t));

  289.             b->in_file = 1;
  290.             b->file_last = rb->temp_file->file.offset;
  291.             b->file = &rb->temp_file->file;

  292.             rb->bufs = cl;

  293.         } else {
  294.             rb->bufs = NULL;
  295.         }
  296.     }

  297.     r->read_event_handler = ngx_http_block_reading;

  298.     rb->post_handler(r);

  299.     return NGX_OK;
  300. }


  301. static ngx_int_t
  302. ngx_http_write_request_body(ngx_http_request_t *r)
  303. {
  304.     ssize_t                    n;
  305.     ngx_chain_t               *cl;
  306.     ngx_temp_file_t           *tf;
  307.     ngx_http_request_body_t   *rb;
  308.     ngx_http_core_loc_conf_t  *clcf;

  309.     rb = r->request_body;

  310.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  311.                    "http write client request body, bufs %p", rb->bufs);

  312.     if (rb->temp_file == NULL) {
  313.         tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
  314.         if (tf == NULL) {
  315.             return NGX_ERROR;
  316.         }

  317.         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  318.         tf->file.fd = NGX_INVALID_FILE;
  319.         tf->file.log = r->connection->log;
  320.         tf->path = clcf->client_body_temp_path;
  321.         tf->pool = r->pool;
  322.         tf->warn = "a client request body is buffered to a temporary file";
  323.         tf->log_level = r->request_body_file_log_level;
  324.         tf->persistent = r->request_body_in_persistent_file;
  325.         tf->clean = r->request_body_in_clean_file;

  326.         if (r->request_body_file_group_access) {
  327.             tf->access = 0660;
  328.         }

  329.         rb->temp_file = tf;

  330.         if (rb->bufs == NULL) {
  331.             /* empty body with r->request_body_in_file_only */

  332.             if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
  333.                                      tf->persistent, tf->clean, tf->access)
  334.                 != NGX_OK)
  335.             {
  336.                 return NGX_ERROR;
  337.             }

  338.             return NGX_OK;
  339.         }
  340.     }

  341.     if (rb->bufs == NULL) {
  342.         return NGX_OK;
  343.     }

  344.     n = ngx_write_chain_to_temp_file(rb->temp_file, rb->bufs);

  345.     /* TODO: n == 0 or not complete and level event */

  346.     if (n == NGX_ERROR) {
  347.         return NGX_ERROR;
  348.     }

  349.     rb->temp_file->offset += n;

  350.     /* mark all buffers as written */

  351.     for (cl = rb->bufs; cl; cl = cl->next) {
  352.         cl->buf->pos = cl->buf->last;
  353.     }

  354.     rb->bufs = NULL;

  355.     return NGX_OK;
  356. }


  357. ngx_int_t
  358. ngx_http_discard_request_body(ngx_http_request_t *r)
  359. {
  360.     ssize_t       size;
  361.     ngx_int_t     rc;
  362.     ngx_event_t  *rev;

  363. #if (NGX_HTTP_SPDY)
  364.     if (r->spdy_stream && r == r->main) {
  365.         r->spdy_stream->skip_data = NGX_SPDY_DATA_DISCARD;
  366.         return NGX_OK;
  367.     }
  368. #endif

  369.     if (r != r->main || r->discard_body || r->request_body) {
  370.         return NGX_OK;
  371.     }

  372.     if (ngx_http_test_expect(r) != NGX_OK) {
  373.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  374.     }

  375.     rev = r->connection->read;

  376.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");

  377.     if (rev->timer_set) {
  378.         ngx_del_timer(rev);
  379.     }

  380.     if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
  381.         return NGX_OK;
  382.     }

  383.     size = r->header_in->last - r->header_in->pos;

  384.     if (size || r->headers_in.chunked) {
  385.         rc = ngx_http_discard_request_body_filter(r, r->header_in);

  386.         if (rc != NGX_OK) {
  387.             return rc;
  388.         }

  389.         if (r->headers_in.content_length_n == 0) {
  390.             return NGX_OK;
  391.         }
  392.     }

  393.     rc = ngx_http_read_discarded_request_body(r);

  394.     if (rc == NGX_OK) {
  395.         r->lingering_close = 0;
  396.         return NGX_OK;
  397.     }

  398.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  399.         return rc;
  400.     }

  401.     /* rc == NGX_AGAIN */

  402.     r->read_event_handler = ngx_http_discarded_request_body_handler;

  403.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  404.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  405.     }

  406.     r->count++;
  407.     r->discard_body = 1;

  408.     return NGX_OK;
  409. }


  410. void
  411. ngx_http_discarded_request_body_handler(ngx_http_request_t *r)
  412. {
  413.     ngx_int_t                  rc;
  414.     ngx_msec_t                 timer;
  415.     ngx_event_t               *rev;
  416.     ngx_connection_t          *c;
  417.     ngx_http_core_loc_conf_t  *clcf;

  418.     c = r->connection;
  419.     rev = c->read;

  420.     if (rev->timedout) {
  421.         c->timedout = 1;
  422.         c->error = 1;
  423.         ngx_http_finalize_request(r, NGX_ERROR);
  424.         return;
  425.     }

  426.     if (r->lingering_time) {
  427.         timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time();

  428.         if ((ngx_msec_int_t) timer <= 0) {
  429.             r->discard_body = 0;
  430.             r->lingering_close = 0;
  431.             ngx_http_finalize_request(r, NGX_ERROR);
  432.             return;
  433.         }

  434.     } else {
  435.         timer = 0;
  436.     }

  437.     rc = ngx_http_read_discarded_request_body(r);

  438.     if (rc == NGX_OK) {
  439.         r->discard_body = 0;
  440.         r->lingering_close = 0;
  441.         ngx_http_finalize_request(r, NGX_DONE);
  442.         return;
  443.     }

  444.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  445.         c->error = 1;
  446.         ngx_http_finalize_request(r, NGX_ERROR);
  447.         return;
  448.     }

  449.     /* rc == NGX_AGAIN */

  450.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  451.         c->error = 1;
  452.         ngx_http_finalize_request(r, NGX_ERROR);
  453.         return;
  454.     }

  455.     if (timer) {

  456.         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  457.         timer *= 1000;

  458.         if (timer > clcf->lingering_timeout) {
  459.             timer = clcf->lingering_timeout;
  460.         }

  461.         ngx_add_timer(rev, timer);
  462.     }
  463. }


  464. static ngx_int_t
  465. ngx_http_read_discarded_request_body(ngx_http_request_t *r)
  466. {
  467.     size_t     size;
  468.     ssize_t    n;
  469.     ngx_int_t  rc;
  470.     ngx_buf_t  b;
  471.     u_char     buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];

  472.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  473.                    "http read discarded body");

  474.     ngx_memzero(&b, sizeof(ngx_buf_t));

  475.     b.temporary = 1;

  476.     for ( ;; ) {
  477.         if (r->headers_in.content_length_n == 0) {
  478.             r->read_event_handler = ngx_http_block_reading;
  479.             return NGX_OK;
  480.         }

  481.         if (!r->connection->read->ready) {
  482.             return NGX_AGAIN;
  483.         }

  484.         size = (size_t) ngx_min(r->headers_in.content_length_n,
  485.                                 NGX_HTTP_DISCARD_BUFFER_SIZE);

  486.         n = r->connection->recv(r->connection, buffer, size);

  487.         if (n == NGX_ERROR) {
  488.             r->connection->error = 1;
  489.             return NGX_OK;
  490.         }

  491.         if (n == NGX_AGAIN) {
  492.             return NGX_AGAIN;
  493.         }

  494.         if (n == 0) {
  495.             return NGX_OK;
  496.         }

  497.         b.pos = buffer;
  498.         b.last = buffer + n;

  499.         rc = ngx_http_discard_request_body_filter(r, &b);

  500.         if (rc != NGX_OK) {
  501.             return rc;
  502.         }
  503.     }
  504. }


  505. static ngx_int_t
  506. ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
  507. {
  508.     size_t                    size;
  509.     ngx_int_t                 rc;
  510.     ngx_http_request_body_t  *rb;

  511.     if (r->headers_in.chunked) {

  512.         rb = r->request_body;

  513.         if (rb == NULL) {

  514.             rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
  515.             if (rb == NULL) {
  516.                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
  517.             }

  518.             rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
  519.             if (rb->chunked == NULL) {
  520.                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
  521.             }

  522.             r->request_body = rb;
  523.         }

  524.         for ( ;; ) {

  525.             rc = ngx_http_parse_chunked(r, b, rb->chunked);

  526.             if (rc == NGX_OK) {

  527.                 /* a chunk has been parsed successfully */

  528.                 size = b->last - b->pos;

  529.                 if ((off_t) size > rb->chunked->size) {
  530.                     b->pos += (size_t) rb->chunked->size;
  531.                     rb->chunked->size = 0;

  532.                 } else {
  533.                     rb->chunked->size -= size;
  534.                     b->pos = b->last;
  535.                 }

  536.                 continue;
  537.             }

  538.             if (rc == NGX_DONE) {

  539.                 /* a whole response has been parsed successfully */

  540.                 r->headers_in.content_length_n = 0;
  541.                 break;
  542.             }

  543.             if (rc == NGX_AGAIN) {

  544.                 /* set amount of data we want to see next time */

  545.                 r->headers_in.content_length_n = rb->chunked->length;
  546.                 break;
  547.             }

  548.             /* invalid */

  549.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  550.                           "client sent invalid chunked body");

  551.             return NGX_HTTP_BAD_REQUEST;
  552.         }

  553.     } else {
  554.         size = b->last - b->pos;

  555.         if ((off_t) size > r->headers_in.content_length_n) {
  556.             b->pos += (size_t) r->headers_in.content_length_n;
  557.             r->headers_in.content_length_n = 0;

  558.         } else {
  559.             b->pos = b->last;
  560.             r->headers_in.content_length_n -= size;
  561.         }
  562.     }

  563.     return NGX_OK;
  564. }


  565. static ngx_int_t
  566. ngx_http_test_expect(ngx_http_request_t *r)
  567. {
  568.     ngx_int_t   n;
  569.     ngx_str_t  *expect;

  570.     if (r->expect_tested
  571.         || r->headers_in.expect == NULL
  572.         || r->http_version < NGX_HTTP_VERSION_11)
  573.     {
  574.         return NGX_OK;
  575.     }

  576.     r->expect_tested = 1;

  577.     expect = &r->headers_in.expect->value;

  578.     if (expect->len != sizeof("100-continue") - 1
  579.         || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
  580.                            sizeof("100-continue") - 1)
  581.            != 0)
  582.     {
  583.         return NGX_OK;
  584.     }

  585.     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  586.                    "send 100 Continue");

  587.     n = r->connection->send(r->connection,
  588.                             (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
  589.                             sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);

  590.     if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
  591.         return NGX_OK;
  592.     }

  593.     /* we assume that such small packet should be send successfully */

  594.     return NGX_ERROR;
  595. }


  596. static ngx_int_t
  597. ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
  598. {
  599.     if (r->headers_in.chunked) {
  600.         return ngx_http_request_body_chunked_filter(r, in);

  601.     } else {
  602.         return ngx_http_request_body_length_filter(r, in);
  603.     }
  604. }


  605. static ngx_int_t
  606. ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
  607. {
  608.     size_t                     size;
  609.     ngx_int_t                  rc;
  610.     ngx_buf_t                 *b;
  611.     ngx_chain_t               *cl, *tl, *out, **ll;
  612.     ngx_http_request_body_t   *rb;

  613.     rb = r->request_body;

  614.     if (rb->rest == -1) {
  615.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  616.                        "http request body content length filter");

  617.         rb->rest = r->headers_in.content_length_n;
  618.     }

  619.     out = NULL;
  620.     ll = &out;

  621.     for (cl = in; cl; cl = cl->next) {

  622.         if (rb->rest == 0) {
  623.             break;
  624.         }

  625.         tl = ngx_chain_get_free_buf(r->pool, &rb->free);
  626.         if (tl == NULL) {
  627.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  628.         }

  629.         b = tl->buf;

  630.         ngx_memzero(b, sizeof(ngx_buf_t));

  631.         b->temporary = 1;
  632.         b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
  633.         b->start = cl->buf->pos;
  634.         b->pos = cl->buf->pos;
  635.         b->last = cl->buf->last;
  636.         b->end = cl->buf->end;

  637.         size = cl->buf->last - cl->buf->pos;

  638.         if ((off_t) size < rb->rest) {
  639.             cl->buf->pos = cl->buf->last;
  640.             rb->rest -= size;

  641.         } else {
  642.             cl->buf->pos += (size_t) rb->rest;
  643.             rb->rest = 0;
  644.             b->last = cl->buf->pos;
  645.             b->last_buf = 1;
  646.         }

  647.         *ll = tl;
  648.         ll = &tl->next;
  649.     }

  650.     rc = ngx_http_request_body_save_filter(r, out);

  651.     ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
  652.                             (ngx_buf_tag_t) &ngx_http_read_client_request_body);

  653.     return rc;
  654. }


  655. static ngx_int_t
  656. ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
  657. {
  658.     size_t                     size;
  659.     ngx_int_t                  rc;
  660.     ngx_buf_t                 *b;
  661.     ngx_chain_t               *cl, *out, *tl, **ll;
  662.     ngx_http_request_body_t   *rb;
  663.     ngx_http_core_loc_conf_t  *clcf;

  664.     rb = r->request_body;

  665.     if (rb->rest == -1) {

  666.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  667.                        "http request body chunked filter");

  668.         rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
  669.         if (rb->chunked == NULL) {
  670.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  671.         }

  672.         r->headers_in.content_length_n = 0;
  673.         rb->rest = 3;
  674.     }

  675.     out = NULL;
  676.     ll = &out;

  677.     for (cl = in; cl; cl = cl->next) {

  678.         for ( ;; ) {

  679.             ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  680.                            "http body chunked buf "
  681.                            "t:%d f:%d %p, pos %p, size: %z file: %O, size: %z",
  682.                            cl->buf->temporary, cl->buf->in_file,
  683.                            cl->buf->start, cl->buf->pos,
  684.                            cl->buf->last - cl->buf->pos,
  685.                            cl->buf->file_pos,
  686.                            cl->buf->file_last - cl->buf->file_pos);

  687.             rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked);

  688.             if (rc == NGX_OK) {

  689.                 /* a chunk has been parsed successfully */

  690.                 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  691.                 if (clcf->client_max_body_size
  692.                     && clcf->client_max_body_size
  693.                        - r->headers_in.content_length_n < rb->chunked->size)
  694.                 {
  695.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  696.                                   "client intended to send too large chunked "
  697.                                   "body: %O+%O bytes",
  698.                                   r->headers_in.content_length_n,
  699.                                   rb->chunked->size);

  700.                     r->lingering_close = 1;

  701.                     return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
  702.                 }

  703.                 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
  704.                 if (tl == NULL) {
  705.                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
  706.                 }

  707.                 b = tl->buf;

  708.                 ngx_memzero(b, sizeof(ngx_buf_t));

  709.                 b->temporary = 1;
  710.                 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
  711.                 b->start = cl->buf->pos;
  712.                 b->pos = cl->buf->pos;
  713.                 b->last = cl->buf->last;
  714.                 b->end = cl->buf->end;

  715.                 *ll = tl;
  716.                 ll = &tl->next;

  717.                 size = cl->buf->last - cl->buf->pos;

  718.                 if ((off_t) size > rb->chunked->size) {
  719.                     cl->buf->pos += (size_t) rb->chunked->size;
  720.                     r->headers_in.content_length_n += rb->chunked->size;
  721.                     rb->chunked->size = 0;

  722.                 } else {
  723.                     rb->chunked->size -= size;
  724.                     r->headers_in.content_length_n += size;
  725.                     cl->buf->pos = cl->buf->last;
  726.                 }

  727.                 b->last = cl->buf->pos;

  728.                 continue;
  729.             }

  730.             if (rc == NGX_DONE) {

  731.                 /* a whole response has been parsed successfully */

  732.                 rb->rest = 0;

  733.                 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
  734.                 if (tl == NULL) {
  735.                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
  736.                 }

  737.                 b = tl->buf;

  738.                 ngx_memzero(b, sizeof(ngx_buf_t));

  739.                 b->last_buf = 1;

  740.                 *ll = tl;
  741.                 ll = &tl->next;

  742.                 break;
  743.             }

  744.             if (rc == NGX_AGAIN) {

  745.                 /* set rb->rest, amount of data we want to see next time */

  746.                 rb->rest = rb->chunked->length;

  747.                 break;
  748.             }

  749.             /* invalid */

  750.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  751.                           "client sent invalid chunked body");

  752.             return NGX_HTTP_BAD_REQUEST;
  753.         }
  754.     }

  755.     rc = ngx_http_request_body_save_filter(r, out);

  756.     ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
  757.                             (ngx_buf_tag_t) &ngx_http_read_client_request_body);

  758.     return rc;
  759. }


  760. static ngx_int_t
  761. ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
  762. {
  763. #if (NGX_DEBUG)
  764.     ngx_chain_t               *cl;
  765. #endif
  766.     ngx_http_request_body_t   *rb;

  767.     rb = r->request_body;

  768. #if (NGX_DEBUG)

  769.     for (cl = rb->bufs; cl; cl = cl->next) {
  770.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  771.                        "http body old buf t:%d f:%d %p, pos %p, size: %z "
  772.                        "file: %O, size: %z",
  773.                        cl->buf->temporary, cl->buf->in_file,
  774.                        cl->buf->start, cl->buf->pos,
  775.                        cl->buf->last - cl->buf->pos,
  776.                        cl->buf->file_pos,
  777.                        cl->buf->file_last - cl->buf->file_pos);
  778.     }

  779.     for (cl = in; cl; cl = cl->next) {
  780.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  781.                        "http body new buf t:%d f:%d %p, pos %p, size: %z "
  782.                        "file: %O, size: %z",
  783.                        cl->buf->temporary, cl->buf->in_file,
  784.                        cl->buf->start, cl->buf->pos,
  785.                        cl->buf->last - cl->buf->pos,
  786.                        cl->buf->file_pos,
  787.                        cl->buf->file_last - cl->buf->file_pos);
  788.     }

  789. #endif

  790.     /* TODO: coalesce neighbouring buffers */

  791.     if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) {
  792.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  793.     }

  794.     return NGX_OK;
  795. }