Annotation of embedaddon/nginx/src/http/ngx_http_request_body.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Igor Sysoev
                      4:  * Copyright (C) Nginx, Inc.
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: #include <ngx_http.h>
                     11: 
                     12: 
                     13: static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
                     14: static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
                     15: static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r);
                     16: static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
                     17: static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r,
                     18:     ngx_buf_t *b);
                     19: static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);
                     20: 
                     21: static ngx_int_t ngx_http_request_body_filter(ngx_http_request_t *r,
                     22:     ngx_chain_t *in);
                     23: static ngx_int_t ngx_http_request_body_length_filter(ngx_http_request_t *r,
                     24:     ngx_chain_t *in);
                     25: static ngx_int_t ngx_http_request_body_chunked_filter(ngx_http_request_t *r,
                     26:     ngx_chain_t *in);
                     27: static ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r,
                     28:     ngx_chain_t *in);
                     29: 
                     30: 
                     31: ngx_int_t
                     32: ngx_http_read_client_request_body(ngx_http_request_t *r,
                     33:     ngx_http_client_body_handler_pt post_handler)
                     34: {
                     35:     size_t                     preread;
                     36:     ssize_t                    size;
                     37:     ngx_int_t                  rc;
                     38:     ngx_buf_t                 *b;
                     39:     ngx_chain_t                out, *cl;
                     40:     ngx_http_request_body_t   *rb;
                     41:     ngx_http_core_loc_conf_t  *clcf;
                     42: 
                     43:     r->main->count++;
                     44: 
                     45: #if (NGX_HTTP_SPDY)
                     46:     if (r->spdy_stream) {
                     47:         rc = ngx_http_spdy_read_request_body(r, post_handler);
                     48:         goto done;
                     49:     }
                     50: #endif
                     51: 
                     52:     if (r != r->main || r->request_body || r->discard_body) {
                     53:         post_handler(r);
                     54:         return NGX_OK;
                     55:     }
                     56: 
                     57:     if (ngx_http_test_expect(r) != NGX_OK) {
                     58:         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                     59:         goto done;
                     60:     }
                     61: 
                     62:     rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
                     63:     if (rb == NULL) {
                     64:         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                     65:         goto done;
                     66:     }
                     67: 
                     68:     /*
                     69:      * set by ngx_pcalloc():
                     70:      *
                     71:      *     rb->bufs = NULL;
                     72:      *     rb->buf = NULL;
                     73:      *     rb->free = NULL;
                     74:      *     rb->busy = NULL;
                     75:      *     rb->chunked = NULL;
                     76:      */
                     77: 
                     78:     rb->rest = -1;
                     79:     rb->post_handler = post_handler;
                     80: 
                     81:     r->request_body = rb;
                     82: 
                     83:     if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
                     84:         post_handler(r);
                     85:         return NGX_OK;
                     86:     }
                     87: 
                     88:     preread = r->header_in->last - r->header_in->pos;
                     89: 
                     90:     if (preread) {
                     91: 
                     92:         /* there is the pre-read part of the request body */
                     93: 
                     94:         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                     95:                        "http client request body preread %uz", preread);
                     96: 
                     97:         out.buf = r->header_in;
                     98:         out.next = NULL;
                     99: 
                    100:         rc = ngx_http_request_body_filter(r, &out);
                    101: 
                    102:         if (rc != NGX_OK) {
                    103:             goto done;
                    104:         }
                    105: 
                    106:         r->request_length += preread - (r->header_in->last - r->header_in->pos);
                    107: 
                    108:         if (!r->headers_in.chunked
                    109:             && rb->rest > 0
                    110:             && rb->rest <= (off_t) (r->header_in->end - r->header_in->last))
                    111:         {
                    112:             /* the whole request body may be placed in r->header_in */
                    113: 
                    114:             b = ngx_calloc_buf(r->pool);
                    115:             if (b == NULL) {
                    116:                 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                    117:                 goto done;
                    118:             }
                    119: 
                    120:             b->temporary = 1;
                    121:             b->start = r->header_in->pos;
                    122:             b->pos = r->header_in->pos;
                    123:             b->last = r->header_in->last;
                    124:             b->end = r->header_in->end;
                    125: 
                    126:             rb->buf = b;
                    127: 
                    128:             r->read_event_handler = ngx_http_read_client_request_body_handler;
                    129:             r->write_event_handler = ngx_http_request_empty_handler;
                    130: 
                    131:             rc = ngx_http_do_read_client_request_body(r);
                    132:             goto done;
                    133:         }
                    134: 
                    135:     } else {
                    136:         /* set rb->rest */
                    137: 
                    138:         if (ngx_http_request_body_filter(r, NULL) != NGX_OK) {
                    139:             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                    140:             goto done;
                    141:         }
                    142:     }
                    143: 
                    144:     if (rb->rest == 0) {
                    145:         /* the whole request body was pre-read */
                    146: 
                    147:         if (r->request_body_in_file_only) {
                    148:             if (ngx_http_write_request_body(r) != NGX_OK) {
                    149:                 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                    150:                 goto done;
                    151:             }
                    152: 
                    153:             cl = ngx_chain_get_free_buf(r->pool, &rb->free);
                    154:             if (cl == NULL) {
                    155:                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    156:             }
                    157: 
                    158:             b = cl->buf;
                    159: 
                    160:             ngx_memzero(b, sizeof(ngx_buf_t));
                    161: 
                    162:             b->in_file = 1;
                    163:             b->file_last = rb->temp_file->file.offset;
                    164:             b->file = &rb->temp_file->file;
                    165: 
                    166:             rb->bufs = cl;
                    167:         }
                    168: 
                    169:         post_handler(r);
                    170: 
                    171:         return NGX_OK;
                    172:     }
                    173: 
                    174:     if (rb->rest < 0) {
                    175:         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                    176:                       "negative request body rest");
                    177:         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                    178:         goto done;
                    179:     }
                    180: 
                    181:     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
                    182: 
                    183:     size = clcf->client_body_buffer_size;
                    184:     size += size >> 2;
                    185: 
                    186:     /* TODO: honor r->request_body_in_single_buf */
                    187: 
                    188:     if (!r->headers_in.chunked && rb->rest < size) {
                    189:         size = (ssize_t) rb->rest;
                    190: 
                    191:         if (r->request_body_in_single_buf) {
                    192:             size += preread;
                    193:         }
                    194: 
                    195:     } else {
                    196:         size = clcf->client_body_buffer_size;
                    197:     }
                    198: 
                    199:     rb->buf = ngx_create_temp_buf(r->pool, size);
                    200:     if (rb->buf == NULL) {
                    201:         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                    202:         goto done;
                    203:     }
                    204: 
                    205:     r->read_event_handler = ngx_http_read_client_request_body_handler;
                    206:     r->write_event_handler = ngx_http_request_empty_handler;
                    207: 
                    208:     rc = ngx_http_do_read_client_request_body(r);
                    209: 
                    210: done:
                    211: 
                    212:     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
                    213:         r->main->count--;
                    214:     }
                    215: 
                    216:     return rc;
                    217: }
                    218: 
                    219: 
                    220: static void
                    221: ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
                    222: {
                    223:     ngx_int_t  rc;
                    224: 
                    225:     if (r->connection->read->timedout) {
                    226:         r->connection->timedout = 1;
                    227:         ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
                    228:         return;
                    229:     }
                    230: 
                    231:     rc = ngx_http_do_read_client_request_body(r);
                    232: 
                    233:     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
                    234:         ngx_http_finalize_request(r, rc);
                    235:     }
                    236: }
                    237: 
                    238: 
                    239: static ngx_int_t
                    240: ngx_http_do_read_client_request_body(ngx_http_request_t *r)
                    241: {
                    242:     off_t                      rest;
                    243:     size_t                     size;
                    244:     ssize_t                    n;
                    245:     ngx_int_t                  rc;
                    246:     ngx_buf_t                 *b;
                    247:     ngx_chain_t               *cl, out;
                    248:     ngx_connection_t          *c;
                    249:     ngx_http_request_body_t   *rb;
                    250:     ngx_http_core_loc_conf_t  *clcf;
                    251: 
                    252:     c = r->connection;
                    253:     rb = r->request_body;
                    254: 
                    255:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    256:                    "http read client request body");
                    257: 
                    258:     for ( ;; ) {
                    259:         for ( ;; ) {
                    260:             if (rb->buf->last == rb->buf->end) {
                    261: 
                    262:                 /* pass buffer to request body filter chain */
                    263: 
                    264:                 out.buf = rb->buf;
                    265:                 out.next = NULL;
                    266: 
                    267:                 rc = ngx_http_request_body_filter(r, &out);
                    268: 
                    269:                 if (rc != NGX_OK) {
                    270:                     return rc;
                    271:                 }
                    272: 
                    273:                 /* write to file */
                    274: 
                    275:                 if (ngx_http_write_request_body(r) != NGX_OK) {
                    276:                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    277:                 }
                    278: 
                    279:                 /* update chains */
                    280: 
                    281:                 rc = ngx_http_request_body_filter(r, NULL);
                    282: 
                    283:                 if (rc != NGX_OK) {
                    284:                     return rc;
                    285:                 }
                    286: 
                    287:                 if (rb->busy != NULL) {
                    288:                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    289:                 }
                    290: 
                    291:                 rb->buf->pos = rb->buf->start;
                    292:                 rb->buf->last = rb->buf->start;
                    293:             }
                    294: 
                    295:             size = rb->buf->end - rb->buf->last;
                    296:             rest = rb->rest - (rb->buf->last - rb->buf->pos);
                    297: 
                    298:             if ((off_t) size > rest) {
                    299:                 size = (size_t) rest;
                    300:             }
                    301: 
                    302:             n = c->recv(c, rb->buf->last, size);
                    303: 
                    304:             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    305:                            "http client request body recv %z", n);
                    306: 
                    307:             if (n == NGX_AGAIN) {
                    308:                 break;
                    309:             }
                    310: 
                    311:             if (n == 0) {
                    312:                 ngx_log_error(NGX_LOG_INFO, c->log, 0,
                    313:                               "client prematurely closed connection");
                    314:             }
                    315: 
                    316:             if (n == 0 || n == NGX_ERROR) {
                    317:                 c->error = 1;
                    318:                 return NGX_HTTP_BAD_REQUEST;
                    319:             }
                    320: 
                    321:             rb->buf->last += n;
                    322:             r->request_length += n;
                    323: 
                    324:             if (n == rest) {
                    325:                 /* pass buffer to request body filter chain */
                    326: 
                    327:                 out.buf = rb->buf;
                    328:                 out.next = NULL;
                    329: 
                    330:                 rc = ngx_http_request_body_filter(r, &out);
                    331: 
                    332:                 if (rc != NGX_OK) {
                    333:                     return rc;
                    334:                 }
                    335:             }
                    336: 
                    337:             if (rb->rest == 0) {
                    338:                 break;
                    339:             }
                    340: 
                    341:             if (rb->buf->last < rb->buf->end) {
                    342:                 break;
                    343:             }
                    344:         }
                    345: 
                    346:         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    347:                        "http client request body rest %O", rb->rest);
                    348: 
                    349:         if (rb->rest == 0) {
                    350:             break;
                    351:         }
                    352: 
                    353:         if (!c->read->ready) {
                    354:             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
                    355:             ngx_add_timer(c->read, clcf->client_body_timeout);
                    356: 
                    357:             if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
                    358:                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    359:             }
                    360: 
                    361:             return NGX_AGAIN;
                    362:         }
                    363:     }
                    364: 
                    365:     if (c->read->timer_set) {
                    366:         ngx_del_timer(c->read);
                    367:     }
                    368: 
                    369:     if (rb->temp_file || r->request_body_in_file_only) {
                    370: 
                    371:         /* save the last part */
                    372: 
                    373:         if (ngx_http_write_request_body(r) != NGX_OK) {
                    374:             return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    375:         }
                    376: 
                    377:         cl = ngx_chain_get_free_buf(r->pool, &rb->free);
                    378:         if (cl == NULL) {
                    379:             return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    380:         }
                    381: 
                    382:         b = cl->buf;
                    383: 
                    384:         ngx_memzero(b, sizeof(ngx_buf_t));
                    385: 
                    386:         b->in_file = 1;
                    387:         b->file_last = rb->temp_file->file.offset;
                    388:         b->file = &rb->temp_file->file;
                    389: 
                    390:         rb->bufs = cl;
                    391:     }
                    392: 
                    393:     r->read_event_handler = ngx_http_block_reading;
                    394: 
                    395:     rb->post_handler(r);
                    396: 
                    397:     return NGX_OK;
                    398: }
                    399: 
                    400: 
                    401: static ngx_int_t
                    402: ngx_http_write_request_body(ngx_http_request_t *r)
                    403: {
                    404:     ssize_t                    n;
                    405:     ngx_chain_t               *cl;
                    406:     ngx_temp_file_t           *tf;
                    407:     ngx_http_request_body_t   *rb;
                    408:     ngx_http_core_loc_conf_t  *clcf;
                    409: 
                    410:     rb = r->request_body;
                    411: 
                    412:     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    413:                    "http write client request body, bufs %p", rb->bufs);
                    414: 
                    415:     if (rb->temp_file == NULL) {
                    416:         tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
                    417:         if (tf == NULL) {
                    418:             return NGX_ERROR;
                    419:         }
                    420: 
                    421:         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
                    422: 
                    423:         tf->file.fd = NGX_INVALID_FILE;
                    424:         tf->file.log = r->connection->log;
                    425:         tf->path = clcf->client_body_temp_path;
                    426:         tf->pool = r->pool;
                    427:         tf->warn = "a client request body is buffered to a temporary file";
                    428:         tf->log_level = r->request_body_file_log_level;
                    429:         tf->persistent = r->request_body_in_persistent_file;
                    430:         tf->clean = r->request_body_in_clean_file;
                    431: 
                    432:         if (r->request_body_file_group_access) {
                    433:             tf->access = 0660;
                    434:         }
                    435: 
                    436:         rb->temp_file = tf;
                    437: 
                    438:         if (rb->bufs == NULL) {
                    439:             /* empty body with r->request_body_in_file_only */
                    440: 
                    441:             if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
                    442:                                      tf->persistent, tf->clean, tf->access)
                    443:                 != NGX_OK)
                    444:             {
                    445:                 return NGX_ERROR;
                    446:             }
                    447: 
                    448:             return NGX_OK;
                    449:         }
                    450:     }
                    451: 
                    452:     if (rb->bufs == NULL) {
                    453:         return NGX_OK;
                    454:     }
                    455: 
                    456:     n = ngx_write_chain_to_temp_file(rb->temp_file, rb->bufs);
                    457: 
                    458:     /* TODO: n == 0 or not complete and level event */
                    459: 
                    460:     if (n == NGX_ERROR) {
                    461:         return NGX_ERROR;
                    462:     }
                    463: 
                    464:     rb->temp_file->offset += n;
                    465: 
                    466:     /* mark all buffers as written */
                    467: 
                    468:     for (cl = rb->bufs; cl; cl = cl->next) {
                    469:         cl->buf->pos = cl->buf->last;
                    470:     }
                    471: 
                    472:     rb->bufs = NULL;
                    473: 
                    474:     return NGX_OK;
                    475: }
                    476: 
                    477: 
                    478: ngx_int_t
                    479: ngx_http_discard_request_body(ngx_http_request_t *r)
                    480: {
                    481:     ssize_t       size;
                    482:     ngx_int_t     rc;
                    483:     ngx_event_t  *rev;
                    484: 
                    485: #if (NGX_HTTP_SPDY)
                    486:     if (r->spdy_stream && r == r->main) {
                    487:         r->spdy_stream->skip_data = NGX_SPDY_DATA_DISCARD;
                    488:         return NGX_OK;
                    489:     }
                    490: #endif
                    491: 
                    492:     if (r != r->main || r->discard_body || r->request_body) {
                    493:         return NGX_OK;
                    494:     }
                    495: 
                    496:     if (ngx_http_test_expect(r) != NGX_OK) {
                    497:         return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    498:     }
                    499: 
                    500:     rev = r->connection->read;
                    501: 
                    502:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");
                    503: 
                    504:     if (rev->timer_set) {
                    505:         ngx_del_timer(rev);
                    506:     }
                    507: 
                    508:     if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
                    509:         return NGX_OK;
                    510:     }
                    511: 
                    512:     size = r->header_in->last - r->header_in->pos;
                    513: 
                    514:     if (size || r->headers_in.chunked) {
                    515:         rc = ngx_http_discard_request_body_filter(r, r->header_in);
                    516: 
                    517:         if (rc != NGX_OK) {
                    518:             return rc;
                    519:         }
                    520: 
                    521:         if (r->headers_in.content_length_n == 0) {
                    522:             return NGX_OK;
                    523:         }
                    524:     }
                    525: 
                    526:     rc = ngx_http_read_discarded_request_body(r);
                    527: 
                    528:     if (rc == NGX_OK) {
                    529:         r->lingering_close = 0;
                    530:         return NGX_OK;
                    531:     }
                    532: 
                    533:     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
                    534:         return rc;
                    535:     }
                    536: 
                    537:     /* rc == NGX_AGAIN */
                    538: 
                    539:     r->read_event_handler = ngx_http_discarded_request_body_handler;
                    540: 
                    541:     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
                    542:         return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    543:     }
                    544: 
                    545:     r->count++;
                    546:     r->discard_body = 1;
                    547: 
                    548:     return NGX_OK;
                    549: }
                    550: 
                    551: 
                    552: void
                    553: ngx_http_discarded_request_body_handler(ngx_http_request_t *r)
                    554: {
                    555:     ngx_int_t                  rc;
                    556:     ngx_msec_t                 timer;
                    557:     ngx_event_t               *rev;
                    558:     ngx_connection_t          *c;
                    559:     ngx_http_core_loc_conf_t  *clcf;
                    560: 
                    561:     c = r->connection;
                    562:     rev = c->read;
                    563: 
                    564:     if (rev->timedout) {
                    565:         c->timedout = 1;
                    566:         c->error = 1;
                    567:         ngx_http_finalize_request(r, NGX_ERROR);
                    568:         return;
                    569:     }
                    570: 
                    571:     if (r->lingering_time) {
                    572:         timer = (ngx_msec_t) (r->lingering_time - ngx_time());
                    573: 
                    574:         if (timer <= 0) {
                    575:             r->discard_body = 0;
                    576:             r->lingering_close = 0;
                    577:             ngx_http_finalize_request(r, NGX_ERROR);
                    578:             return;
                    579:         }
                    580: 
                    581:     } else {
                    582:         timer = 0;
                    583:     }
                    584: 
                    585:     rc = ngx_http_read_discarded_request_body(r);
                    586: 
                    587:     if (rc == NGX_OK) {
                    588:         r->discard_body = 0;
                    589:         r->lingering_close = 0;
                    590:         ngx_http_finalize_request(r, NGX_DONE);
                    591:         return;
                    592:     }
                    593: 
                    594:     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
                    595:         c->error = 1;
                    596:         ngx_http_finalize_request(r, NGX_ERROR);
                    597:         return;
                    598:     }
                    599: 
                    600:     /* rc == NGX_AGAIN */
                    601: 
                    602:     if (ngx_handle_read_event(rev, 0) != NGX_OK) {
                    603:         c->error = 1;
                    604:         ngx_http_finalize_request(r, NGX_ERROR);
                    605:         return;
                    606:     }
                    607: 
                    608:     if (timer) {
                    609: 
                    610:         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
                    611: 
                    612:         timer *= 1000;
                    613: 
                    614:         if (timer > clcf->lingering_timeout) {
                    615:             timer = clcf->lingering_timeout;
                    616:         }
                    617: 
                    618:         ngx_add_timer(rev, timer);
                    619:     }
                    620: }
                    621: 
                    622: 
                    623: static ngx_int_t
                    624: ngx_http_read_discarded_request_body(ngx_http_request_t *r)
                    625: {
                    626:     size_t     size;
                    627:     ssize_t    n;
                    628:     ngx_int_t  rc;
                    629:     ngx_buf_t  b;
                    630:     u_char     buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];
                    631: 
                    632:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    633:                    "http read discarded body");
                    634: 
                    635:     ngx_memzero(&b, sizeof(ngx_buf_t));
                    636: 
                    637:     b.temporary = 1;
                    638: 
                    639:     for ( ;; ) {
                    640:         if (r->headers_in.content_length_n == 0) {
                    641:             r->read_event_handler = ngx_http_block_reading;
                    642:             return NGX_OK;
                    643:         }
                    644: 
                    645:         if (!r->connection->read->ready) {
                    646:             return NGX_AGAIN;
                    647:         }
                    648: 
                    649:         size = (size_t) ngx_min(r->headers_in.content_length_n,
                    650:                                 NGX_HTTP_DISCARD_BUFFER_SIZE);
                    651: 
                    652:         n = r->connection->recv(r->connection, buffer, size);
                    653: 
                    654:         if (n == NGX_ERROR) {
                    655:             r->connection->error = 1;
                    656:             return NGX_OK;
                    657:         }
                    658: 
                    659:         if (n == NGX_AGAIN) {
                    660:             return NGX_AGAIN;
                    661:         }
                    662: 
                    663:         if (n == 0) {
                    664:             return NGX_OK;
                    665:         }
                    666: 
                    667:         b.pos = buffer;
                    668:         b.last = buffer + n;
                    669: 
                    670:         rc = ngx_http_discard_request_body_filter(r, &b);
                    671: 
                    672:         if (rc != NGX_OK) {
                    673:             return rc;
                    674:         }
                    675:     }
                    676: }
                    677: 
                    678: 
                    679: static ngx_int_t
                    680: ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
                    681: {
                    682:     size_t                    size;
                    683:     ngx_int_t                 rc;
                    684:     ngx_http_request_body_t  *rb;
                    685: 
                    686:     if (r->headers_in.chunked) {
                    687: 
                    688:         rb = r->request_body;
                    689: 
                    690:         if (rb == NULL) {
                    691: 
                    692:             rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
                    693:             if (rb == NULL) {
                    694:                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    695:             }
                    696: 
                    697:             rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
                    698:             if (rb->chunked == NULL) {
                    699:                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    700:             }
                    701: 
                    702:             r->request_body = rb;
                    703:         }
                    704: 
                    705:         for ( ;; ) {
                    706: 
                    707:             rc = ngx_http_parse_chunked(r, b, rb->chunked);
                    708: 
                    709:             if (rc == NGX_OK) {
                    710: 
                    711:                 /* a chunk has been parsed successfully */
                    712: 
                    713:                 size = b->last - b->pos;
                    714: 
                    715:                 if ((off_t) size > rb->chunked->size) {
                    716:                     b->pos += rb->chunked->size;
                    717:                     rb->chunked->size = 0;
                    718: 
                    719:                 } else {
                    720:                     rb->chunked->size -= size;
                    721:                     b->pos = b->last;
                    722:                 }
                    723: 
                    724:                 continue;
                    725:             }
                    726: 
                    727:             if (rc == NGX_DONE) {
                    728: 
                    729:                 /* a whole response has been parsed successfully */
                    730: 
                    731:                 r->headers_in.content_length_n = 0;
                    732:                 break;
                    733:             }
                    734: 
                    735:             if (rc == NGX_AGAIN) {
                    736: 
                    737:                 /* set amount of data we want to see next time */
                    738: 
                    739:                 r->headers_in.content_length_n = rb->chunked->length;
                    740:                 break;
                    741:             }
                    742: 
                    743:             /* invalid */
                    744: 
                    745:             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                    746:                           "client sent invalid chunked body");
                    747: 
                    748:             return NGX_HTTP_BAD_REQUEST;
                    749:         }
                    750: 
                    751:     } else {
                    752:         size = b->last - b->pos;
                    753: 
                    754:         if ((off_t) size > r->headers_in.content_length_n) {
                    755:             b->pos += r->headers_in.content_length_n;
                    756:             r->headers_in.content_length_n = 0;
                    757: 
                    758:         } else {
                    759:             b->pos = b->last;
                    760:             r->headers_in.content_length_n -= size;
                    761:         }
                    762:     }
                    763: 
                    764:     return NGX_OK;
                    765: }
                    766: 
                    767: 
                    768: static ngx_int_t
                    769: ngx_http_test_expect(ngx_http_request_t *r)
                    770: {
                    771:     ngx_int_t   n;
                    772:     ngx_str_t  *expect;
                    773: 
                    774:     if (r->expect_tested
                    775:         || r->headers_in.expect == NULL
                    776:         || r->http_version < NGX_HTTP_VERSION_11)
                    777:     {
                    778:         return NGX_OK;
                    779:     }
                    780: 
                    781:     r->expect_tested = 1;
                    782: 
                    783:     expect = &r->headers_in.expect->value;
                    784: 
                    785:     if (expect->len != sizeof("100-continue") - 1
                    786:         || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
                    787:                            sizeof("100-continue") - 1)
                    788:            != 0)
                    789:     {
                    790:         return NGX_OK;
                    791:     }
                    792: 
                    793:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    794:                    "send 100 Continue");
                    795: 
                    796:     n = r->connection->send(r->connection,
                    797:                             (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
                    798:                             sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);
                    799: 
                    800:     if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
                    801:         return NGX_OK;
                    802:     }
                    803: 
                    804:     /* we assume that such small packet should be send successfully */
                    805: 
                    806:     return NGX_ERROR;
                    807: }
                    808: 
                    809: 
                    810: static ngx_int_t
                    811: ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
                    812: {
                    813:     if (r->headers_in.chunked) {
                    814:         return ngx_http_request_body_chunked_filter(r, in);
                    815: 
                    816:     } else {
                    817:         return ngx_http_request_body_length_filter(r, in);
                    818:     }
                    819: }
                    820: 
                    821: 
                    822: static ngx_int_t
                    823: ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
                    824: {
                    825:     size_t                     size;
                    826:     ngx_int_t                  rc;
                    827:     ngx_buf_t                 *b;
                    828:     ngx_chain_t               *cl, *tl, *out, **ll;
                    829:     ngx_http_request_body_t   *rb;
                    830: 
                    831:     rb = r->request_body;
                    832: 
                    833:     if (rb->rest == -1) {
                    834:         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    835:                        "http request body content length filter");
                    836: 
                    837:         rb->rest = r->headers_in.content_length_n;
                    838:     }
                    839: 
                    840:     out = NULL;
                    841:     ll = &out;
                    842: 
                    843:     for (cl = in; cl; cl = cl->next) {
                    844: 
                    845:         tl = ngx_chain_get_free_buf(r->pool, &rb->free);
                    846:         if (tl == NULL) {
                    847:             return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    848:         }
                    849: 
                    850:         b = tl->buf;
                    851: 
                    852:         ngx_memzero(b, sizeof(ngx_buf_t));
                    853: 
                    854:         b->temporary = 1;
                    855:         b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
                    856:         b->start = cl->buf->pos;
                    857:         b->pos = cl->buf->pos;
                    858:         b->last = cl->buf->last;
                    859:         b->end = cl->buf->end;
                    860: 
                    861:         size = cl->buf->last - cl->buf->pos;
                    862: 
                    863:         if ((off_t) size < rb->rest) {
                    864:             cl->buf->pos = cl->buf->last;
                    865:             rb->rest -= size;
                    866: 
                    867:         } else {
                    868:             cl->buf->pos += rb->rest;
                    869:             rb->rest = 0;
                    870:             b->last = cl->buf->pos;
                    871:             b->last_buf = 1;
                    872:         }
                    873: 
                    874:         *ll = tl;
                    875:         ll = &tl->next;
                    876:     }
                    877: 
                    878:     rc = ngx_http_request_body_save_filter(r, out);
                    879: 
                    880:     ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
                    881:                             (ngx_buf_tag_t) &ngx_http_read_client_request_body);
                    882: 
                    883:     return rc;
                    884: }
                    885: 
                    886: 
                    887: static ngx_int_t
                    888: ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
                    889: {
                    890:     size_t                     size;
                    891:     ngx_int_t                  rc;
                    892:     ngx_buf_t                 *b;
                    893:     ngx_chain_t               *cl, *out, *tl, **ll;
                    894:     ngx_http_request_body_t   *rb;
                    895:     ngx_http_core_loc_conf_t  *clcf;
                    896: 
                    897:     rb = r->request_body;
                    898: 
                    899:     if (rb->rest == -1) {
                    900: 
                    901:         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    902:                        "http request body chunked filter");
                    903: 
                    904:         rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
                    905:         if (rb->chunked == NULL) {
                    906:             return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    907:         }
                    908: 
                    909:         r->headers_in.content_length_n = 0;
                    910:         rb->rest = 3;
                    911:     }
                    912: 
                    913:     out = NULL;
                    914:     ll = &out;
                    915: 
                    916:     for (cl = in; cl; cl = cl->next) {
                    917: 
                    918:         for ( ;; ) {
                    919: 
                    920:             ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
                    921:                            "http body chunked buf "
                    922:                            "t:%d f:%d %p, pos %p, size: %z file: %O, size: %z",
                    923:                            cl->buf->temporary, cl->buf->in_file,
                    924:                            cl->buf->start, cl->buf->pos,
                    925:                            cl->buf->last - cl->buf->pos,
                    926:                            cl->buf->file_pos,
                    927:                            cl->buf->file_last - cl->buf->file_pos);
                    928: 
                    929:             rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked);
                    930: 
                    931:             if (rc == NGX_OK) {
                    932: 
                    933:                 /* a chunk has been parsed successfully */
                    934: 
                    935:                 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
                    936: 
                    937:                 if (clcf->client_max_body_size
                    938:                     && clcf->client_max_body_size
                    939:                        < r->headers_in.content_length_n + rb->chunked->size)
                    940:                 {
                    941:                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                    942:                                   "client intended to send too large chunked "
                    943:                                   "body: %O bytes",
                    944:                                   r->headers_in.content_length_n
                    945:                                   + rb->chunked->size);
                    946: 
                    947:                     r->lingering_close = 1;
                    948: 
                    949:                     return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
                    950:                 }
                    951: 
                    952:                 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
                    953:                 if (tl == NULL) {
                    954:                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    955:                 }
                    956: 
                    957:                 b = tl->buf;
                    958: 
                    959:                 ngx_memzero(b, sizeof(ngx_buf_t));
                    960: 
                    961:                 b->temporary = 1;
                    962:                 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
                    963:                 b->start = cl->buf->pos;
                    964:                 b->pos = cl->buf->pos;
                    965:                 b->last = cl->buf->last;
                    966:                 b->end = cl->buf->end;
                    967: 
                    968:                 *ll = tl;
                    969:                 ll = &tl->next;
                    970: 
                    971:                 size = cl->buf->last - cl->buf->pos;
                    972: 
                    973:                 if ((off_t) size > rb->chunked->size) {
                    974:                     cl->buf->pos += rb->chunked->size;
                    975:                     r->headers_in.content_length_n += rb->chunked->size;
                    976:                     rb->chunked->size = 0;
                    977: 
                    978:                 } else {
                    979:                     rb->chunked->size -= size;
                    980:                     r->headers_in.content_length_n += size;
                    981:                     cl->buf->pos = cl->buf->last;
                    982:                 }
                    983: 
                    984:                 b->last = cl->buf->pos;
                    985: 
                    986:                 continue;
                    987:             }
                    988: 
                    989:             if (rc == NGX_DONE) {
                    990: 
                    991:                 /* a whole response has been parsed successfully */
                    992: 
                    993:                 rb->rest = 0;
                    994: 
                    995:                 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
                    996:                 if (tl == NULL) {
                    997:                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    998:                 }
                    999: 
                   1000:                 b = tl->buf;
                   1001: 
                   1002:                 ngx_memzero(b, sizeof(ngx_buf_t));
                   1003: 
                   1004:                 b->last_buf = 1;
                   1005: 
                   1006:                 *ll = tl;
                   1007:                 ll = &tl->next;
                   1008: 
                   1009:                 break;
                   1010:             }
                   1011: 
                   1012:             if (rc == NGX_AGAIN) {
                   1013: 
                   1014:                 /* set rb->rest, amount of data we want to see next time */
                   1015: 
                   1016:                 rb->rest = rb->chunked->length;
                   1017: 
                   1018:                 break;
                   1019:             }
                   1020: 
                   1021:             /* invalid */
                   1022: 
                   1023:             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   1024:                           "client sent invalid chunked body");
                   1025: 
                   1026:             return NGX_HTTP_BAD_REQUEST;
                   1027:         }
                   1028:     }
                   1029: 
                   1030:     rc = ngx_http_request_body_save_filter(r, out);
                   1031: 
                   1032:     ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
                   1033:                             (ngx_buf_tag_t) &ngx_http_read_client_request_body);
                   1034: 
                   1035:     return rc;
                   1036: }
                   1037: 
                   1038: 
                   1039: static ngx_int_t
                   1040: ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
                   1041: {
                   1042: #if (NGX_DEBUG)
                   1043:     ngx_chain_t               *cl;
                   1044: #endif
                   1045:     ngx_http_request_body_t   *rb;
                   1046: 
                   1047:     rb = r->request_body;
                   1048: 
                   1049: #if (NGX_DEBUG)
                   1050: 
                   1051:     for (cl = rb->bufs; cl; cl = cl->next) {
                   1052:         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
                   1053:                        "http body old buf t:%d f:%d %p, pos %p, size: %z "
                   1054:                        "file: %O, size: %z",
                   1055:                        cl->buf->temporary, cl->buf->in_file,
                   1056:                        cl->buf->start, cl->buf->pos,
                   1057:                        cl->buf->last - cl->buf->pos,
                   1058:                        cl->buf->file_pos,
                   1059:                        cl->buf->file_last - cl->buf->file_pos);
                   1060:     }
                   1061: 
                   1062:     for (cl = in; cl; cl = cl->next) {
                   1063:         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
                   1064:                        "http body new buf t:%d f:%d %p, pos %p, size: %z "
                   1065:                        "file: %O, size: %z",
                   1066:                        cl->buf->temporary, cl->buf->in_file,
                   1067:                        cl->buf->start, cl->buf->pos,
                   1068:                        cl->buf->last - cl->buf->pos,
                   1069:                        cl->buf->file_pos,
                   1070:                        cl->buf->file_last - cl->buf->file_pos);
                   1071:     }
                   1072: 
                   1073: #endif
                   1074: 
                   1075:     /* TODO: coalesce neighbouring buffers */
                   1076: 
                   1077:     if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) {
                   1078:         return NGX_HTTP_INTERNAL_SERVER_ERROR;
                   1079:     }
                   1080: 
                   1081:     return NGX_OK;
                   1082: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>