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_test_expect(r) != NGX_OK) {
0050         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
0051         goto done;
0052     }
0053 
0054     rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
0055     if (rb == NULL) {
0056         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
0057         goto done;
0058     }
0059 
0060     /*
0061      * set by ngx_pcalloc():
0062      *
0063      *     rb->bufs = NULL;
0064      *     rb->buf = NULL;
0065      *     rb->free = NULL;
0066      *     rb->busy = NULL;
0067      *     rb->chunked = NULL;
0068      */
0069 
0070     rb->rest = -1;
0071     rb->post_handler = post_handler;
0072 
0073     r->request_body = rb;
0074 
0075     if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
0076         r->request_body_no_buffering = 0;
0077         post_handler(r);
0078         return NGX_OK;
0079     }
0080 
0081 #if (NGX_HTTP_V2)
0082     if (r->stream) {
0083         rc = ngx_http_v2_read_request_body(r);
0084         goto done;
0085     }
0086 #endif
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 #if (NGX_HTTP_V2)
0810         || r->stream != NULL
0811 #endif
0812        )
0813     {
0814         return NGX_OK;
0815     }
0816 
0817     r->expect_tested = 1;
0818 
0819     expect = &r->headers_in.expect->value;
0820 
0821     if (expect->len != sizeof("100-continue") - 1
0822         || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
0823                            sizeof("100-continue") - 1)
0824            != 0)
0825     {
0826         return NGX_OK;
0827     }
0828 
0829     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0830                    "send 100 Continue");
0831 
0832     n = r->connection->send(r->connection,
0833                             (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
0834                             sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);
0835 
0836     if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
0837         return NGX_OK;
0838     }
0839 
0840     /* we assume that such small packet should be send successfully */
0841 
0842     r->connection->error = 1;
0843 
0844     return NGX_ERROR;
0845 }
0846 
0847 
0848 static ngx_int_t
0849 ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
0850 {
0851     if (r->headers_in.chunked) {
0852         return ngx_http_request_body_chunked_filter(r, in);
0853 
0854     } else {
0855         return ngx_http_request_body_length_filter(r, in);
0856     }
0857 }
0858 
0859 
0860 static ngx_int_t
0861 ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
0862 {
0863     size_t                     size;
0864     ngx_int_t                  rc;
0865     ngx_buf_t                 *b;
0866     ngx_chain_t               *cl, *tl, *out, **ll;
0867     ngx_http_request_body_t   *rb;
0868 
0869     rb = r->request_body;
0870 
0871     if (rb->rest == -1) {
0872         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0873                        "http request body content length filter");
0874 
0875         rb->rest = r->headers_in.content_length_n;
0876     }
0877 
0878     out = NULL;
0879     ll = &out;
0880 
0881     for (cl = in; cl; cl = cl->next) {
0882 
0883         if (rb->rest == 0) {
0884             break;
0885         }
0886 
0887         tl = ngx_chain_get_free_buf(r->pool, &rb->free);
0888         if (tl == NULL) {
0889             return NGX_HTTP_INTERNAL_SERVER_ERROR;
0890         }
0891 
0892         b = tl->buf;
0893 
0894         ngx_memzero(b, sizeof(ngx_buf_t));
0895 
0896         b->temporary = 1;
0897         b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
0898         b->start = cl->buf->pos;
0899         b->pos = cl->buf->pos;
0900         b->last = cl->buf->last;
0901         b->end = cl->buf->end;
0902         b->flush = r->request_body_no_buffering;
0903 
0904         size = cl->buf->last - cl->buf->pos;
0905 
0906         if ((off_t) size < rb->rest) {
0907             cl->buf->pos = cl->buf->last;
0908             rb->rest -= size;
0909 
0910         } else {
0911             cl->buf->pos += (size_t) rb->rest;
0912             rb->rest = 0;
0913             b->last = cl->buf->pos;
0914             b->last_buf = 1;
0915         }
0916 
0917         *ll = tl;
0918         ll = &tl->next;
0919     }
0920 
0921     rc = ngx_http_top_request_body_filter(r, out);
0922 
0923     ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
0924                             (ngx_buf_tag_t) &ngx_http_read_client_request_body);
0925 
0926     return rc;
0927 }
0928 
0929 
0930 static ngx_int_t
0931 ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
0932 {
0933     size_t                     size;
0934     ngx_int_t                  rc;
0935     ngx_buf_t                 *b;
0936     ngx_chain_t               *cl, *out, *tl, **ll;
0937     ngx_http_request_body_t   *rb;
0938     ngx_http_core_loc_conf_t  *clcf;
0939 
0940     rb = r->request_body;
0941 
0942     if (rb->rest == -1) {
0943 
0944         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0945                        "http request body chunked filter");
0946 
0947         rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
0948         if (rb->chunked == NULL) {
0949             return NGX_HTTP_INTERNAL_SERVER_ERROR;
0950         }
0951 
0952         r->headers_in.content_length_n = 0;
0953         rb->rest = 3;
0954     }
0955 
0956     out = NULL;
0957     ll = &out;
0958 
0959     for (cl = in; cl; cl = cl->next) {
0960 
0961         for ( ;; ) {
0962 
0963             ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
0964                            "http body chunked buf "
0965                            "t:%d f:%d %p, pos %p, size: %z file: %O, size: %O",
0966                            cl->buf->temporary, cl->buf->in_file,
0967                            cl->buf->start, cl->buf->pos,
0968                            cl->buf->last - cl->buf->pos,
0969                            cl->buf->file_pos,
0970                            cl->buf->file_last - cl->buf->file_pos);
0971 
0972             rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked);
0973 
0974             if (rc == NGX_OK) {
0975 
0976                 /* a chunk has been parsed successfully */
0977 
0978                 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
0979 
0980                 if (clcf->client_max_body_size
0981                     && clcf->client_max_body_size
0982                        - r->headers_in.content_length_n < rb->chunked->size)
0983                 {
0984                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0985                                   "client intended to send too large chunked "
0986                                   "body: %O+%O bytes",
0987                                   r->headers_in.content_length_n,
0988                                   rb->chunked->size);
0989 
0990                     r->lingering_close = 1;
0991 
0992                     return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
0993                 }
0994 
0995                 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
0996                 if (tl == NULL) {
0997                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
0998                 }
0999 
1000                 b = tl->buf;
1001 
1002                 ngx_memzero(b, sizeof(ngx_buf_t));
1003 
1004                 b->temporary = 1;
1005                 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
1006                 b->start = cl->buf->pos;
1007                 b->pos = cl->buf->pos;
1008                 b->last = cl->buf->last;
1009                 b->end = cl->buf->end;
1010                 b->flush = r->request_body_no_buffering;
1011 
1012                 *ll = tl;
1013                 ll = &tl->next;
1014 
1015                 size = cl->buf->last - cl->buf->pos;
1016 
1017                 if ((off_t) size > rb->chunked->size) {
1018                     cl->buf->pos += (size_t) rb->chunked->size;
1019                     r->headers_in.content_length_n += rb->chunked->size;
1020                     rb->chunked->size = 0;
1021 
1022                 } else {
1023                     rb->chunked->size -= size;
1024                     r->headers_in.content_length_n += size;
1025                     cl->buf->pos = cl->buf->last;
1026                 }
1027 
1028                 b->last = cl->buf->pos;
1029 
1030                 continue;
1031             }
1032 
1033             if (rc == NGX_DONE) {
1034 
1035                 /* a whole response has been parsed successfully */
1036 
1037                 rb->rest = 0;
1038 
1039                 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
1040                 if (tl == NULL) {
1041                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
1042                 }
1043 
1044                 b = tl->buf;
1045 
1046                 ngx_memzero(b, sizeof(ngx_buf_t));
1047 
1048                 b->last_buf = 1;
1049 
1050                 *ll = tl;
1051                 ll = &tl->next;
1052 
1053                 break;
1054             }
1055 
1056             if (rc == NGX_AGAIN) {
1057 
1058                 /* set rb->rest, amount of data we want to see next time */
1059 
1060                 rb->rest = rb->chunked->length;
1061 
1062                 break;
1063             }
1064 
1065             /* invalid */
1066 
1067             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1068                           "client sent invalid chunked body");
1069 
1070             return NGX_HTTP_BAD_REQUEST;
1071         }
1072     }
1073 
1074     rc = ngx_http_top_request_body_filter(r, out);
1075 
1076     ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
1077                             (ngx_buf_tag_t) &ngx_http_read_client_request_body);
1078 
1079     return rc;
1080 }
1081 
1082 
1083 ngx_int_t
1084 ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
1085 {
1086     ngx_buf_t                 *b;
1087     ngx_chain_t               *cl;
1088     ngx_http_request_body_t   *rb;
1089 
1090     rb = r->request_body;
1091 
1092 #if (NGX_DEBUG)
1093 
1094 #if 0
1095     for (cl = rb->bufs; cl; cl = cl->next) {
1096         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1097                        "http body old buf t:%d f:%d %p, pos %p, size: %z "
1098                        "file: %O, size: %O",
1099                        cl->buf->temporary, cl->buf->in_file,
1100                        cl->buf->start, cl->buf->pos,
1101                        cl->buf->last - cl->buf->pos,
1102                        cl->buf->file_pos,
1103                        cl->buf->file_last - cl->buf->file_pos);
1104     }
1105 #endif
1106 
1107     for (cl = in; cl; cl = cl->next) {
1108         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1109                        "http body new buf t:%d f:%d %p, pos %p, size: %z "
1110                        "file: %O, size: %O",
1111                        cl->buf->temporary, cl->buf->in_file,
1112                        cl->buf->start, cl->buf->pos,
1113                        cl->buf->last - cl->buf->pos,
1114                        cl->buf->file_pos,
1115                        cl->buf->file_last - cl->buf->file_pos);
1116     }
1117 
1118 #endif
1119 
1120     /* TODO: coalesce neighbouring buffers */
1121 
1122     if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) {
1123         return NGX_HTTP_INTERNAL_SERVER_ERROR;
1124     }
1125 
1126     if (r->request_body_no_buffering) {
1127         return NGX_OK;
1128     }
1129 
1130     if (rb->rest > 0) {
1131 
1132         if (rb->buf && rb->buf->last == rb->buf->end
1133             && ngx_http_write_request_body(r) != NGX_OK)
1134         {
1135             return NGX_HTTP_INTERNAL_SERVER_ERROR;
1136         }
1137 
1138         return NGX_OK;
1139     }
1140 
1141     /* rb->rest == 0 */
1142 
1143     if (rb->temp_file || r->request_body_in_file_only) {
1144 
1145         if (ngx_http_write_request_body(r) != NGX_OK) {
1146             return NGX_HTTP_INTERNAL_SERVER_ERROR;
1147         }
1148 
1149         if (rb->temp_file->file.offset != 0) {
1150 
1151             cl = ngx_chain_get_free_buf(r->pool, &rb->free);
1152             if (cl == NULL) {
1153                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1154             }
1155 
1156             b = cl->buf;
1157 
1158             ngx_memzero(b, sizeof(ngx_buf_t));
1159 
1160             b->in_file = 1;
1161             b->file_last = rb->temp_file->file.offset;
1162             b->file = &rb->temp_file->file;
1163 
1164             rb->bufs = cl;
1165         }
1166     }
1167 
1168     return NGX_OK;
1169 }