Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.19.2 ]​[ nginx-1.18.0 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
0014 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
0015 static ngx_int_t ngx_http_copy_pipelined_header(ngx_http_request_t *r,
0016     ngx_buf_t *buf);
0017 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r);
0018 static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
0019 static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r,
0020     ngx_buf_t *b);
0021 static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);
0022 
0023 static ngx_int_t ngx_http_request_body_filter(ngx_http_request_t *r,
0024     ngx_chain_t *in);
0025 static ngx_int_t ngx_http_request_body_length_filter(ngx_http_request_t *r,
0026     ngx_chain_t *in);
0027 static ngx_int_t ngx_http_request_body_chunked_filter(ngx_http_request_t *r,
0028     ngx_chain_t *in);
0029 
0030 
0031 ngx_int_t
0032 ngx_http_read_client_request_body(ngx_http_request_t *r,
0033     ngx_http_client_body_handler_pt post_handler)
0034 {
0035     size_t                     preread;
0036     ssize_t                    size;
0037     ngx_int_t                  rc;
0038     ngx_buf_t                 *b;
0039     ngx_chain_t                out;
0040     ngx_http_request_body_t   *rb;
0041     ngx_http_core_loc_conf_t  *clcf;
0042 
0043     r->main->count++;
0044 
0045     if (r != r->main || r->request_body || r->discard_body) {
0046         r->request_body_no_buffering = 0;
0047         post_handler(r);
0048         return NGX_OK;
0049     }
0050 
0051     if (ngx_http_test_expect(r) != NGX_OK) {
0052         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
0053         goto done;
0054     }
0055 
0056     rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
0057     if (rb == NULL) {
0058         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
0059         goto done;
0060     }
0061 
0062     /*
0063      * set by ngx_pcalloc():
0064      *
0065      *     rb->bufs = NULL;
0066      *     rb->buf = NULL;
0067      *     rb->free = NULL;
0068      *     rb->busy = NULL;
0069      *     rb->chunked = NULL;
0070      */
0071 
0072     rb->rest = -1;
0073     rb->post_handler = post_handler;
0074 
0075     r->request_body = rb;
0076 
0077     if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
0078         r->request_body_no_buffering = 0;
0079         post_handler(r);
0080         return NGX_OK;
0081     }
0082 
0083 #if (NGX_HTTP_V2)
0084     if (r->stream) {
0085         rc = ngx_http_v2_read_request_body(r);
0086         goto done;
0087     }
0088 #endif
0089 
0090     preread = r->header_in->last - r->header_in->pos;
0091 
0092     if (preread) {
0093 
0094         /* there is the pre-read part of the request body */
0095 
0096         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0097                        "http client request body preread %uz", preread);
0098 
0099         out.buf = r->header_in;
0100         out.next = NULL;
0101 
0102         rc = ngx_http_request_body_filter(r, &out);
0103 
0104         if (rc != NGX_OK) {
0105             goto done;
0106         }
0107 
0108         r->request_length += preread - (r->header_in->last - r->header_in->pos);
0109 
0110         if (!r->headers_in.chunked
0111             && rb->rest > 0
0112             && rb->rest <= (off_t) (r->header_in->end - r->header_in->last))
0113         {
0114             /* the whole request body may be placed in r->header_in */
0115 
0116             b = ngx_calloc_buf(r->pool);
0117             if (b == NULL) {
0118                 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
0119                 goto done;
0120             }
0121 
0122             b->temporary = 1;
0123             b->start = r->header_in->pos;
0124             b->pos = r->header_in->pos;
0125             b->last = r->header_in->last;
0126             b->end = r->header_in->end;
0127 
0128             rb->buf = b;
0129 
0130             r->read_event_handler = ngx_http_read_client_request_body_handler;
0131             r->write_event_handler = ngx_http_request_empty_handler;
0132 
0133             rc = ngx_http_do_read_client_request_body(r);
0134             goto done;
0135         }
0136 
0137     } else {
0138         /* set rb->rest */
0139 
0140         if (ngx_http_request_body_filter(r, NULL) != NGX_OK) {
0141             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
0142             goto done;
0143         }
0144     }
0145 
0146     if (rb->rest == 0) {
0147         /* the whole request body was pre-read */
0148         r->request_body_no_buffering = 0;
0149         post_handler(r);
0150         return NGX_OK;
0151     }
0152 
0153     if (rb->rest < 0) {
0154         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
0155                       "negative request body rest");
0156         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
0157         goto done;
0158     }
0159 
0160     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
0161 
0162     size = clcf->client_body_buffer_size;
0163     size += size >> 2;
0164 
0165     /* TODO: honor r->request_body_in_single_buf */
0166 
0167     if (!r->headers_in.chunked && rb->rest < size) {
0168         size = (ssize_t) rb->rest;
0169 
0170         if (r->request_body_in_single_buf) {
0171             size += preread;
0172         }
0173 
0174     } else {
0175         size = clcf->client_body_buffer_size;
0176     }
0177 
0178     rb->buf = ngx_create_temp_buf(r->pool, size);
0179     if (rb->buf == NULL) {
0180         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
0181         goto done;
0182     }
0183 
0184     r->read_event_handler = ngx_http_read_client_request_body_handler;
0185     r->write_event_handler = ngx_http_request_empty_handler;
0186 
0187     rc = ngx_http_do_read_client_request_body(r);
0188 
0189 done:
0190 
0191     if (r->request_body_no_buffering
0192         && (rc == NGX_OK || rc == NGX_AGAIN))
0193     {
0194         if (rc == NGX_OK) {
0195             r->request_body_no_buffering = 0;
0196 
0197         } else {
0198             /* rc == NGX_AGAIN */
0199             r->reading_body = 1;
0200         }
0201 
0202         r->read_event_handler = ngx_http_block_reading;
0203         post_handler(r);
0204     }
0205 
0206     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
0207         r->main->count--;
0208     }
0209 
0210     return rc;
0211 }
0212 
0213 
0214 ngx_int_t
0215 ngx_http_read_unbuffered_request_body(ngx_http_request_t *r)
0216 {
0217     ngx_int_t  rc;
0218 
0219 #if (NGX_HTTP_V2)
0220     if (r->stream) {
0221         rc = ngx_http_v2_read_unbuffered_request_body(r);
0222 
0223         if (rc == NGX_OK) {
0224             r->reading_body = 0;
0225         }
0226 
0227         return rc;
0228     }
0229 #endif
0230 
0231     if (r->connection->read->timedout) {
0232         r->connection->timedout = 1;
0233         return NGX_HTTP_REQUEST_TIME_OUT;
0234     }
0235 
0236     rc = ngx_http_do_read_client_request_body(r);
0237 
0238     if (rc == NGX_OK) {
0239         r->reading_body = 0;
0240     }
0241 
0242     return rc;
0243 }
0244 
0245 
0246 static void
0247 ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
0248 {
0249     ngx_int_t  rc;
0250 
0251     if (r->connection->read->timedout) {
0252         r->connection->timedout = 1;
0253         ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
0254         return;
0255     }
0256 
0257     rc = ngx_http_do_read_client_request_body(r);
0258 
0259     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
0260         ngx_http_finalize_request(r, rc);
0261     }
0262 }
0263 
0264 
0265 static ngx_int_t
0266 ngx_http_do_read_client_request_body(ngx_http_request_t *r)
0267 {
0268     off_t                      rest;
0269     size_t                     size;
0270     ssize_t                    n;
0271     ngx_int_t                  rc;
0272     ngx_chain_t                out;
0273     ngx_connection_t          *c;
0274     ngx_http_request_body_t   *rb;
0275     ngx_http_core_loc_conf_t  *clcf;
0276 
0277     c = r->connection;
0278     rb = r->request_body;
0279 
0280     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
0281                    "http read client request body");
0282 
0283     for ( ;; ) {
0284         for ( ;; ) {
0285             if (rb->buf->last == rb->buf->end) {
0286 
0287                 /* update chains */
0288 
0289                 rc = ngx_http_request_body_filter(r, NULL);
0290 
0291                 if (rc != NGX_OK) {
0292                     return rc;
0293                 }
0294 
0295                 if (rb->busy != NULL) {
0296                     if (r->request_body_no_buffering) {
0297                         if (c->read->timer_set) {
0298                             ngx_del_timer(c->read);
0299                         }
0300 
0301                         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
0302                             return NGX_HTTP_INTERNAL_SERVER_ERROR;
0303                         }
0304 
0305                         return NGX_AGAIN;
0306                     }
0307 
0308                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
0309                 }
0310 
0311                 rb->buf->pos = rb->buf->start;
0312                 rb->buf->last = rb->buf->start;
0313             }
0314 
0315             size = rb->buf->end - rb->buf->last;
0316             rest = rb->rest - (rb->buf->last - rb->buf->pos);
0317 
0318             if ((off_t) size > rest) {
0319                 size = (size_t) rest;
0320             }
0321 
0322             n = c->recv(c, rb->buf->last, size);
0323 
0324             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
0325                            "http client request body recv %z", n);
0326 
0327             if (n == NGX_AGAIN) {
0328                 break;
0329             }
0330 
0331             if (n == 0) {
0332                 ngx_log_error(NGX_LOG_INFO, c->log, 0,
0333                               "client prematurely closed connection");
0334             }
0335 
0336             if (n == 0 || n == NGX_ERROR) {
0337                 c->error = 1;
0338                 return NGX_HTTP_BAD_REQUEST;
0339             }
0340 
0341             rb->buf->last += n;
0342             r->request_length += n;
0343 
0344             /* pass buffer to request body filter chain */
0345 
0346             out.buf = rb->buf;
0347             out.next = NULL;
0348 
0349             rc = ngx_http_request_body_filter(r, &out);
0350 
0351             if (rc != NGX_OK) {
0352                 return rc;
0353             }
0354 
0355             if (rb->rest == 0) {
0356                 break;
0357             }
0358 
0359             if (rb->buf->last < rb->buf->end) {
0360                 break;
0361             }
0362         }
0363 
0364         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
0365                        "http client request body rest %O", rb->rest);
0366 
0367         if (rb->rest == 0) {
0368             break;
0369         }
0370 
0371         if (!c->read->ready) {
0372 
0373             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
0374             ngx_add_timer(c->read, clcf->client_body_timeout);
0375 
0376             if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
0377                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
0378             }
0379 
0380             return NGX_AGAIN;
0381         }
0382     }
0383 
0384     if (ngx_http_copy_pipelined_header(r, rb->buf) != NGX_OK) {
0385         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0386     }
0387 
0388     if (c->read->timer_set) {
0389         ngx_del_timer(c->read);
0390     }
0391 
0392     if (!r->request_body_no_buffering) {
0393         r->read_event_handler = ngx_http_block_reading;
0394         rb->post_handler(r);
0395     }
0396 
0397     return NGX_OK;
0398 }
0399 
0400 
0401 static ngx_int_t
0402 ngx_http_copy_pipelined_header(ngx_http_request_t *r, ngx_buf_t *buf)
0403 {
0404     size_t                     n;
0405     ngx_buf_t                 *b;
0406     ngx_chain_t               *cl;
0407     ngx_http_connection_t     *hc;
0408     ngx_http_core_srv_conf_t  *cscf;
0409 
0410     b = r->header_in;
0411     n = buf->last - buf->pos;
0412 
0413     if (buf == b || n == 0) {
0414         return NGX_OK;
0415     }
0416 
0417     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0418                    "http body pipelined header: %uz", n);
0419 
0420     /*
0421      * if there is a pipelined request in the client body buffer,
0422      * copy it to the r->header_in buffer if there is enough room,
0423      * or allocate a large client header buffer
0424      */
0425 
0426     if (n > (size_t) (b->end - b->last)) {
0427 
0428         hc = r->http_connection;
0429 
0430         if (hc->free) {
0431             cl = hc->free;
0432             hc->free = cl->next;
0433 
0434             b = cl->buf;
0435 
0436             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0437                            "http large header free: %p %uz",
0438                            b->pos, b->end - b->last);
0439 
0440         } else {
0441             cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
0442 
0443             b = ngx_create_temp_buf(r->connection->pool,
0444                                     cscf->large_client_header_buffers.size);
0445             if (b == NULL) {
0446                 return NGX_ERROR;
0447             }
0448 
0449             cl = ngx_alloc_chain_link(r->connection->pool);
0450             if (cl == NULL) {
0451                 return NGX_ERROR;
0452             }
0453 
0454             cl->buf = b;
0455 
0456             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0457                            "http large header alloc: %p %uz",
0458                            b->pos, b->end - b->last);
0459         }
0460 
0461         cl->next = hc->busy;
0462         hc->busy = cl;
0463         hc->nbusy++;
0464 
0465         r->header_in = b;
0466 
0467         if (n > (size_t) (b->end - b->last)) {
0468             ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
0469                           "too large pipelined header after reading body");
0470             return NGX_ERROR;
0471         }
0472     }
0473 
0474     ngx_memcpy(b->last, buf->pos, n);
0475 
0476     b->last += n;
0477     r->request_length -= n;
0478 
0479     return NGX_OK;
0480 }
0481 
0482 
0483 static ngx_int_t
0484 ngx_http_write_request_body(ngx_http_request_t *r)
0485 {
0486     ssize_t                    n;
0487     ngx_chain_t               *cl, *ln;
0488     ngx_temp_file_t           *tf;
0489     ngx_http_request_body_t   *rb;
0490     ngx_http_core_loc_conf_t  *clcf;
0491 
0492     rb = r->request_body;
0493 
0494     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0495                    "http write client request body, bufs %p", rb->bufs);
0496 
0497     if (rb->temp_file == NULL) {
0498         tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
0499         if (tf == NULL) {
0500             return NGX_ERROR;
0501         }
0502 
0503         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
0504 
0505         tf->file.fd = NGX_INVALID_FILE;
0506         tf->file.log = r->connection->log;
0507         tf->path = clcf->client_body_temp_path;
0508         tf->pool = r->pool;
0509         tf->warn = "a client request body is buffered to a temporary file";
0510         tf->log_level = r->request_body_file_log_level;
0511         tf->persistent = r->request_body_in_persistent_file;
0512         tf->clean = r->request_body_in_clean_file;
0513 
0514         if (r->request_body_file_group_access) {
0515             tf->access = 0660;
0516         }
0517 
0518         rb->temp_file = tf;
0519 
0520         if (rb->bufs == NULL) {
0521             /* empty body with r->request_body_in_file_only */
0522 
0523             if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
0524                                      tf->persistent, tf->clean, tf->access)
0525                 != NGX_OK)
0526             {
0527                 return NGX_ERROR;
0528             }
0529 
0530             return NGX_OK;
0531         }
0532     }
0533 
0534     if (rb->bufs == NULL) {
0535         return NGX_OK;
0536     }
0537 
0538     n = ngx_write_chain_to_temp_file(rb->temp_file, rb->bufs);
0539 
0540     /* TODO: n == 0 or not complete and level event */
0541 
0542     if (n == NGX_ERROR) {
0543         return NGX_ERROR;
0544     }
0545 
0546     rb->temp_file->offset += n;
0547 
0548     /* mark all buffers as written */
0549 
0550     for (cl = rb->bufs; cl; /* void */) {
0551 
0552         cl->buf->pos = cl->buf->last;
0553 
0554         ln = cl;
0555         cl = cl->next;
0556         ngx_free_chain(r->pool, ln);
0557     }
0558 
0559     rb->bufs = NULL;
0560 
0561     return NGX_OK;
0562 }
0563 
0564 
0565 ngx_int_t
0566 ngx_http_discard_request_body(ngx_http_request_t *r)
0567 {
0568     ssize_t       size;
0569     ngx_int_t     rc;
0570     ngx_event_t  *rev;
0571 
0572     if (r != r->main || r->discard_body || r->request_body) {
0573         return NGX_OK;
0574     }
0575 
0576 #if (NGX_HTTP_V2)
0577     if (r->stream) {
0578         r->stream->skip_data = 1;
0579         return NGX_OK;
0580     }
0581 #endif
0582 
0583     if (ngx_http_test_expect(r) != NGX_OK) {
0584         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0585     }
0586 
0587     rev = r->connection->read;
0588 
0589     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");
0590 
0591     if (rev->timer_set) {
0592         ngx_del_timer(rev);
0593     }
0594 
0595     if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
0596         return NGX_OK;
0597     }
0598 
0599     size = r->header_in->last - r->header_in->pos;
0600 
0601     if (size || r->headers_in.chunked) {
0602         rc = ngx_http_discard_request_body_filter(r, r->header_in);
0603 
0604         if (rc != NGX_OK) {
0605             return rc;
0606         }
0607 
0608         if (r->headers_in.content_length_n == 0) {
0609             return NGX_OK;
0610         }
0611     }
0612 
0613     rc = ngx_http_read_discarded_request_body(r);
0614 
0615     if (rc == NGX_OK) {
0616         r->lingering_close = 0;
0617         return NGX_OK;
0618     }
0619 
0620     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
0621         return rc;
0622     }
0623 
0624     /* rc == NGX_AGAIN */
0625 
0626     r->read_event_handler = ngx_http_discarded_request_body_handler;
0627 
0628     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
0629         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0630     }
0631 
0632     r->count++;
0633     r->discard_body = 1;
0634 
0635     return NGX_OK;
0636 }
0637 
0638 
0639 void
0640 ngx_http_discarded_request_body_handler(ngx_http_request_t *r)
0641 {
0642     ngx_int_t                  rc;
0643     ngx_msec_t                 timer;
0644     ngx_event_t               *rev;
0645     ngx_connection_t          *c;
0646     ngx_http_core_loc_conf_t  *clcf;
0647 
0648     c = r->connection;
0649     rev = c->read;
0650 
0651     if (rev->timedout) {
0652         c->timedout = 1;
0653         c->error = 1;
0654         ngx_http_finalize_request(r, NGX_ERROR);
0655         return;
0656     }
0657 
0658     if (r->lingering_time) {
0659         timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time();
0660 
0661         if ((ngx_msec_int_t) timer <= 0) {
0662             r->discard_body = 0;
0663             r->lingering_close = 0;
0664             ngx_http_finalize_request(r, NGX_ERROR);
0665             return;
0666         }
0667 
0668     } else {
0669         timer = 0;
0670     }
0671 
0672     rc = ngx_http_read_discarded_request_body(r);
0673 
0674     if (rc == NGX_OK) {
0675         r->discard_body = 0;
0676         r->lingering_close = 0;
0677         ngx_http_finalize_request(r, NGX_DONE);
0678         return;
0679     }
0680 
0681     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
0682         c->error = 1;
0683         ngx_http_finalize_request(r, NGX_ERROR);
0684         return;
0685     }
0686 
0687     /* rc == NGX_AGAIN */
0688 
0689     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
0690         c->error = 1;
0691         ngx_http_finalize_request(r, NGX_ERROR);
0692         return;
0693     }
0694 
0695     if (timer) {
0696 
0697         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
0698 
0699         timer *= 1000;
0700 
0701         if (timer > clcf->lingering_timeout) {
0702             timer = clcf->lingering_timeout;
0703         }
0704 
0705         ngx_add_timer(rev, timer);
0706     }
0707 }
0708 
0709 
0710 static ngx_int_t
0711 ngx_http_read_discarded_request_body(ngx_http_request_t *r)
0712 {
0713     size_t     size;
0714     ssize_t    n;
0715     ngx_int_t  rc;
0716     ngx_buf_t  b;
0717     u_char     buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];
0718 
0719     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0720                    "http read discarded body");
0721 
0722     ngx_memzero(&b, sizeof(ngx_buf_t));
0723 
0724     b.temporary = 1;
0725 
0726     for ( ;; ) {
0727         if (r->headers_in.content_length_n == 0) {
0728             break;
0729         }
0730 
0731         if (!r->connection->read->ready) {
0732             return NGX_AGAIN;
0733         }
0734 
0735         size = (size_t) ngx_min(r->headers_in.content_length_n,
0736                                 NGX_HTTP_DISCARD_BUFFER_SIZE);
0737 
0738         n = r->connection->recv(r->connection, buffer, size);
0739 
0740         if (n == NGX_ERROR) {
0741             r->connection->error = 1;
0742             return NGX_OK;
0743         }
0744 
0745         if (n == NGX_AGAIN) {
0746             return NGX_AGAIN;
0747         }
0748 
0749         if (n == 0) {
0750             return NGX_OK;
0751         }
0752 
0753         b.pos = buffer;
0754         b.last = buffer + n;
0755 
0756         rc = ngx_http_discard_request_body_filter(r, &b);
0757 
0758         if (rc != NGX_OK) {
0759             return rc;
0760         }
0761     }
0762 
0763     if (ngx_http_copy_pipelined_header(r, &b) != NGX_OK) {
0764         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0765     }
0766 
0767     r->read_event_handler = ngx_http_block_reading;
0768 
0769     return NGX_OK;
0770 }
0771 
0772 
0773 static ngx_int_t
0774 ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
0775 {
0776     size_t                     size;
0777     ngx_int_t                  rc;
0778     ngx_http_request_body_t   *rb;
0779     ngx_http_core_srv_conf_t  *cscf;
0780 
0781     if (r->headers_in.chunked) {
0782 
0783         rb = r->request_body;
0784 
0785         if (rb == NULL) {
0786 
0787             rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
0788             if (rb == NULL) {
0789                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
0790             }
0791 
0792             rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
0793             if (rb->chunked == NULL) {
0794                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
0795             }
0796 
0797             r->request_body = rb;
0798         }
0799 
0800         for ( ;; ) {
0801 
0802             rc = ngx_http_parse_chunked(r, b, rb->chunked);
0803 
0804             if (rc == NGX_OK) {
0805 
0806                 /* a chunk has been parsed successfully */
0807 
0808                 size = b->last - b->pos;
0809 
0810                 if ((off_t) size > rb->chunked->size) {
0811                     b->pos += (size_t) rb->chunked->size;
0812                     rb->chunked->size = 0;
0813 
0814                 } else {
0815                     rb->chunked->size -= size;
0816                     b->pos = b->last;
0817                 }
0818 
0819                 continue;
0820             }
0821 
0822             if (rc == NGX_DONE) {
0823 
0824                 /* a whole response has been parsed successfully */
0825 
0826                 r->headers_in.content_length_n = 0;
0827                 break;
0828             }
0829 
0830             if (rc == NGX_AGAIN) {
0831 
0832                 /* set amount of data we want to see next time */
0833 
0834                 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
0835 
0836                 r->headers_in.content_length_n = ngx_max(rb->chunked->length,
0837                                (off_t) cscf->large_client_header_buffers.size);
0838                 break;
0839             }
0840 
0841             /* invalid */
0842 
0843             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0844                           "client sent invalid chunked body");
0845 
0846             return NGX_HTTP_BAD_REQUEST;
0847         }
0848 
0849     } else {
0850         size = b->last - b->pos;
0851 
0852         if ((off_t) size > r->headers_in.content_length_n) {
0853             b->pos += (size_t) r->headers_in.content_length_n;
0854             r->headers_in.content_length_n = 0;
0855 
0856         } else {
0857             b->pos = b->last;
0858             r->headers_in.content_length_n -= size;
0859         }
0860     }
0861 
0862     return NGX_OK;
0863 }
0864 
0865 
0866 static ngx_int_t
0867 ngx_http_test_expect(ngx_http_request_t *r)
0868 {
0869     ngx_int_t   n;
0870     ngx_str_t  *expect;
0871 
0872     if (r->expect_tested
0873         || r->headers_in.expect == NULL
0874         || r->http_version < NGX_HTTP_VERSION_11
0875 #if (NGX_HTTP_V2)
0876         || r->stream != NULL
0877 #endif
0878        )
0879     {
0880         return NGX_OK;
0881     }
0882 
0883     r->expect_tested = 1;
0884 
0885     expect = &r->headers_in.expect->value;
0886 
0887     if (expect->len != sizeof("100-continue") - 1
0888         || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
0889                            sizeof("100-continue") - 1)
0890            != 0)
0891     {
0892         return NGX_OK;
0893     }
0894 
0895     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0896                    "send 100 Continue");
0897 
0898     n = r->connection->send(r->connection,
0899                             (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
0900                             sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);
0901 
0902     if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
0903         return NGX_OK;
0904     }
0905 
0906     /* we assume that such small packet should be send successfully */
0907 
0908     r->connection->error = 1;
0909 
0910     return NGX_ERROR;
0911 }
0912 
0913 
0914 static ngx_int_t
0915 ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
0916 {
0917     if (r->headers_in.chunked) {
0918         return ngx_http_request_body_chunked_filter(r, in);
0919 
0920     } else {
0921         return ngx_http_request_body_length_filter(r, in);
0922     }
0923 }
0924 
0925 
0926 static ngx_int_t
0927 ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
0928 {
0929     size_t                     size;
0930     ngx_int_t                  rc;
0931     ngx_buf_t                 *b;
0932     ngx_chain_t               *cl, *tl, *out, **ll;
0933     ngx_http_request_body_t   *rb;
0934 
0935     rb = r->request_body;
0936 
0937     if (rb->rest == -1) {
0938         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0939                        "http request body content length filter");
0940 
0941         rb->rest = r->headers_in.content_length_n;
0942     }
0943 
0944     out = NULL;
0945     ll = &out;
0946 
0947     for (cl = in; cl; cl = cl->next) {
0948 
0949         if (rb->rest == 0) {
0950             break;
0951         }
0952 
0953         tl = ngx_chain_get_free_buf(r->pool, &rb->free);
0954         if (tl == NULL) {
0955             return NGX_HTTP_INTERNAL_SERVER_ERROR;
0956         }
0957 
0958         b = tl->buf;
0959 
0960         ngx_memzero(b, sizeof(ngx_buf_t));
0961 
0962         b->temporary = 1;
0963         b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
0964         b->start = cl->buf->pos;
0965         b->pos = cl->buf->pos;
0966         b->last = cl->buf->last;
0967         b->end = cl->buf->end;
0968         b->flush = r->request_body_no_buffering;
0969 
0970         size = cl->buf->last - cl->buf->pos;
0971 
0972         if ((off_t) size < rb->rest) {
0973             cl->buf->pos = cl->buf->last;
0974             rb->rest -= size;
0975 
0976         } else {
0977             cl->buf->pos += (size_t) rb->rest;
0978             rb->rest = 0;
0979             b->last = cl->buf->pos;
0980             b->last_buf = 1;
0981         }
0982 
0983         *ll = tl;
0984         ll = &tl->next;
0985     }
0986 
0987     rc = ngx_http_top_request_body_filter(r, out);
0988 
0989     ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
0990                             (ngx_buf_tag_t) &ngx_http_read_client_request_body);
0991 
0992     return rc;
0993 }
0994 
0995 
0996 static ngx_int_t
0997 ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
0998 {
0999     size_t                     size;
1000     ngx_int_t                  rc;
1001     ngx_buf_t                 *b;
1002     ngx_chain_t               *cl, *out, *tl, **ll;
1003     ngx_http_request_body_t   *rb;
1004     ngx_http_core_loc_conf_t  *clcf;
1005     ngx_http_core_srv_conf_t  *cscf;
1006 
1007     rb = r->request_body;
1008 
1009     if (rb->rest == -1) {
1010 
1011         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1012                        "http request body chunked filter");
1013 
1014         rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
1015         if (rb->chunked == NULL) {
1016             return NGX_HTTP_INTERNAL_SERVER_ERROR;
1017         }
1018 
1019         cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1020 
1021         r->headers_in.content_length_n = 0;
1022         rb->rest = cscf->large_client_header_buffers.size;
1023     }
1024 
1025     out = NULL;
1026     ll = &out;
1027 
1028     for (cl = in; cl; cl = cl->next) {
1029 
1030         b = NULL;
1031 
1032         for ( ;; ) {
1033 
1034             ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1035                            "http body chunked buf "
1036                            "t:%d f:%d %p, pos %p, size: %z file: %O, size: %O",
1037                            cl->buf->temporary, cl->buf->in_file,
1038                            cl->buf->start, cl->buf->pos,
1039                            cl->buf->last - cl->buf->pos,
1040                            cl->buf->file_pos,
1041                            cl->buf->file_last - cl->buf->file_pos);
1042 
1043             rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked);
1044 
1045             if (rc == NGX_OK) {
1046 
1047                 /* a chunk has been parsed successfully */
1048 
1049                 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1050 
1051                 if (clcf->client_max_body_size
1052                     && clcf->client_max_body_size
1053                        - r->headers_in.content_length_n < rb->chunked->size)
1054                 {
1055                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1056                                   "client intended to send too large chunked "
1057                                   "body: %O+%O bytes",
1058                                   r->headers_in.content_length_n,
1059                                   rb->chunked->size);
1060 
1061                     r->lingering_close = 1;
1062 
1063                     return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
1064                 }
1065 
1066                 if (b
1067                     && rb->chunked->size <= 128
1068                     && cl->buf->last - cl->buf->pos >= rb->chunked->size)
1069                 {
1070                     r->headers_in.content_length_n += rb->chunked->size;
1071 
1072                     if (rb->chunked->size < 8) {
1073 
1074                         while (rb->chunked->size) {
1075                             *b->last++ = *cl->buf->pos++;
1076                             rb->chunked->size--;
1077                         }
1078 
1079                     } else {
1080                         ngx_memmove(b->last, cl->buf->pos, rb->chunked->size);
1081                         b->last += rb->chunked->size;
1082                         cl->buf->pos += rb->chunked->size;
1083                         rb->chunked->size = 0;
1084                     }
1085 
1086                     continue;
1087                 }
1088 
1089                 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
1090                 if (tl == NULL) {
1091                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
1092                 }
1093 
1094                 b = tl->buf;
1095 
1096                 ngx_memzero(b, sizeof(ngx_buf_t));
1097 
1098                 b->temporary = 1;
1099                 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
1100                 b->start = cl->buf->pos;
1101                 b->pos = cl->buf->pos;
1102                 b->last = cl->buf->last;
1103                 b->end = cl->buf->end;
1104                 b->flush = r->request_body_no_buffering;
1105 
1106                 *ll = tl;
1107                 ll = &tl->next;
1108 
1109                 size = cl->buf->last - cl->buf->pos;
1110 
1111                 if ((off_t) size > rb->chunked->size) {
1112                     cl->buf->pos += (size_t) rb->chunked->size;
1113                     r->headers_in.content_length_n += rb->chunked->size;
1114                     rb->chunked->size = 0;
1115 
1116                 } else {
1117                     rb->chunked->size -= size;
1118                     r->headers_in.content_length_n += size;
1119                     cl->buf->pos = cl->buf->last;
1120                 }
1121 
1122                 b->last = cl->buf->pos;
1123 
1124                 continue;
1125             }
1126 
1127             if (rc == NGX_DONE) {
1128 
1129                 /* a whole response has been parsed successfully */
1130 
1131                 rb->rest = 0;
1132 
1133                 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
1134                 if (tl == NULL) {
1135                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
1136                 }
1137 
1138                 b = tl->buf;
1139 
1140                 ngx_memzero(b, sizeof(ngx_buf_t));
1141 
1142                 b->last_buf = 1;
1143 
1144                 *ll = tl;
1145                 ll = &tl->next;
1146 
1147                 break;
1148             }
1149 
1150             if (rc == NGX_AGAIN) {
1151 
1152                 /* set rb->rest, amount of data we want to see next time */
1153 
1154                 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1155 
1156                 rb->rest = ngx_max(rb->chunked->length,
1157                                (off_t) cscf->large_client_header_buffers.size);
1158 
1159                 break;
1160             }
1161 
1162             /* invalid */
1163 
1164             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1165                           "client sent invalid chunked body");
1166 
1167             return NGX_HTTP_BAD_REQUEST;
1168         }
1169     }
1170 
1171     rc = ngx_http_top_request_body_filter(r, out);
1172 
1173     ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
1174                             (ngx_buf_tag_t) &ngx_http_read_client_request_body);
1175 
1176     return rc;
1177 }
1178 
1179 
1180 ngx_int_t
1181 ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
1182 {
1183     ngx_buf_t                 *b;
1184     ngx_chain_t               *cl;
1185     ngx_http_request_body_t   *rb;
1186 
1187     rb = r->request_body;
1188 
1189 #if (NGX_DEBUG)
1190 
1191 #if 0
1192     for (cl = rb->bufs; cl; cl = cl->next) {
1193         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1194                        "http body old buf t:%d f:%d %p, pos %p, size: %z "
1195                        "file: %O, size: %O",
1196                        cl->buf->temporary, cl->buf->in_file,
1197                        cl->buf->start, cl->buf->pos,
1198                        cl->buf->last - cl->buf->pos,
1199                        cl->buf->file_pos,
1200                        cl->buf->file_last - cl->buf->file_pos);
1201     }
1202 #endif
1203 
1204     for (cl = in; cl; cl = cl->next) {
1205         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1206                        "http body new buf t:%d f:%d %p, pos %p, size: %z "
1207                        "file: %O, size: %O",
1208                        cl->buf->temporary, cl->buf->in_file,
1209                        cl->buf->start, cl->buf->pos,
1210                        cl->buf->last - cl->buf->pos,
1211                        cl->buf->file_pos,
1212                        cl->buf->file_last - cl->buf->file_pos);
1213     }
1214 
1215 #endif
1216 
1217     /* TODO: coalesce neighbouring buffers */
1218 
1219     if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) {
1220         return NGX_HTTP_INTERNAL_SERVER_ERROR;
1221     }
1222 
1223     if (r->request_body_no_buffering) {
1224         return NGX_OK;
1225     }
1226 
1227     if (rb->rest > 0) {
1228 
1229         if (rb->buf && rb->buf->last == rb->buf->end
1230             && ngx_http_write_request_body(r) != NGX_OK)
1231         {
1232             return NGX_HTTP_INTERNAL_SERVER_ERROR;
1233         }
1234 
1235         return NGX_OK;
1236     }
1237 
1238     /* rb->rest == 0 */
1239 
1240     if (rb->temp_file || r->request_body_in_file_only) {
1241 
1242         if (ngx_http_write_request_body(r) != NGX_OK) {
1243             return NGX_HTTP_INTERNAL_SERVER_ERROR;
1244         }
1245 
1246         if (rb->temp_file->file.offset != 0) {
1247 
1248             cl = ngx_chain_get_free_buf(r->pool, &rb->free);
1249             if (cl == NULL) {
1250                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1251             }
1252 
1253             b = cl->buf;
1254 
1255             ngx_memzero(b, sizeof(ngx_buf_t));
1256 
1257             b->in_file = 1;
1258             b->file_last = rb->temp_file->file.offset;
1259             b->file = &rb->temp_file->file;
1260 
1261             rb->bufs = cl;
1262         }
1263     }
1264 
1265     return NGX_OK;
1266 }