Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

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