static ngx_int_t
ngx_http_eval_handler(ngx_http_request_t *r)
{
    size_t                      loc_len;
    ngx_str_t                   args; 
    ngx_str_t                   subrequest_uri;
    ngx_uint_t                  flags;
    ngx_http_core_loc_conf_t   *clcf;
    ngx_http_eval_loc_conf_t   *ecf;
    ngx_http_eval_ctx_t        *ctx;
    ngx_http_request_t         *sr; 
    ngx_int_t                   rc;
    ngx_http_post_subrequest_t *psr;
    ngx_http_eval_block_t      *block;
    u_char                     *p;

    if(r != r->main && r->uri.len > 6 && r->uri.data[0] == '/' && r->uri.data[1] == 'e'
        && r->uri.data[2] == 'v' && r->uri.data[3] == 'a' && r->uri.data[4] == 'l'
        && r->uri.data[5] == '_')
    {
        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

        loc_len = r->valid_location ? clcf->name.len : 0;

        if(r->uri.len != loc_len) {
            r->uri.data += loc_len;
            r->uri.len -= loc_len;
        }
        else {
            r->uri.len = 1;
        }
    }

    ecf = ngx_http_get_module_loc_conf(r, ngx_http_eval_module);

    if(ecf->blocks == NULL || !ecf->blocks->nelts) {
        return NGX_DECLINED;
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_eval_module);

    if(ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t));
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ctx->base_conf = ecf;

        ctx->current_block = ecf->blocks->elts;
        ctx->last_block = ctx->current_block + ecf->blocks->nelts - 1;

        ngx_http_set_ctx(r, ctx, ngx_http_eval_module);
    }

    if(ctx->done) {
        ctx->in_progress = 0;

        if(ctx->current_block == ctx->last_block) {
            if(!ecf->escalate || ctx->status == NGX_OK || ctx->status == NGX_HTTP_OK) {
                return NGX_DECLINED;
            }

            return ctx->status;
        }

        ctx->current_block++;
    }

    if(ctx->in_progress) {
#if defined nginx_version && nginx_version >= 8042
        return NGX_DONE;
#else
        return NGX_AGAIN;
#endif
    }

    /*
     * Advance to block which has at least one variable
     */
    while(ctx->current_block->variables == NULL || ctx->current_block->variables->nelts == 0) {
        if(ctx->current_block == ctx->last_block) {
            return NGX_DECLINED;
        }

        ctx->current_block++;
    }

    block = ctx->current_block;

    psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
    if (psr == NULL) {
        return NGX_ERROR;
    }

    if(ngx_http_eval_init_variables(r, ctx, block) != NGX_OK) {
        return NGX_ERROR;
    }

    args.len = r->args.len;
    args.data = r->args.data;
    flags = 0;

    subrequest_uri.len = block->eval_location.len + r->uri.len;

    p = subrequest_uri.data = ngx_palloc(r->pool, subrequest_uri.len);

    if(p == NULL) {
        return NGX_ERROR;
    }

    p = ngx_copy(p, block->eval_location.data, block->eval_location.len);
    p = ngx_copy(p, r->uri.data, r->uri.len);

    if (ngx_http_parse_unsafe_uri(r, &subrequest_uri, &args, &flags) != NGX_OK) {
        return NGX_ERROR;
    }

    psr->handler = ngx_http_eval_post_subrequest_handler;
    psr->data = ctx;

    flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY|NGX_HTTP_SUBREQUEST_WAITED;

    rc = ngx_http_subrequest(r, &subrequest_uri, &args, &sr, psr, flags);

    if (rc == NGX_ERROR || rc == NGX_DONE) {
        return rc;
    }

    /*
     * create a fake request body instead of discarding the real one
     * in order to avoid attempts to read it
     */
    sr->request_body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
    if (sr->request_body == NULL) {
        return NGX_ERROR;
    }

    ctx->in_progress = 1;
    ctx->done = 0;

    /*
     * Wait for subrequest to complete
     */

#if defined nginx_version && nginx_version >= 8042
    return NGX_DONE;
#else
    return NGX_AGAIN;
#endif
}
static ngx_int_t
ngx_http_eval_handler(ngx_http_request_t *r)
{
    size_t                      loc_len;
    ngx_str_t                   args; 
    ngx_str_t                   subrequest_uri;
    ngx_uint_t                  flags;
    ngx_http_core_loc_conf_t   *clcf;
    ngx_http_eval_loc_conf_t   *ecf;
    ngx_http_eval_ctx_t        *ctx;
    ngx_http_request_t         *sr; 
    ngx_int_t                   rc;
    ngx_http_post_subrequest_t *psr;
    u_char                     *p;

    if(r != r->main && ngx_memn2cmp(r->uri.data, "/eval_", r->uri.len, 6 - 1) == 0) {
        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

        loc_len = r->valid_location ? clcf->name.len : 0;

        if(r->uri.len != loc_len) {
            r->uri.data += loc_len;
            r->uri.len -= loc_len;
        }
        else {
            r->uri.len = 1;
        }
    }

    ecf = ngx_http_get_module_loc_conf(r, ngx_http_eval_module);

    if(ecf->variables == NULL || !ecf->variables->nelts) {
        return NGX_DECLINED;
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_eval_module);

    if(ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t));
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ctx->base_conf = ecf;

        ngx_http_set_ctx(r, ctx, ngx_http_eval_module);
    }

    if(ctx->done) {
        if(!ecf->escalate || ctx->status == NGX_OK || ctx->status == NGX_HTTP_OK) {
            return NGX_DECLINED;
        }

        return ctx->status;
    }

    if(ctx->in_progress) {
        return NGX_AGAIN;
    }

    psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
    if (psr == NULL) {
        return NGX_ERROR;
    }

    if(ngx_http_eval_init_variables(r, ctx, ecf) != NGX_OK) {
        return NGX_ERROR;
    }

    args.len = 0;
    args.data = NULL;
    flags = 0;

    subrequest_uri.len = ecf->eval_location.len + r->uri.len;

    p = subrequest_uri.data = ngx_palloc(r->pool, subrequest_uri.len);

    if(p == NULL) {
        return NGX_ERROR;
    }

    p = ngx_copy(p, ecf->eval_location.data, ecf->eval_location.len);
    p = ngx_copy(p, r->uri.data, r->uri.len);

    if (ngx_http_parse_unsafe_uri(r, &subrequest_uri, &args, &flags) != NGX_OK) {
        return NGX_ERROR;
    }

    psr->handler = ngx_http_eval_post_subrequest_handler;
    psr->data = ctx;

    flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY|NGX_HTTP_SUBREQUEST_WAITED;

    rc = ngx_http_subrequest(r, &subrequest_uri, &args, &sr, psr, flags);

    if (rc == NGX_ERROR || rc == NGX_DONE) {
        return rc;
    }

    sr->discard_body = 1;

    ctx->in_progress = 1;

    /*
     * Wait for subrequest to complete
     */
    return NGX_AGAIN;
}
static ngx_int_t
ngx_http_eval_handler(ngx_http_request_t *r)
{
    /* size_t                      loc_len; */
    ngx_str_t                   args;
    ngx_str_t                   subrequest_uri;
    ngx_uint_t                  flags;
    /* ngx_http_core_loc_conf_t   *clcf; */
    ngx_http_eval_loc_conf_t   *ecf;
    ngx_http_eval_ctx_t        *ctx;
    ngx_http_eval_ctx_t        *sr_ctx;
    ngx_http_request_t         *sr;
    ngx_int_t                   rc;
    ngx_http_post_subrequest_t *psr;
    u_char                     *p;

    /*
    if(r != r->main) {
        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

        loc_len = r->valid_location ? clcf->name.len : 0;

        if(r->uri.len != loc_len) {
            r->uri.data += loc_len;
            r->uri.len -= loc_len;
        }
        else {
            r->uri.len = 1;
        }
    }
    */

    ecf = ngx_http_get_module_loc_conf(r, ngx_http_eval_module);

    if(ecf->variables == NULL || !ecf->variables->nelts) {
        return NGX_DECLINED;
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_eval_module);

    if(ctx == NULL) {
        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t));
        if (ctx == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ctx->base_conf = ecf;

        ngx_http_set_ctx(r, ctx, ngx_http_eval_module);
    }

    if (ctx->done) {
        dd("subrequest done");
        if(!ecf->escalate || ctx->status == NGX_OK || ctx->status == NGX_HTTP_OK) {
            return NGX_DECLINED;
        }

        dd("status: %d", (int) ctx->status);

        return ctx->status;
    }

    if (ctx->in_progress) {
        dd("still in progress");
        return NGX_DONE;
    }

    psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
    if (psr == NULL) {
        return NGX_ERROR;
    }

    if(ngx_http_eval_init_variables(r, ctx, ecf) != NGX_OK) {
        return NGX_ERROR;
    }

    args = r->args;
    flags = 0;

    subrequest_uri.len = ecf->eval_location.len + r->uri.len;

    p = subrequest_uri.data = ngx_palloc(r->pool, subrequest_uri.len);

    if(p == NULL) {
        return NGX_ERROR;
    }

    p = ngx_copy(p, ecf->eval_location.data, ecf->eval_location.len);
    p = ngx_copy(p, r->uri.data, r->uri.len);

    if (ngx_http_parse_unsafe_uri(r, &subrequest_uri, &args, &flags) != NGX_OK) {
        return NGX_ERROR;
    }

    psr->handler = ngx_http_eval_post_subrequest_handler;
    psr->data = ctx;

    flags |= NGX_HTTP_SUBREQUEST_WAITED;

    dd("subrequest in memory : %d", (int) ecf->subrequest_in_memory);

    if (ecf->subrequest_in_memory) {
        flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY;
    } else {
    }

    dd("issue subrequest");

    rc = ngx_http_subrequest(r, &subrequest_uri, &args, &sr, psr, flags);

    if (rc == NGX_ERROR || rc == NGX_DONE) {
        return rc;
    }

    sr->discard_body = 1;

    ctx->in_progress = 1;

    /* XXX we don't allow eval in subrequests, i think? */
    sr_ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_eval_ctx_t));
    if (sr_ctx == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ngx_http_set_ctx(sr, sr_ctx, ngx_http_eval_module);

    dd("wait for subrequest to complete");

    return NGX_DONE;
}