/* mostly based on the ngx_http_do_read_client_request_body * function in ngx_http_request_body.c of nginx 0.8.20. * copyrighted by Igor Sysoev. */ static ngx_int_t ngx_http_chunkin_do_read_chunked_request_body(ngx_http_request_t *r) { ngx_int_t rc; size_t size; ssize_t n; ngx_buf_t *b; ngx_connection_t *c; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; ngx_http_chunkin_ctx_t *ctx; ngx_flag_t done; ngx_chain_t *cl, *pending_chunk; u_char *p; ngx_http_chunkin_conf_t *conf; c = r->connection; rb = r->request_body; ctx = ngx_http_get_module_ctx(r, ngx_http_chunkin_filter_module); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "chunkin: http chunkin read chunked client request body"); done = 0; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (ctx->just_after_preread) { ctx->just_after_preread = 0; dd("Just after preread and ctx->chunks defined (bytes read: %d, " "chunk size: %d, last chars %c %c %c)", ctx->chunk_bytes_read, ctx->chunk_size, *(r->header_in->pos - 2), *(r->header_in->pos - 1), *r->header_in->pos); for (cl = ctx->chunks; cl; cl = cl->next) { b = cl->buf; dd("before ngx_copy..."); p = rb->buf->last; rb->buf->last = ngx_copy(rb->buf->last, b->pos, b->last - b->pos); dd("after ngx_copy..."); b->pos = p; b->last = rb->buf->last; } } conf = ngx_http_get_module_loc_conf(r, ngx_http_chunkin_filter_module); for ( ;; ) { for ( ;; ) { /* dd("client_max_body_size: %d, raw_body_size: %d", (int)clcf->client_max_body_size, (int)ctx->raw_body_size); */ if (clcf->client_max_body_size && clcf->client_max_body_size < ctx->raw_body_size) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "chunkin: client intended to send too large body: " "%O bytes", (off_t) ctx->raw_body_size); return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; } /* dd("rb->buf pos: %d", (int) (rb->buf->last - rb->buf->pos)); */ if (rb->buf->last == rb->buf->end || ctx->chunks_count > conf->max_chunks_per_buf) { if (ctx->chunks_count > conf->max_chunks_per_buf) { dd("too many chounks already: %d (max %d, buf last %c)", (int) ctx->chunks_count, (int) conf->max_chunks_per_buf, *(rb->buf->last - 2)); } if (ctx->chunks == NULL || (ctx->chunks_total_size && ctx->chunks_total_size <= ctx->chunks_written_size)) { ngx_log_error(NGX_LOG_WARN, c->log, 0, "chunkin: the chunkin_max_chunks_per_buf or " "max_client_body_size setting seems rather small " "(chunks %snull, total decoded %d, " "total written %d)", (u_char *) (ctx->chunks ? "not " : ""), (int) ctx->chunks_total_size, (int) ctx->chunks_written_size); } else { dd("save exceeding part to disk (%d bytes), buf size: %d, " "chunks count: %d", ctx->chunks_total_size - ctx->chunks_written_size, rb->buf->end - rb->buf->start, ctx->chunks_count); rc = ngx_http_write_request_body(r, ctx->chunks, ctx->chunks_count); if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } if (ctx->last_complete_chunk) { pending_chunk = ctx->last_complete_chunk->next; /* add ctx->chunks ~ ctx->last_complete_chunk * into ctx->free_bufs */ ctx->last_complete_chunk->next = ctx->free_bufs; ctx->free_bufs = ctx->chunks; ctx->last_complete_chunk = NULL; } else { pending_chunk = ctx->chunks; } if (pending_chunk) { ctx->next_chunk = &pending_chunk->next; ctx->chunks = pending_chunk; ctx->chunk = pending_chunk; ctx->chunk->buf->pos = rb->buf->start; ctx->chunk->buf->last = rb->buf->start; ctx->chunks_count = 1; ctx->chunks_written_size = ctx->chunks_total_size - ngx_buf_size(pending_chunk->buf); } else { ctx->next_chunk = NULL; ctx->chunks = NULL; ctx->chunk = NULL; ctx->chunks_count = 0; ctx->chunks_written_size = ctx->chunks_total_size; } dd("reset rb->buf"); rb->buf->last = rb->buf->start; #if 0 /* XXX just for debugging... */ ngx_memzero(rb->buf->start, rb->buf->end - rb->buf->start); #endif } size = rb->buf->end - rb->buf->last; n = c->recv(c, rb->buf->last, size); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "chunkin: http chunked client request body recv %z", n); if (n == NGX_AGAIN) { dd("NGX_AGAIN caught"); break; } if (n == 0) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "chunkin: client closed prematurely connection"); } if (n == 0 || n == NGX_ERROR) { c->error = 1; return NGX_HTTP_BAD_REQUEST; } /* save the original pos */ p = rb->buf->last; rc = ngx_http_chunkin_run_chunked_parser(r, ctx, &rb->buf->last, rb->buf->last + n, "main handler"); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } if (rc == NGX_ERROR) { /* chunked body parsefail */ return NGX_HTTP_BAD_REQUEST; } /* rb->buf->last += n; */ r->request_length += n; ctx->raw_body_size += n; if (rc == NGX_OK) { dd("successfully done the parsing"); dd("keepalive? %s", r->keepalive ? "yes" : "no"); if (r->keepalive) { dd("cleaning the buffers for pipelined reqeusts (if any)"); size = p + n - rb->buf->last; if (size) { dd("found remaining data for pipelined requests"); if (size > (size_t) (r->header_in->end - ctx->saved_header_in_pos)) { /* XXX enlarge the r->header_in buffer... */ r->keepalive = 0; } else { r->header_in->pos = ctx->saved_header_in_pos; r->header_in->last = ngx_copy(r->header_in->pos, rb->buf->last, size); } } } done = 1; break; } /* rc == NGX_AGAIN */ if (rb->buf->last < rb->buf->end) { break; } } if (done) { break; } if (!c->read->ready) { ngx_add_timer(c->read, clcf->client_body_timeout); if (ngx_handle_read_event(c->read, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } return NGX_AGAIN; } } if (!done) { return NGX_HTTP_BAD_REQUEST; } if (c->read->timer_set) { ngx_del_timer(c->read); } if (rb->temp_file || r->request_body_in_file_only) { size = ctx->chunks_total_size - ctx->chunks_written_size; dd("save the last part to disk...(%d bytes left)", size); if (size == 0) { ctx->chunks = NULL; } #if 0 n = 0; for (cl = ctx->chunks; cl != NULL; cl = cl->next) { /* dd("chunks %d found buf %c", n, *cl->buf->start); */ n++; } #endif dd("for total %d chunks found", n); /* save the last part */ rc = ngx_http_write_request_body(r, ctx->chunks, ctx->chunks_count); if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b = ngx_calloc_buf(r->pool); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } b->in_file = 1; b->file_pos = 0; b->file_last = rb->temp_file->file.offset; b->file = &rb->temp_file->file; rb->bufs = ngx_http_chunkin_get_buf(r->pool, ctx); if (rb->bufs == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rb->bufs->buf = b; } else if ( r->request_body_in_single_buf ) { dd("request body in single buf"); /* XXX we may not have to allocate a big buffer here */ size = 0; for (cl = ctx->chunks; cl != NULL; cl = cl->next) { size += ngx_buf_size(cl->buf); } rb->buf = ngx_create_temp_buf(r->pool, size); if (rb->buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } for (cl = ctx->chunks; cl != NULL; cl = cl->next) { size = ngx_buf_size(cl->buf); dd("copy buf ...(size %d)", size); rb->buf->last = ngx_cpymem(rb->buf->last, cl->buf->pos, size); } rb->bufs = ngx_http_chunkin_get_buf(r->pool, ctx); if (rb->bufs == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } rb->bufs->buf = rb->buf; } else { rb->bufs = ctx->chunks; } #if 0 if (rb->bufs) { int i; for (i = 0, cl = rb->bufs; cl; cl = cl->next, i++) { if (cl->buf->memory && cl->buf->pos == cl->buf->last) { dd("Found zero size buf in chain pos %d", i); } } } #endif dd("last minute, chunks count: %d, chunks_total_size: %d", ctx->chunks_count, ctx->chunks_total_size); #if 0 size = 0; for (cl = rb->bufs; cl; cl = cl->next) { size += ngx_buf_size(cl->buf); } dd("data size: %d", size); #endif rc = ngx_http_chunkin_set_content_length_header(r, ctx->chunks_total_size); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } rb->post_handler(r); return NGX_OK; }
ngx_int_t ngx_http_chunkin_run_chunked_parser(ngx_http_request_t *r, ngx_http_chunkin_ctx_t *ctx, u_char **pos_addr, u_char *last, char *caller_info) { int cs = ctx->parser_state; ngx_connection_t *c = r->connection; char *pos = (char *) *pos_addr; char *p = (char *) *pos_addr; char *pe = (char *) last; char *eof = NULL; ngx_buf_t *b; ngx_flag_t done = 0; ngx_str_t pre, post; char* err_ctx = ""; ngx_str_t user_agent = ngx_null_string; ssize_t rest; #line 235 "src/chunked_parser.rl" #line 86 "src/chunked_parser.c" { short _widec; if ( p == pe ) goto _test_eof; switch ( cs ) { case 1: if ( (*p) == 48 ) goto tr0; if ( (*p) < 65 ) { if ( 49 <= (*p) && (*p) <= 57 ) goto tr2; } else if ( (*p) > 70 ) { if ( 97 <= (*p) && (*p) <= 102 ) goto tr2; } else goto tr2; goto st0; tr3: #line 226 "src/chunked_parser.rl" { err_ctx = "last_chunk"; } goto st0; tr9: #line 167 "src/chunked_parser.rl" { err_ctx = "CRLF"; } #line 226 "src/chunked_parser.rl" { err_ctx = "last_chunk"; } goto st0; tr11: #line 167 "src/chunked_parser.rl" { err_ctx = "CRLF"; } #line 226 "src/chunked_parser.rl" { err_ctx = "last_chunk"; } #line 230 "src/chunked_parser.rl" { err_ctx = "parser"; } goto st0; tr13: #line 167 "src/chunked_parser.rl" { err_ctx = "CRLF"; } #line 230 "src/chunked_parser.rl" { err_ctx = "parser"; } goto st0; tr23: #line 167 "src/chunked_parser.rl" { err_ctx = "CRLF"; } goto st0; tr29: #line 217 "src/chunked_parser.rl" { err_ctx = "chunk_size"; } #line 220 "src/chunked_parser.rl" { err_ctx = "chunk_ext"; } goto st0; tr33: #line 167 "src/chunked_parser.rl" { err_ctx = "CRLF"; } #line 220 "src/chunked_parser.rl" { err_ctx = "chunk_ext"; } goto st0; tr35: #line 167 "src/chunked_parser.rl" { err_ctx = "CRLF"; } #line 220 "src/chunked_parser.rl" { err_ctx = "chunk_ext"; } #line 176 "src/chunked_parser.rl" { err_ctx = "chunk_data"; } goto st0; tr37: #line 176 "src/chunked_parser.rl" { err_ctx = "chunk_data"; } goto st0; tr40: #line 180 "src/chunked_parser.rl" { err_ctx = "chunk_data_terminator"; } goto st0; tr43: #line 220 "src/chunked_parser.rl" { err_ctx = "chunk_ext"; } goto st0; #line 165 "src/chunked_parser.c" st0: cs = 0; goto _out; tr0: #line 97 "src/chunked_parser.rl" { ctx->chunk_bytes_read = 0; ctx->chunk_size = 0; ctx->chunk_size_order = 0; } #line 103 "src/chunked_parser.rl" { ctx->chunk_size <<= 4; ctx->chunk_size_order++; if (*p >= 'A' && *p <= 'F') { ctx->chunk_size |= 10 + *p - 'A'; } else if (*p >= 'a' && *p <= 'f') { ctx->chunk_size |= 10 + *p - 'a'; } else { ctx->chunk_size |= *p - '0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "chunkin: chunk size: %uz\n", ctx->chunk_size); } goto st2; tr6: #line 103 "src/chunked_parser.rl" { ctx->chunk_size <<= 4; ctx->chunk_size_order++; if (*p >= 'A' && *p <= 'F') { ctx->chunk_size |= 10 + *p - 'A'; } else if (*p >= 'a' && *p <= 'f') { ctx->chunk_size |= 10 + *p - 'a'; } else { ctx->chunk_size |= *p - '0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "chunkin: chunk size: %uz\n", ctx->chunk_size); } goto st2; st2: if ( ++p == pe ) goto _test_eof2; case 2: #line 213 "src/chunked_parser.c" switch( (*p) ) { case 9: goto st3; case 13: goto st4; case 32: goto st3; case 48: goto tr6; case 59: goto st7; } if ( (*p) < 65 ) { if ( 49 <= (*p) && (*p) <= 57 ) goto tr7; } else if ( (*p) > 70 ) { if ( 97 <= (*p) && (*p) <= 102 ) goto tr7; } else goto tr7; goto tr3; st3: if ( ++p == pe ) goto _test_eof3; case 3: switch( (*p) ) { case 9: goto st3; case 13: goto st4; case 32: goto st3; case 59: goto st7; } goto tr3; st4: if ( ++p == pe ) goto _test_eof4; case 4: if ( (*p) == 10 ) goto st5; goto tr9; st5: if ( ++p == pe ) goto _test_eof5; case 5: if ( (*p) == 13 ) goto st6; goto tr11; st6: if ( ++p == pe ) goto _test_eof6; case 6: if ( (*p) == 10 ) goto tr14; goto tr13; tr14: #line 65 "src/chunked_parser.rl" { done = 1; } goto st43; st43: if ( ++p == pe ) goto _test_eof43; case 43: #line 272 "src/chunked_parser.c" goto tr13; st7: if ( ++p == pe ) goto _test_eof7; case 7: switch( (*p) ) { case 9: goto st7; case 32: goto st7; case 34: goto st0; case 44: goto st0; case 47: goto st0; case 123: goto st0; case 125: goto st0; case 127: goto st0; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto st0; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto st0; } else if ( (*p) >= 58 ) goto st0; } else goto st0; goto st8; st8: if ( ++p == pe ) goto _test_eof8; case 8: switch( (*p) ) { case 9: goto st9; case 13: goto st4; case 32: goto st9; case 34: goto tr3; case 44: goto tr3; case 47: goto tr3; case 59: goto st7; case 61: goto st10; case 123: goto tr3; case 125: goto tr3; case 127: goto tr3; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto tr3; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto tr3; } else if ( (*p) >= 58 ) goto tr3; } else goto tr3; goto st8; st9: if ( ++p == pe ) goto _test_eof9; case 9: switch( (*p) ) { case 9: goto st9; case 13: goto st4; case 32: goto st9; case 59: goto st7; case 61: goto st10; } goto tr3; st10: if ( ++p == pe ) goto _test_eof10; case 10: switch( (*p) ) { case 9: goto st10; case 32: goto st10; case 34: goto st12; case 44: goto st0; case 47: goto st0; case 123: goto st0; case 125: goto st0; case 127: goto st0; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto st0; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto st0; } else if ( (*p) >= 58 ) goto st0; } else goto st0; goto st11; st11: if ( ++p == pe ) goto _test_eof11; case 11: switch( (*p) ) { case 9: goto st3; case 13: goto st4; case 32: goto st3; case 34: goto tr3; case 44: goto tr3; case 47: goto tr3; case 59: goto st7; case 123: goto tr3; case 125: goto tr3; case 127: goto tr3; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto tr3; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto tr3; } else if ( (*p) >= 58 ) goto tr3; } else goto tr3; goto st11; st12: if ( ++p == pe ) goto _test_eof12; case 12: switch( (*p) ) { case 34: goto st3; case 92: goto st13; case 127: goto st0; } if ( (*p) > 8 ) { if ( 10 <= (*p) && (*p) <= 31 ) goto st0; } else if ( (*p) >= 0 ) goto st0; goto st12; st13: if ( ++p == pe ) goto _test_eof13; case 13: switch( (*p) ) { case 13: goto st14; case 34: goto st15; case 92: goto st13; } goto st12; st14: if ( ++p == pe ) goto _test_eof14; case 14: switch( (*p) ) { case 34: goto st3; case 92: goto st13; case 127: goto tr23; } if ( (*p) > 8 ) { if ( 10 <= (*p) && (*p) <= 31 ) goto tr23; } else if ( (*p) >= 0 ) goto tr23; goto st12; st15: if ( ++p == pe ) goto _test_eof15; case 15: switch( (*p) ) { case 9: goto st15; case 13: goto st4; case 32: goto st15; case 34: goto st3; case 59: goto st16; case 92: goto st13; case 127: goto tr3; } if ( 0 <= (*p) && (*p) <= 31 ) goto tr3; goto st12; st16: if ( ++p == pe ) goto _test_eof16; case 16: switch( (*p) ) { case 9: goto st16; case 32: goto st16; case 34: goto st3; case 44: goto st12; case 47: goto st12; case 92: goto st13; case 123: goto st12; case 125: goto st12; case 127: goto st0; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto st0; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto st12; } else if ( (*p) >= 58 ) goto st12; } else goto st12; goto st17; st17: if ( ++p == pe ) goto _test_eof17; case 17: switch( (*p) ) { case 9: goto st18; case 13: goto st4; case 32: goto st18; case 34: goto st3; case 44: goto st12; case 47: goto st12; case 59: goto st16; case 61: goto st19; case 92: goto st13; case 123: goto st12; case 125: goto st12; case 127: goto tr3; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto tr3; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto st12; } else if ( (*p) >= 58 ) goto st12; } else goto st12; goto st17; st18: if ( ++p == pe ) goto _test_eof18; case 18: switch( (*p) ) { case 9: goto st18; case 13: goto st4; case 32: goto st18; case 34: goto st3; case 59: goto st16; case 61: goto st19; case 92: goto st13; case 127: goto tr3; } if ( 0 <= (*p) && (*p) <= 31 ) goto tr3; goto st12; st19: if ( ++p == pe ) goto _test_eof19; case 19: switch( (*p) ) { case 9: goto st19; case 32: goto st19; case 34: goto st15; case 44: goto st12; case 47: goto st12; case 92: goto st13; case 123: goto st12; case 125: goto st12; case 127: goto st0; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto st0; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto st12; } else if ( (*p) >= 58 ) goto st12; } else goto st12; goto st20; st20: if ( ++p == pe ) goto _test_eof20; case 20: switch( (*p) ) { case 9: goto st15; case 13: goto st4; case 32: goto st15; case 34: goto st3; case 44: goto st12; case 47: goto st12; case 59: goto st16; case 92: goto st13; case 123: goto st12; case 125: goto st12; case 127: goto tr3; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto tr3; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto st12; } else if ( (*p) >= 58 ) goto st12; } else goto st12; goto st20; tr2: #line 97 "src/chunked_parser.rl" { ctx->chunk_bytes_read = 0; ctx->chunk_size = 0; ctx->chunk_size_order = 0; } #line 103 "src/chunked_parser.rl" { ctx->chunk_size <<= 4; ctx->chunk_size_order++; if (*p >= 'A' && *p <= 'F') { ctx->chunk_size |= 10 + *p - 'A'; } else if (*p >= 'a' && *p <= 'f') { ctx->chunk_size |= 10 + *p - 'a'; } else { ctx->chunk_size |= *p - '0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "chunkin: chunk size: %uz\n", ctx->chunk_size); } goto st21; tr7: #line 103 "src/chunked_parser.rl" { ctx->chunk_size <<= 4; ctx->chunk_size_order++; if (*p >= 'A' && *p <= 'F') { ctx->chunk_size |= 10 + *p - 'A'; } else if (*p >= 'a' && *p <= 'f') { ctx->chunk_size |= 10 + *p - 'a'; } else { ctx->chunk_size |= *p - '0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "chunkin: chunk size: %uz\n", ctx->chunk_size); } goto st21; st21: if ( ++p == pe ) goto _test_eof21; case 21: #line 625 "src/chunked_parser.c" switch( (*p) ) { case 9: goto st22; case 13: goto st23; case 32: goto st22; case 59: goto st28; } if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto tr7; } else if ( (*p) > 70 ) { if ( 97 <= (*p) && (*p) <= 102 ) goto tr7; } else goto tr7; goto tr29; st22: if ( ++p == pe ) goto _test_eof22; case 22: switch( (*p) ) { case 9: goto st22; case 13: goto st23; case 32: goto st22; case 59: goto st28; } goto tr29; st23: if ( ++p == pe ) goto _test_eof23; case 23: if ( (*p) == 10 ) goto st24; goto tr33; st24: if ( ++p == pe ) goto _test_eof24; case 24: _widec = (*p); _widec = (short)(128 + ((*p) - -128)); if ( #line 69 "src/chunked_parser.rl" ctx->chunk_bytes_read < ctx->chunk_size ) _widec += 256; if ( 384 <= _widec && _widec <= 639 ) goto tr36; goto tr35; tr36: #line 118 "src/chunked_parser.rl" { ctx->chunk = ngx_http_chunkin_get_buf(r->pool, ctx); ctx->chunks_count++; if (ctx->chunks) { *ctx->next_chunk = ctx->chunk; } else { ctx->chunks = ctx->chunk; } ctx->next_chunk = &ctx->chunk->next; b = ctx->chunk->buf; b->last = b->pos = (u_char *) p; b->memory = 1; } #line 73 "src/chunked_parser.rl" { /* optimization for buffered chunk data */ rest = ngx_chunkin_min( (ssize_t)ctx->chunk_size - (ssize_t)ctx->chunk_bytes_read, (ssize_t)(pe - p)); dd("moving %d, chunk size %d, read %d, rest %d", (int)rest, (int)ctx->chunk_size, (int)ctx->chunk_bytes_read, (int)rest); ctx->chunk_bytes_read += rest; p += rest - 1; ctx->chunk->buf->last = (u_char *)p + 1; ctx->chunks_total_size += rest; /* dd("bytes read: %d (char '%c', bytes read %d, chunk size %d)", ctx->chunk->buf->last - ctx->chunk->buf->pos, *p, ctx->chunk_bytes_read, ctx->chunk_size); */ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "chunkin: data bytes read: %uz (char: \"%c\")\n", ctx->chunk_bytes_read, *p); } goto st25; tr39: #line 73 "src/chunked_parser.rl" { /* optimization for buffered chunk data */ rest = ngx_chunkin_min( (ssize_t)ctx->chunk_size - (ssize_t)ctx->chunk_bytes_read, (ssize_t)(pe - p)); dd("moving %d, chunk size %d, read %d, rest %d", (int)rest, (int)ctx->chunk_size, (int)ctx->chunk_bytes_read, (int)rest); ctx->chunk_bytes_read += rest; p += rest - 1; ctx->chunk->buf->last = (u_char *)p + 1; ctx->chunks_total_size += rest; /* dd("bytes read: %d (char '%c', bytes read %d, chunk size %d)", ctx->chunk->buf->last - ctx->chunk->buf->pos, *p, ctx->chunk_bytes_read, ctx->chunk_size); */ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "chunkin: data bytes read: %uz (char: \"%c\")\n", ctx->chunk_bytes_read, *p); } goto st25; st25: if ( ++p == pe ) goto _test_eof25; case 25: #line 748 "src/chunked_parser.c" _widec = (*p); if ( (*p) < 13 ) { if ( (*p) <= 12 ) { _widec = (short)(128 + ((*p) - -128)); if ( #line 69 "src/chunked_parser.rl" ctx->chunk_bytes_read < ctx->chunk_size ) _widec += 256; } } else if ( (*p) > 13 ) { if ( 14 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( #line 69 "src/chunked_parser.rl" ctx->chunk_bytes_read < ctx->chunk_size ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( #line 69 "src/chunked_parser.rl" ctx->chunk_bytes_read < ctx->chunk_size ) _widec += 256; } if ( _widec == 269 ) goto st26; if ( 384 <= _widec && _widec <= 639 ) goto tr39; goto tr37; st26: if ( ++p == pe ) goto _test_eof26; case 26: if ( (*p) == 10 ) goto tr41; goto tr40; tr41: #line 137 "src/chunked_parser.rl" { if (ctx->chunk_bytes_read != ctx->chunk_size) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "ERROR: chunk size not met: " "%uz != %uz\n", ctx->chunk_bytes_read, ctx->chunk_size); *pos_addr = (u_char*) p; ctx->parser_state = chunked_error; return NGX_ERROR; } if (ctx->chunk_size == 0) { /* remove the current chunk */ ctx->chunk->next = ctx->free_bufs; ctx->free_bufs = ctx->chunk; ctx->chunk = ctx->last_complete_chunk; if (ctx->last_complete_chunk) { ctx->last_complete_chunk->next = NULL; } else { ctx->chunks = NULL; } } else { ctx->last_complete_chunk = ctx->chunk; } } goto st27; st27: if ( ++p == pe ) goto _test_eof27; case 27: #line 820 "src/chunked_parser.c" if ( (*p) == 48 ) goto tr0; if ( (*p) < 65 ) { if ( 49 <= (*p) && (*p) <= 57 ) goto tr2; } else if ( (*p) > 70 ) { if ( 97 <= (*p) && (*p) <= 102 ) goto tr2; } else goto tr2; goto tr40; st28: if ( ++p == pe ) goto _test_eof28; case 28: switch( (*p) ) { case 9: goto st28; case 32: goto st28; case 34: goto st0; case 44: goto st0; case 47: goto st0; case 123: goto st0; case 125: goto st0; case 127: goto st0; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto st0; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto st0; } else if ( (*p) >= 58 ) goto st0; } else goto st0; goto st29; st29: if ( ++p == pe ) goto _test_eof29; case 29: switch( (*p) ) { case 9: goto st30; case 13: goto st23; case 32: goto st30; case 34: goto tr43; case 44: goto tr43; case 47: goto tr43; case 59: goto st28; case 61: goto st31; case 123: goto tr43; case 125: goto tr43; case 127: goto tr43; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto tr43; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto tr43; } else if ( (*p) >= 58 ) goto tr43; } else goto tr43; goto st29; st30: if ( ++p == pe ) goto _test_eof30; case 30: switch( (*p) ) { case 9: goto st30; case 13: goto st23; case 32: goto st30; case 59: goto st28; case 61: goto st31; } goto tr43; st31: if ( ++p == pe ) goto _test_eof31; case 31: switch( (*p) ) { case 9: goto st31; case 32: goto st31; case 34: goto st34; case 44: goto st0; case 47: goto st0; case 123: goto st0; case 125: goto st0; case 127: goto st0; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto st0; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto st0; } else if ( (*p) >= 58 ) goto st0; } else goto st0; goto st32; st32: if ( ++p == pe ) goto _test_eof32; case 32: switch( (*p) ) { case 9: goto st33; case 13: goto st23; case 32: goto st33; case 34: goto tr43; case 44: goto tr43; case 47: goto tr43; case 59: goto st28; case 123: goto tr43; case 125: goto tr43; case 127: goto tr43; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto tr43; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto tr43; } else if ( (*p) >= 58 ) goto tr43; } else goto tr43; goto st32; st33: if ( ++p == pe ) goto _test_eof33; case 33: switch( (*p) ) { case 9: goto st33; case 13: goto st23; case 32: goto st33; case 59: goto st28; } goto tr43; st34: if ( ++p == pe ) goto _test_eof34; case 34: switch( (*p) ) { case 34: goto st33; case 92: goto st35; case 127: goto st0; } if ( (*p) > 8 ) { if ( 10 <= (*p) && (*p) <= 31 ) goto st0; } else if ( (*p) >= 0 ) goto st0; goto st34; st35: if ( ++p == pe ) goto _test_eof35; case 35: switch( (*p) ) { case 13: goto st36; case 34: goto st37; case 92: goto st35; } goto st34; st36: if ( ++p == pe ) goto _test_eof36; case 36: switch( (*p) ) { case 34: goto st33; case 92: goto st35; case 127: goto tr23; } if ( (*p) > 8 ) { if ( 10 <= (*p) && (*p) <= 31 ) goto tr23; } else if ( (*p) >= 0 ) goto tr23; goto st34; st37: if ( ++p == pe ) goto _test_eof37; case 37: switch( (*p) ) { case 9: goto st37; case 13: goto st23; case 32: goto st37; case 34: goto st33; case 59: goto st38; case 92: goto st35; case 127: goto tr43; } if ( 0 <= (*p) && (*p) <= 31 ) goto tr43; goto st34; st38: if ( ++p == pe ) goto _test_eof38; case 38: switch( (*p) ) { case 9: goto st38; case 32: goto st38; case 34: goto st33; case 44: goto st34; case 47: goto st34; case 92: goto st35; case 123: goto st34; case 125: goto st34; case 127: goto st0; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto st0; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto st34; } else if ( (*p) >= 58 ) goto st34; } else goto st34; goto st39; st39: if ( ++p == pe ) goto _test_eof39; case 39: switch( (*p) ) { case 9: goto st40; case 13: goto st23; case 32: goto st40; case 34: goto st33; case 44: goto st34; case 47: goto st34; case 59: goto st38; case 61: goto st41; case 92: goto st35; case 123: goto st34; case 125: goto st34; case 127: goto tr43; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto tr43; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto st34; } else if ( (*p) >= 58 ) goto st34; } else goto st34; goto st39; st40: if ( ++p == pe ) goto _test_eof40; case 40: switch( (*p) ) { case 9: goto st40; case 13: goto st23; case 32: goto st40; case 34: goto st33; case 59: goto st38; case 61: goto st41; case 92: goto st35; case 127: goto tr43; } if ( 0 <= (*p) && (*p) <= 31 ) goto tr43; goto st34; st41: if ( ++p == pe ) goto _test_eof41; case 41: switch( (*p) ) { case 9: goto st41; case 32: goto st41; case 34: goto st37; case 44: goto st34; case 47: goto st34; case 92: goto st35; case 123: goto st34; case 125: goto st34; case 127: goto st0; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto st0; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto st34; } else if ( (*p) >= 58 ) goto st34; } else goto st34; goto st42; st42: if ( ++p == pe ) goto _test_eof42; case 42: switch( (*p) ) { case 9: goto st37; case 13: goto st23; case 32: goto st37; case 34: goto st33; case 44: goto st34; case 47: goto st34; case 59: goto st38; case 92: goto st35; case 123: goto st34; case 125: goto st34; case 127: goto tr43; } if ( (*p) < 40 ) { if ( 0 <= (*p) && (*p) <= 31 ) goto tr43; } else if ( (*p) > 41 ) { if ( (*p) > 64 ) { if ( 91 <= (*p) && (*p) <= 93 ) goto st34; } else if ( (*p) >= 58 ) goto st34; } else goto st34; goto st42; } _test_eof2: cs = 2; goto _test_eof; _test_eof3: cs = 3; goto _test_eof; _test_eof4: cs = 4; goto _test_eof; _test_eof5: cs = 5; goto _test_eof; _test_eof6: cs = 6; goto _test_eof; _test_eof43: cs = 43; goto _test_eof; _test_eof7: cs = 7; goto _test_eof; _test_eof8: cs = 8; goto _test_eof; _test_eof9: cs = 9; goto _test_eof; _test_eof10: cs = 10; goto _test_eof; _test_eof11: cs = 11; goto _test_eof; _test_eof12: cs = 12; goto _test_eof; _test_eof13: cs = 13; goto _test_eof; _test_eof14: cs = 14; goto _test_eof; _test_eof15: cs = 15; goto _test_eof; _test_eof16: cs = 16; goto _test_eof; _test_eof17: cs = 17; goto _test_eof; _test_eof18: cs = 18; goto _test_eof; _test_eof19: cs = 19; goto _test_eof; _test_eof20: cs = 20; goto _test_eof; _test_eof21: cs = 21; goto _test_eof; _test_eof22: cs = 22; goto _test_eof; _test_eof23: cs = 23; goto _test_eof; _test_eof24: cs = 24; goto _test_eof; _test_eof25: cs = 25; goto _test_eof; _test_eof26: cs = 26; goto _test_eof; _test_eof27: cs = 27; goto _test_eof; _test_eof28: cs = 28; goto _test_eof; _test_eof29: cs = 29; goto _test_eof; _test_eof30: cs = 30; goto _test_eof; _test_eof31: cs = 31; goto _test_eof; _test_eof32: cs = 32; goto _test_eof; _test_eof33: cs = 33; goto _test_eof; _test_eof34: cs = 34; goto _test_eof; _test_eof35: cs = 35; goto _test_eof; _test_eof36: cs = 36; goto _test_eof; _test_eof37: cs = 37; goto _test_eof; _test_eof38: cs = 38; goto _test_eof; _test_eof39: cs = 39; goto _test_eof; _test_eof40: cs = 40; goto _test_eof; _test_eof41: cs = 41; goto _test_eof; _test_eof42: cs = 42; goto _test_eof; _test_eof: {} if ( p == eof ) { switch ( cs ) { case 14: case 36: #line 167 "src/chunked_parser.rl" { err_ctx = "CRLF"; } break; case 25: #line 176 "src/chunked_parser.rl" { err_ctx = "chunk_data"; } break; case 26: case 27: #line 180 "src/chunked_parser.rl" { err_ctx = "chunk_data_terminator"; } break; case 29: case 30: case 32: case 33: case 37: case 39: case 40: case 42: #line 220 "src/chunked_parser.rl" { err_ctx = "chunk_ext"; } break; case 2: case 3: case 8: case 9: case 11: case 15: case 17: case 18: case 20: #line 226 "src/chunked_parser.rl" { err_ctx = "last_chunk"; } break; case 23: #line 167 "src/chunked_parser.rl" { err_ctx = "CRLF"; } #line 220 "src/chunked_parser.rl" { err_ctx = "chunk_ext"; } break; case 4: #line 167 "src/chunked_parser.rl" { err_ctx = "CRLF"; } #line 226 "src/chunked_parser.rl" { err_ctx = "last_chunk"; } break; case 6: #line 167 "src/chunked_parser.rl" { err_ctx = "CRLF"; } #line 230 "src/chunked_parser.rl" { err_ctx = "parser"; } break; case 21: case 22: #line 217 "src/chunked_parser.rl" { err_ctx = "chunk_size"; } #line 220 "src/chunked_parser.rl" { err_ctx = "chunk_ext"; } break; case 24: #line 167 "src/chunked_parser.rl" { err_ctx = "CRLF"; } #line 220 "src/chunked_parser.rl" { err_ctx = "chunk_ext"; } #line 176 "src/chunked_parser.rl" { err_ctx = "chunk_data"; } break; case 5: #line 167 "src/chunked_parser.rl" { err_ctx = "CRLF"; } #line 226 "src/chunked_parser.rl" { err_ctx = "last_chunk"; } #line 230 "src/chunked_parser.rl" { err_ctx = "parser"; } break; #line 1276 "src/chunked_parser.c" } } _out: {} } #line 238 "src/chunked_parser.rl" ctx->parser_state = cs; *pos_addr = (u_char *) p; if (p != pe) { dd("ASSERTION FAILED: p != pe"); } if (done) { return NGX_OK; } if (cs == chunked_error) { #if EXTENDED_DEBUG ngx_str_t headers_buf, preread_buf; #endif for (post.data = (u_char *) p, post.len = 0; post.data + post.len != (u_char *) pe; post.len++) { if (post.len >= POST_TEXT_LEN) { break; } } for (pre.data = (u_char *) p, pre.len = 0; pre.data != (u_char *) pos; pre.data--, pre.len++) { if (pre.len >= PRE_TEXT_LEN) { break; } } if (r->headers_in.user_agent) { user_agent = r->headers_in.user_agent->value; } #if EXTENDED_DEBUG headers_buf.data = r->header_in->start; headers_buf.len = ctx->saved_header_in_pos - r->header_in->start; if (strcmp(caller_info, "preread") == 0) { preread_buf.data = (u_char *) pos; preread_buf.len = pe - pos; } else { preread_buf.data = ctx->saved_header_in_pos; preread_buf.len = r->header_in->pos - ctx->saved_header_in_pos; } #endif ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "bad chunked body (buf size %O, buf offset %O, " "total decoded %uz, chunks count %d, " "chunk size %uz, chunk data read %uz, " "total to disk %uz, " "raw body size %O, caller \"%s\", " "plain_http %d, " #if (NGX_HTTP_SSL) "ssl %d, " #endif "keepalive %d, err ctx \"%s\", " "ctx ref count %ud, user agent \"%V\", " #if EXTENDED_DEBUG "headers \"%V\", preread \"%V\", " #endif "at char '%c' (%d), " "near \"%V <-- HERE %V\", marked by \" <-- HERE \").\n", (off_t) (pe - pos), (off_t) (p - pos), ctx->chunks_total_size, ctx->chunks_count, ctx->chunk_size, ctx->chunk_bytes_read, ctx->chunks_written_size, (off_t) ctx->raw_body_size, caller_info, (int) r->plain_http, #if (NGX_HTTP_SSL) r->connection->ssl ? 1 : 0, #endif (int) r->keepalive, err_ctx, ctx->count, &user_agent, #if EXTENDED_DEBUG &headers_buf, &preread_buf, #endif *p, *p, &pre, &post); return NGX_ERROR; } return NGX_AGAIN; }