src/http/ngx_http_request_body.c - nginx

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_copy_pipelined_header(ngx_http_request_t *r,
  11.     ngx_buf_t *buf);
  12. static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r);
  13. static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
  14. static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r,
  15.     ngx_buf_t *b);
  16. static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);

  17. static ngx_int_t ngx_http_request_body_filter(ngx_http_request_t *r,
  18.     ngx_chain_t *in);
  19. static ngx_int_t ngx_http_request_body_length_filter(ngx_http_request_t *r,
  20.     ngx_chain_t *in);
  21. static ngx_int_t ngx_http_request_body_chunked_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;
  32.     ngx_http_request_body_t   *rb;
  33.     ngx_http_core_loc_conf_t  *clcf;

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

  35.     if (r != r->main || r->request_body || r->discard_body) {
  36.         r->request_body_no_buffering = 0;
  37.         post_handler(r);
  38.         return NGX_OK;
  39.     }

  40.     if (ngx_http_test_expect(r) != NGX_OK) {
  41.         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  42.         goto done;
  43.     }

  44.     rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
  45.     if (rb == NULL) {
  46.         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  47.         goto done;
  48.     }

  49.     /*
  50.      * set by ngx_pcalloc():
  51.      *
  52.      *     rb->temp_file = NULL;
  53.      *     rb->bufs = NULL;
  54.      *     rb->buf = NULL;
  55.      *     rb->free = NULL;
  56.      *     rb->busy = NULL;
  57.      *     rb->chunked = NULL;
  58.      *     rb->received = 0;
  59.      *     rb->filter_need_buffering = 0;
  60.      *     rb->last_sent = 0;
  61.      *     rb->last_saved = 0;
  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.         r->request_body_no_buffering = 0;
  68.         post_handler(r);
  69.         return NGX_OK;
  70.     }

  71. #if (NGX_HTTP_V2)
  72.     if (r->stream) {
  73.         rc = ngx_http_v2_read_request_body(r);
  74.         goto done;
  75.     }
  76. #endif

  77. #if (NGX_HTTP_V3)
  78.     if (r->http_version == NGX_HTTP_VERSION_30) {
  79.         rc = ngx_http_v3_read_request_body(r);
  80.         goto done;
  81.     }
  82. #endif

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

  84.     if (preread) {

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

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

  88.         out.buf = r->header_in;
  89.         out.next = NULL;

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

  91.         if (rc != NGX_OK) {
  92.             goto done;
  93.         }

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

  95.         if (!r->headers_in.chunked
  96.             && rb->rest > 0
  97.             && rb->rest <= (off_t) (r->header_in->end - r->header_in->last))
  98.         {
  99.             /* the whole request body may be placed in r->header_in */

  100.             b = ngx_calloc_buf(r->pool);
  101.             if (b == NULL) {
  102.                 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  103.                 goto done;
  104.             }

  105.             b->temporary = 1;
  106.             b->start = r->header_in->pos;
  107.             b->pos = r->header_in->pos;
  108.             b->last = r->header_in->last;
  109.             b->end = r->header_in->end;

  110.             rb->buf = b;

  111.             r->read_event_handler = ngx_http_read_client_request_body_handler;
  112.             r->write_event_handler = ngx_http_request_empty_handler;

  113.             rc = ngx_http_do_read_client_request_body(r);
  114.             goto done;
  115.         }

  116.     } else {
  117.         /* set rb->rest */

  118.         rc = ngx_http_request_body_filter(r, NULL);

  119.         if (rc != NGX_OK) {
  120.             goto done;
  121.         }
  122.     }

  123.     if (rb->rest == 0 && rb->last_saved) {
  124.         /* the whole request body was pre-read */
  125.         r->request_body_no_buffering = 0;
  126.         post_handler(r);
  127.         return NGX_OK;
  128.     }

  129.     if (rb->rest < 0) {
  130.         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  131.                       "negative request body rest");
  132.         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  133.         goto done;
  134.     }

  135.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  136.     size = clcf->client_body_buffer_size;
  137.     size += size >> 2;

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

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

  141.         if (r->request_body_in_single_buf) {
  142.             size += preread;
  143.         }

  144.         if (size == 0) {
  145.             size++;
  146.         }

  147.     } else {
  148.         size = clcf->client_body_buffer_size;
  149.     }

  150.     rb->buf = ngx_create_temp_buf(r->pool, size);
  151.     if (rb->buf == NULL) {
  152.         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  153.         goto done;
  154.     }

  155.     r->read_event_handler = ngx_http_read_client_request_body_handler;
  156.     r->write_event_handler = ngx_http_request_empty_handler;

  157.     rc = ngx_http_do_read_client_request_body(r);

  158. done:

  159.     if (r->request_body_no_buffering
  160.         && (rc == NGX_OK || rc == NGX_AGAIN))
  161.     {
  162.         if (rc == NGX_OK) {
  163.             r->request_body_no_buffering = 0;

  164.         } else {
  165.             /* rc == NGX_AGAIN */
  166.             r->reading_body = 1;
  167.         }

  168.         r->read_event_handler = ngx_http_block_reading;
  169.         post_handler(r);
  170.     }

  171.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  172.         r->main->count--;
  173.     }

  174.     return rc;
  175. }


  176. ngx_int_t
  177. ngx_http_read_unbuffered_request_body(ngx_http_request_t *r)
  178. {
  179.     ngx_int_t  rc;

  180. #if (NGX_HTTP_V2)
  181.     if (r->stream) {
  182.         rc = ngx_http_v2_read_unbuffered_request_body(r);

  183.         if (rc == NGX_OK) {
  184.             r->reading_body = 0;
  185.         }

  186.         return rc;
  187.     }
  188. #endif

  189. #if (NGX_HTTP_V3)
  190.     if (r->http_version == NGX_HTTP_VERSION_30) {
  191.         rc = ngx_http_v3_read_unbuffered_request_body(r);

  192.         if (rc == NGX_OK) {
  193.             r->reading_body = 0;
  194.         }

  195.         return rc;
  196.     }
  197. #endif

  198.     if (r->connection->read->timedout) {
  199.         r->connection->timedout = 1;
  200.         return NGX_HTTP_REQUEST_TIME_OUT;
  201.     }

  202.     rc = ngx_http_do_read_client_request_body(r);

  203.     if (rc == NGX_OK) {
  204.         r->reading_body = 0;
  205.     }

  206.     return rc;
  207. }


  208. static void
  209. ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
  210. {
  211.     ngx_int_t  rc;

  212.     if (r->connection->read->timedout) {
  213.         r->connection->timedout = 1;
  214.         ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
  215.         return;
  216.     }

  217.     rc = ngx_http_do_read_client_request_body(r);

  218.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  219.         ngx_http_finalize_request(r, rc);
  220.     }
  221. }


  222. static ngx_int_t
  223. ngx_http_do_read_client_request_body(ngx_http_request_t *r)
  224. {
  225.     off_t                      rest;
  226.     size_t                     size;
  227.     ssize_t                    n;
  228.     ngx_int_t                  rc;
  229.     ngx_uint_t                 flush;
  230.     ngx_chain_t                out;
  231.     ngx_connection_t          *c;
  232.     ngx_http_request_body_t   *rb;
  233.     ngx_http_core_loc_conf_t  *clcf;

  234.     c = r->connection;
  235.     rb = r->request_body;
  236.     flush = 1;

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

  239.     for ( ;; ) {
  240.         for ( ;; ) {
  241.             if (rb->rest == 0) {
  242.                 break;
  243.             }

  244.             if (rb->buf->last == rb->buf->end) {

  245.                 /* update chains */

  246.                 rc = ngx_http_request_body_filter(r, NULL);

  247.                 if (rc != NGX_OK) {
  248.                     return rc;
  249.                 }

  250.                 if (rb->busy != NULL) {
  251.                     if (r->request_body_no_buffering) {
  252.                         if (c->read->timer_set) {
  253.                             ngx_del_timer(c->read);
  254.                         }

  255.                         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  256.                             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  257.                         }

  258.                         return NGX_AGAIN;
  259.                     }

  260.                     if (rb->filter_need_buffering) {
  261.                         clcf = ngx_http_get_module_loc_conf(r,
  262.                                                          ngx_http_core_module);
  263.                         ngx_add_timer(c->read, clcf->client_body_timeout);

  264.                         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  265.                             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  266.                         }

  267.                         return NGX_AGAIN;
  268.                     }

  269.                     ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  270.                                   "busy buffers after request body flush");

  271.                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
  272.                 }

  273.                 flush = 0;
  274.                 rb->buf->pos = rb->buf->start;
  275.                 rb->buf->last = rb->buf->start;
  276.             }

  277.             size = rb->buf->end - rb->buf->last;
  278.             rest = rb->rest - (rb->buf->last - rb->buf->pos);

  279.             if ((off_t) size > rest) {
  280.                 size = (size_t) rest;
  281.             }

  282.             if (size == 0) {
  283.                 break;
  284.             }

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

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

  288.             if (n == NGX_AGAIN) {
  289.                 break;
  290.             }

  291.             if (n == 0) {
  292.                 ngx_log_error(NGX_LOG_INFO, c->log, 0,
  293.                               "client prematurely closed connection");
  294.             }

  295.             if (n == 0 || n == NGX_ERROR) {
  296.                 c->error = 1;
  297.                 return NGX_HTTP_BAD_REQUEST;
  298.             }

  299.             rb->buf->last += n;
  300.             r->request_length += n;

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

  302.             flush = 0;
  303.             out.buf = rb->buf;
  304.             out.next = NULL;

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

  306.             if (rc != NGX_OK) {
  307.                 return rc;
  308.             }

  309.             if (rb->rest == 0) {
  310.                 break;
  311.             }

  312.             if (rb->buf->last < rb->buf->end) {
  313.                 break;
  314.             }
  315.         }

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

  318.         if (flush) {
  319.             rc = ngx_http_request_body_filter(r, NULL);

  320.             if (rc != NGX_OK) {
  321.                 return rc;
  322.             }
  323.         }

  324.         if (rb->rest == 0 && rb->last_saved) {
  325.             break;
  326.         }

  327.         if (!c->read->ready || rb->rest == 0) {

  328.             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
  329.             ngx_add_timer(c->read, clcf->client_body_timeout);

  330.             if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
  331.                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
  332.             }

  333.             return NGX_AGAIN;
  334.         }
  335.     }

  336.     if (ngx_http_copy_pipelined_header(r, rb->buf) != NGX_OK) {
  337.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  338.     }

  339.     if (c->read->timer_set) {
  340.         ngx_del_timer(c->read);
  341.     }

  342.     if (!r->request_body_no_buffering) {
  343.         r->read_event_handler = ngx_http_block_reading;
  344.         rb->post_handler(r);
  345.     }

  346.     return NGX_OK;
  347. }


  348. static ngx_int_t
  349. ngx_http_copy_pipelined_header(ngx_http_request_t *r, ngx_buf_t *buf)
  350. {
  351.     size_t                     n;
  352.     ngx_buf_t                 *b;
  353.     ngx_chain_t               *cl;
  354.     ngx_http_connection_t     *hc;
  355.     ngx_http_core_srv_conf_t  *cscf;

  356.     b = r->header_in;
  357.     n = buf->last - buf->pos;

  358.     if (buf == b || n == 0) {
  359.         return NGX_OK;
  360.     }

  361.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  362.                    "http body pipelined header: %uz", n);

  363.     /*
  364.      * if there is a pipelined request in the client body buffer,
  365.      * copy it to the r->header_in buffer if there is enough room,
  366.      * or allocate a large client header buffer
  367.      */

  368.     if (n > (size_t) (b->end - b->last)) {

  369.         hc = r->http_connection;

  370.         if (hc->free) {
  371.             cl = hc->free;
  372.             hc->free = cl->next;

  373.             b = cl->buf;

  374.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  375.                            "http large header free: %p %uz",
  376.                            b->pos, b->end - b->last);

  377.         } else {
  378.             cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);

  379.             b = ngx_create_temp_buf(r->connection->pool,
  380.                                     cscf->large_client_header_buffers.size);
  381.             if (b == NULL) {
  382.                 return NGX_ERROR;
  383.             }

  384.             cl = ngx_alloc_chain_link(r->connection->pool);
  385.             if (cl == NULL) {
  386.                 return NGX_ERROR;
  387.             }

  388.             cl->buf = b;

  389.             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  390.                            "http large header alloc: %p %uz",
  391.                            b->pos, b->end - b->last);
  392.         }

  393.         cl->next = hc->busy;
  394.         hc->busy = cl;
  395.         hc->nbusy++;

  396.         r->header_in = b;

  397.         if (n > (size_t) (b->end - b->last)) {
  398.             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  399.                           "too large pipelined header after reading body");
  400.             return NGX_ERROR;
  401.         }
  402.     }

  403.     ngx_memcpy(b->last, buf->pos, n);

  404.     b->last += n;
  405.     r->request_length -= n;

  406.     return NGX_OK;
  407. }


  408. static ngx_int_t
  409. ngx_http_write_request_body(ngx_http_request_t *r)
  410. {
  411.     ssize_t                    n;
  412.     ngx_chain_t               *cl, *ln;
  413.     ngx_temp_file_t           *tf;
  414.     ngx_http_request_body_t   *rb;
  415.     ngx_http_core_loc_conf_t  *clcf;

  416.     rb = r->request_body;

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

  419.     if (rb->temp_file == NULL) {
  420.         tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
  421.         if (tf == NULL) {
  422.             return NGX_ERROR;
  423.         }

  424.         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  425.         tf->file.fd = NGX_INVALID_FILE;
  426.         tf->file.log = r->connection->log;
  427.         tf->path = clcf->client_body_temp_path;
  428.         tf->pool = r->pool;
  429.         tf->warn = "a client request body is buffered to a temporary file";
  430.         tf->log_level = r->request_body_file_log_level;
  431.         tf->persistent = r->request_body_in_persistent_file;
  432.         tf->clean = r->request_body_in_clean_file;

  433.         if (r->request_body_file_group_access) {
  434.             tf->access = 0660;
  435.         }

  436.         rb->temp_file = tf;

  437.         if (rb->bufs == NULL
  438.             || (!ngx_buf_in_memory(rb->bufs->buf) && rb->bufs->buf->last_buf))
  439.         {
  440.             /* empty body with r->request_body_in_file_only */

  441.             if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
  442.                                      tf->persistent, tf->clean, tf->access)
  443.                 != NGX_OK)
  444.             {
  445.                 return NGX_ERROR;
  446.             }

  447.             return NGX_OK;
  448.         }
  449.     }

  450.     if (rb->bufs == NULL) {
  451.         return NGX_OK;
  452.     }

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

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

  455.     if (n == NGX_ERROR) {
  456.         return NGX_ERROR;
  457.     }

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

  459.     /* mark all buffers as written */

  460.     for (cl = rb->bufs; cl; /* void */) {

  461.         cl->buf->pos = cl->buf->last;

  462.         ln = cl;
  463.         cl = cl->next;
  464.         ngx_free_chain(r->pool, ln);
  465.     }

  466.     rb->bufs = NULL;

  467.     return NGX_OK;
  468. }


  469. ngx_int_t
  470. ngx_http_discard_request_body(ngx_http_request_t *r)
  471. {
  472.     ssize_t       size;
  473.     ngx_int_t     rc;
  474.     ngx_event_t  *rev;

  475.     if (r != r->main || r->discard_body || r->request_body) {
  476.         return NGX_OK;
  477.     }

  478. #if (NGX_HTTP_V2)
  479.     if (r->stream) {
  480.         r->stream->skip_data = 1;
  481.         return NGX_OK;
  482.     }
  483. #endif

  484. #if (NGX_HTTP_V3)
  485.     if (r->http_version == NGX_HTTP_VERSION_30) {
  486.         return NGX_OK;
  487.     }
  488. #endif

  489.     if (ngx_http_test_expect(r) != NGX_OK) {
  490.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  491.     }

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

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

  494.     if (rev->timer_set) {
  495.         ngx_del_timer(rev);
  496.     }

  497.     if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
  498.         return NGX_OK;
  499.     }

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

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

  503.         if (rc != NGX_OK) {
  504.             return rc;
  505.         }

  506.         if (r->headers_in.content_length_n == 0) {
  507.             return NGX_OK;
  508.         }
  509.     }

  510.     rc = ngx_http_read_discarded_request_body(r);

  511.     if (rc == NGX_OK) {
  512.         r->lingering_close = 0;
  513.         return NGX_OK;
  514.     }

  515.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  516.         return rc;
  517.     }

  518.     /* rc == NGX_AGAIN */

  519.     r->read_event_handler = ngx_http_discarded_request_body_handler;

  520.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  521.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  522.     }

  523.     r->count++;
  524.     r->discard_body = 1;

  525.     return NGX_OK;
  526. }


  527. void
  528. ngx_http_discarded_request_body_handler(ngx_http_request_t *r)
  529. {
  530.     ngx_int_t                  rc;
  531.     ngx_msec_t                 timer;
  532.     ngx_event_t               *rev;
  533.     ngx_connection_t          *c;
  534.     ngx_http_core_loc_conf_t  *clcf;

  535.     c = r->connection;
  536.     rev = c->read;

  537.     if (rev->timedout) {
  538.         c->timedout = 1;
  539.         c->error = 1;
  540.         ngx_http_finalize_request(r, NGX_ERROR);
  541.         return;
  542.     }

  543.     if (r->lingering_time) {
  544.         timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time();

  545.         if ((ngx_msec_int_t) timer <= 0) {
  546.             r->discard_body = 0;
  547.             r->lingering_close = 0;
  548.             ngx_http_finalize_request(r, NGX_ERROR);
  549.             return;
  550.         }

  551.     } else {
  552.         timer = 0;
  553.     }

  554.     rc = ngx_http_read_discarded_request_body(r);

  555.     if (rc == NGX_OK) {
  556.         r->discard_body = 0;
  557.         r->lingering_close = 0;
  558.         r->lingering_time = 0;
  559.         ngx_http_finalize_request(r, NGX_DONE);
  560.         return;
  561.     }

  562.     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
  563.         c->error = 1;
  564.         ngx_http_finalize_request(r, NGX_ERROR);
  565.         return;
  566.     }

  567.     /* rc == NGX_AGAIN */

  568.     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
  569.         c->error = 1;
  570.         ngx_http_finalize_request(r, NGX_ERROR);
  571.         return;
  572.     }

  573.     if (timer) {

  574.         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  575.         timer *= 1000;

  576.         if (timer > clcf->lingering_timeout) {
  577.             timer = clcf->lingering_timeout;
  578.         }

  579.         ngx_add_timer(rev, timer);
  580.     }
  581. }


  582. static ngx_int_t
  583. ngx_http_read_discarded_request_body(ngx_http_request_t *r)
  584. {
  585.     size_t     size;
  586.     ssize_t    n;
  587.     ngx_int_t  rc;
  588.     ngx_buf_t  b;
  589.     u_char     buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];

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

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

  593.     b.temporary = 1;

  594.     for ( ;; ) {
  595.         if (r->headers_in.content_length_n == 0) {
  596.             break;
  597.         }

  598.         if (!r->connection->read->ready) {
  599.             return NGX_AGAIN;
  600.         }

  601.         size = (size_t) ngx_min(r->headers_in.content_length_n,
  602.                                 NGX_HTTP_DISCARD_BUFFER_SIZE);

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

  604.         if (n == NGX_ERROR) {
  605.             r->connection->error = 1;
  606.             return NGX_OK;
  607.         }

  608.         if (n == NGX_AGAIN) {
  609.             return NGX_AGAIN;
  610.         }

  611.         if (n == 0) {
  612.             return NGX_OK;
  613.         }

  614.         b.pos = buffer;
  615.         b.last = buffer + n;

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

  617.         if (rc != NGX_OK) {
  618.             return rc;
  619.         }
  620.     }

  621.     if (ngx_http_copy_pipelined_header(r, &b) != NGX_OK) {
  622.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  623.     }

  624.     r->read_event_handler = ngx_http_block_reading;

  625.     return NGX_OK;
  626. }


  627. static ngx_int_t
  628. ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
  629. {
  630.     size_t                     size;
  631.     ngx_int_t                  rc;
  632.     ngx_http_request_body_t   *rb;
  633.     ngx_http_core_srv_conf_t  *cscf;

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

  635.         rb = r->request_body;

  636.         if (rb == NULL) {

  637.             rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
  638.             if (rb == NULL) {
  639.                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
  640.             }

  641.             rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
  642.             if (rb->chunked == NULL) {
  643.                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
  644.             }

  645.             r->request_body = rb;
  646.         }

  647.         for ( ;; ) {

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

  649.             if (rc == NGX_OK) {

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

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

  652.                 if ((off_t) size > rb->chunked->size) {
  653.                     b->pos += (size_t) rb->chunked->size;
  654.                     rb->chunked->size = 0;

  655.                 } else {
  656.                     rb->chunked->size -= size;
  657.                     b->pos = b->last;
  658.                 }

  659.                 continue;
  660.             }

  661.             if (rc == NGX_DONE) {

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

  663.                 r->headers_in.content_length_n = 0;
  664.                 break;
  665.             }

  666.             if (rc == NGX_AGAIN) {

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

  668.                 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);

  669.                 r->headers_in.content_length_n = ngx_max(rb->chunked->length,
  670.                                (off_t) cscf->large_client_header_buffers.size);
  671.                 break;
  672.             }

  673.             /* invalid */

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

  676.             return NGX_HTTP_BAD_REQUEST;
  677.         }

  678.     } else {
  679.         size = b->last - b->pos;

  680.         if ((off_t) size > r->headers_in.content_length_n) {
  681.             b->pos += (size_t) r->headers_in.content_length_n;
  682.             r->headers_in.content_length_n = 0;

  683.         } else {
  684.             b->pos = b->last;
  685.             r->headers_in.content_length_n -= size;
  686.         }
  687.     }

  688.     return NGX_OK;
  689. }


  690. static ngx_int_t
  691. ngx_http_test_expect(ngx_http_request_t *r)
  692. {
  693.     ngx_int_t   n;
  694.     ngx_str_t  *expect;

  695.     if (r->expect_tested
  696.         || r->headers_in.expect == NULL
  697.         || r->http_version < NGX_HTTP_VERSION_11
  698. #if (NGX_HTTP_V2)
  699.         || r->stream != NULL
  700. #endif
  701. #if (NGX_HTTP_V3)
  702.         || r->connection->quic != NULL
  703. #endif
  704.        )
  705.     {
  706.         return NGX_OK;
  707.     }

  708.     r->expect_tested = 1;

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

  710.     if (expect->len != sizeof("100-continue") - 1
  711.         || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
  712.                            sizeof("100-continue") - 1)
  713.            != 0)
  714.     {
  715.         return NGX_OK;
  716.     }

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

  719.     n = r->connection->send(r->connection,
  720.                             (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
  721.                             sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);

  722.     if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
  723.         return NGX_OK;
  724.     }

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

  726.     r->connection->error = 1;

  727.     return NGX_ERROR;
  728. }


  729. static ngx_int_t
  730. ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
  731. {
  732.     if (r->headers_in.chunked) {
  733.         return ngx_http_request_body_chunked_filter(r, in);

  734.     } else {
  735.         return ngx_http_request_body_length_filter(r, in);
  736.     }
  737. }


  738. static ngx_int_t
  739. ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
  740. {
  741.     size_t                     size;
  742.     ngx_int_t                  rc;
  743.     ngx_buf_t                 *b;
  744.     ngx_chain_t               *cl, *tl, *out, **ll;
  745.     ngx_http_request_body_t   *rb;

  746.     rb = r->request_body;

  747.     out = NULL;
  748.     ll = &out;

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

  752.         rb->rest = r->headers_in.content_length_n;

  753.         if (rb->rest == 0) {

  754.             tl = ngx_chain_get_free_buf(r->pool, &rb->free);
  755.             if (tl == NULL) {
  756.                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
  757.             }

  758.             b = tl->buf;

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

  760.             b->last_buf = 1;

  761.             *ll = tl;
  762.             ll = &tl->next;
  763.         }
  764.     }

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

  766.         if (rb->rest == 0) {
  767.             break;
  768.         }

  769.         tl = ngx_chain_get_free_buf(r->pool, &rb->free);
  770.         if (tl == NULL) {
  771.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  772.         }

  773.         b = tl->buf;

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

  775.         b->temporary = 1;
  776.         b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
  777.         b->start = cl->buf->pos;
  778.         b->pos = cl->buf->pos;
  779.         b->last = cl->buf->last;
  780.         b->end = cl->buf->end;
  781.         b->flush = r->request_body_no_buffering;

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

  783.         if ((off_t) size < rb->rest) {
  784.             cl->buf->pos = cl->buf->last;
  785.             rb->rest -= size;

  786.         } else {
  787.             cl->buf->pos += (size_t) rb->rest;
  788.             rb->rest = 0;
  789.             b->last = cl->buf->pos;
  790.             b->last_buf = 1;
  791.         }

  792.         *ll = tl;
  793.         ll = &tl->next;
  794.     }

  795.     rc = ngx_http_top_request_body_filter(r, out);

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

  798.     return rc;
  799. }


  800. static ngx_int_t
  801. ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
  802. {
  803.     size_t                     size;
  804.     ngx_int_t                  rc;
  805.     ngx_buf_t                 *b;
  806.     ngx_chain_t               *cl, *out, *tl, **ll;
  807.     ngx_http_request_body_t   *rb;
  808.     ngx_http_core_loc_conf_t  *clcf;
  809.     ngx_http_core_srv_conf_t  *cscf;

  810.     rb = r->request_body;

  811.     out = NULL;
  812.     ll = &out;

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

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

  816.         rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
  817.         if (rb->chunked == NULL) {
  818.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  819.         }

  820.         cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);

  821.         r->headers_in.content_length_n = 0;
  822.         rb->rest = cscf->large_client_header_buffers.size;
  823.     }

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

  825.         b = NULL;

  826.         for ( ;; ) {

  827.             ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  828.                            "http body chunked buf "
  829.                            "t:%d f:%d %p, pos %p, size: %z file: %O, size: %O",
  830.                            cl->buf->temporary, cl->buf->in_file,
  831.                            cl->buf->start, cl->buf->pos,
  832.                            cl->buf->last - cl->buf->pos,
  833.                            cl->buf->file_pos,
  834.                            cl->buf->file_last - cl->buf->file_pos);

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

  836.             if (rc == NGX_OK) {

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

  838.                 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  839.                 if (clcf->client_max_body_size
  840.                     && clcf->client_max_body_size
  841.                        - r->headers_in.content_length_n < rb->chunked->size)
  842.                 {
  843.                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  844.                                   "client intended to send too large chunked "
  845.                                   "body: %O+%O bytes",
  846.                                   r->headers_in.content_length_n,
  847.                                   rb->chunked->size);

  848.                     r->lingering_close = 1;

  849.                     return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
  850.                 }

  851.                 if (b
  852.                     && rb->chunked->size <= 128
  853.                     && cl->buf->last - cl->buf->pos >= rb->chunked->size)
  854.                 {
  855.                     r->headers_in.content_length_n += rb->chunked->size;

  856.                     if (rb->chunked->size < 8) {

  857.                         while (rb->chunked->size) {
  858.                             *b->last++ = *cl->buf->pos++;
  859.                             rb->chunked->size--;
  860.                         }

  861.                     } else {
  862.                         ngx_memmove(b->last, cl->buf->pos, rb->chunked->size);
  863.                         b->last += rb->chunked->size;
  864.                         cl->buf->pos += rb->chunked->size;
  865.                         rb->chunked->size = 0;
  866.                     }

  867.                     continue;
  868.                 }

  869.                 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
  870.                 if (tl == NULL) {
  871.                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
  872.                 }

  873.                 b = tl->buf;

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

  875.                 b->temporary = 1;
  876.                 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
  877.                 b->start = cl->buf->pos;
  878.                 b->pos = cl->buf->pos;
  879.                 b->last = cl->buf->last;
  880.                 b->end = cl->buf->end;
  881.                 b->flush = r->request_body_no_buffering;

  882.                 *ll = tl;
  883.                 ll = &tl->next;

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

  885.                 if ((off_t) size > rb->chunked->size) {
  886.                     cl->buf->pos += (size_t) rb->chunked->size;
  887.                     r->headers_in.content_length_n += rb->chunked->size;
  888.                     rb->chunked->size = 0;

  889.                 } else {
  890.                     rb->chunked->size -= size;
  891.                     r->headers_in.content_length_n += size;
  892.                     cl->buf->pos = cl->buf->last;
  893.                 }

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

  895.                 continue;
  896.             }

  897.             if (rc == NGX_DONE) {

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

  899.                 rb->rest = 0;

  900.                 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
  901.                 if (tl == NULL) {
  902.                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
  903.                 }

  904.                 b = tl->buf;

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

  906.                 b->last_buf = 1;

  907.                 *ll = tl;
  908.                 ll = &tl->next;

  909.                 break;
  910.             }

  911.             if (rc == NGX_AGAIN) {

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

  913.                 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);

  914.                 rb->rest = ngx_max(rb->chunked->length,
  915.                                (off_t) cscf->large_client_header_buffers.size);

  916.                 break;
  917.             }

  918.             /* invalid */

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

  921.             return NGX_HTTP_BAD_REQUEST;
  922.         }
  923.     }

  924.     rc = ngx_http_top_request_body_filter(r, out);

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

  927.     return rc;
  928. }


  929. ngx_int_t
  930. ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
  931. {
  932.     ngx_buf_t                 *b;
  933.     ngx_chain_t               *cl, *tl, **ll;
  934.     ngx_http_request_body_t   *rb;

  935.     rb = r->request_body;

  936.     ll = &rb->bufs;

  937.     for (cl = rb->bufs; cl; cl = cl->next) {

  938. #if 0
  939.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  940.                        "http body old buf t:%d f:%d %p, pos %p, size: %z "
  941.                        "file: %O, size: %O",
  942.                        cl->buf->temporary, cl->buf->in_file,
  943.                        cl->buf->start, cl->buf->pos,
  944.                        cl->buf->last - cl->buf->pos,
  945.                        cl->buf->file_pos,
  946.                        cl->buf->file_last - cl->buf->file_pos);
  947. #endif

  948.         ll = &cl->next;
  949.     }

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

  951.         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
  952.                        "http body new buf t:%d f:%d %p, pos %p, size: %z "
  953.                        "file: %O, size: %O",
  954.                        cl->buf->temporary, cl->buf->in_file,
  955.                        cl->buf->start, cl->buf->pos,
  956.                        cl->buf->last - cl->buf->pos,
  957.                        cl->buf->file_pos,
  958.                        cl->buf->file_last - cl->buf->file_pos);

  959.         if (cl->buf->last_buf) {

  960.             if (rb->last_saved) {
  961.                 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  962.                               "duplicate last buf in save filter");
  963.                 *ll = NULL;
  964.                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
  965.             }

  966.             rb->last_saved = 1;
  967.         }

  968.         tl = ngx_alloc_chain_link(r->pool);
  969.         if (tl == NULL) {
  970.             *ll = NULL;
  971.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  972.         }

  973.         tl->buf = cl->buf;
  974.         *ll = tl;
  975.         ll = &tl->next;
  976.     }

  977.     *ll = NULL;

  978.     if (r->request_body_no_buffering) {
  979.         return NGX_OK;
  980.     }

  981.     if (rb->rest > 0) {

  982.         if (rb->bufs && rb->buf && rb->buf->last == rb->buf->end
  983.             && ngx_http_write_request_body(r) != NGX_OK)
  984.         {
  985.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  986.         }

  987.         return NGX_OK;
  988.     }

  989.     if (!rb->last_saved) {
  990.         return NGX_OK;
  991.     }

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

  993.         if (rb->bufs && rb->bufs->buf->in_file) {
  994.             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
  995.                           "body already in file");
  996.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  997.         }

  998.         if (ngx_http_write_request_body(r) != NGX_OK) {
  999.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  1000.         }

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

  1002.             cl = ngx_chain_get_free_buf(r->pool, &rb->free);
  1003.             if (cl == NULL) {
  1004.                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
  1005.             }

  1006.             b = cl->buf;

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

  1008.             b->in_file = 1;
  1009.             b->file_last = rb->temp_file->file.offset;
  1010.             b->file = &rb->temp_file->file;

  1011.             rb->bufs = cl;
  1012.         }
  1013.     }

  1014.     return NGX_OK;
  1015. }