コード例 #1
0
/* 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;
}
コード例 #2
0
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;
}