static ngx_int_t
ngx_http_mogilefs_eval_class(ngx_http_request_t *r, ngx_http_mogilefs_loc_conf_t *mgcf)
{
    ngx_uint_t                           i;
    ngx_http_mogilefs_class_template_t  *t;
    ngx_str_t                            class;

    if(mgcf->class_templates == NULL) {
        return NGX_DECLINED;
    }

    t = mgcf->class_templates->elts;

    for(i = 0;i < mgcf->class_templates->nelts;i++) {
        if(t->lengths != NULL && t->values != NULL) {
            if(ngx_http_script_run(r, &class, t->lengths->elts, 0,
                                    t->values->elts)
                == NULL)
            {
                return NGX_ERROR;
            }
        }
        else {
            if(ngx_http_mogilefs_add_aux_param(r, &ngx_http_mogilefs_class, &t->source) != NGX_OK) {
                return NGX_ERROR;
            }

            return NGX_OK;
        }

        if(class.len) {
            if(ngx_http_mogilefs_add_aux_param(r, &ngx_http_mogilefs_class, &class) != NGX_OK) {
                return NGX_ERROR;
            }

            return NGX_OK;
        }

        t++;
    }
static ngx_int_t
ngx_http_mogilefs_put_handler(ngx_http_request_t *r)
{
    ngx_http_mogilefs_put_ctx_t        *ctx;
    ngx_str_t                           args; 
    ngx_uint_t                          flags;
    ngx_http_request_t                 *sr; 
    ngx_str_t                           spare_location = ngx_null_string, uri, value;
    ngx_int_t                           rc;
    u_char                             *p;
    ngx_http_core_loc_conf_t           *clcf;
    ngx_http_mogilefs_loc_conf_t       *mgcf;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "mogilefs put handler");

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    mgcf = ngx_http_get_module_loc_conf(r, ngx_http_mogilefs_module);

    if (clcf->handler != ngx_http_mogilefs_handler ||
        (mgcf->location_type == NGX_MOGILEFS_MAIN && !(r->method & mgcf->methods)))
    {
        return NGX_DECLINED;
    }

    ctx = ngx_http_get_module_ctx(r, ngx_http_mogilefs_module);

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

        ctx->psr = NULL;
        ctx->state = START;
        ctx->status = 0;
        ctx->create_open_ctx = NULL;

        if(ngx_http_mogilefs_eval_key(r, &ctx->key) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        ngx_http_set_ctx(r, ctx, ngx_http_mogilefs_module);
    }

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

    if(r->request_body == NULL) {
        rc = ngx_http_read_client_request_body(r, ngx_http_mogilefs_body_handler);

        if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
            return rc;
        }

        return NGX_DONE;
    }

    // Still receiving body?
    if(r->request_body->rest) {
        return NGX_DONE;
    }

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "mogilefs put handler state: %ui, status: %i", ctx->state, ctx->status);

    if(ctx->state == CREATE_OPEN || ctx->state == FETCH || ctx->state == CREATE_CLOSE) {
        if(ctx->status != NGX_OK && ctx->status != NGX_HTTP_CREATED && ctx->status != NGX_HTTP_NO_CONTENT) {
            return (ctx->status >= NGX_HTTP_SPECIAL_RESPONSE) ?
                ctx->status : NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    }

    switch(ctx->state) {
        case START:
            spare_location = mgcf->create_open_spare_location;
            ctx->state = CREATE_OPEN;
            break;
        case CREATE_OPEN:
            spare_location = mgcf->fetch_location;
            ctx->state = FETCH;
            break;
        case FETCH:
            spare_location = mgcf->create_close_spare_location;
            ctx->state = CREATE_CLOSE;
            break;
        case CREATE_CLOSE:
            r->headers_out.content_length_n = 0;
            r->headers_out.status = NGX_HTTP_CREATED;

            r->header_only = 1;

            return ngx_http_send_header(r);
    }

    uri.len = spare_location.len + ctx->key.len;

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

    p = ngx_cpymem(uri.data, spare_location.data, spare_location.len);

    p = ngx_cpymem(p, ctx->key.data, ctx->key.len);

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

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

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

    flags |= NGX_HTTP_SUBREQUEST_WAITED;

    if(ctx->state == FETCH) {
        flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY;
    }

    rc = ngx_http_subrequest(r, &uri, &args, &sr, ctx->psr, flags);

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

    if(ctx->state == CREATE_CLOSE) {
        ngx_http_set_ctx(sr, ctx->create_open_ctx, ngx_http_mogilefs_module);

        value.data = ngx_palloc(r->pool, NGX_OFF_T_LEN);

        if(value.data == NULL) {
            return NGX_ERROR;
        }

        value.len = ngx_sprintf(value.data, "%O", r->headers_in.content_length_n)
            - value.data;

        if(ngx_http_mogilefs_add_aux_param(sr, &ngx_http_mogilefs_size, &value) != NGX_OK) {
            return NGX_ERROR;
        }
    }

    /*
     * Nginx closes temporary file with buffered body
     * whenever it starts sending reponse from upstream
     * and it is not doing subrequest in memory.
     *
     * Since the request body in create_open subrequest is
     * inherited from main request, it is necessary to prevent
     * nginx from closing the temporary file with request body,
     * before it could be passed to the storage node on fetch/store
     * stage.
     *
     * We do it by "hiding" the request body from nginx internals.
     */
    if(ctx->state == CREATE_OPEN) {
        sr->request_body = NULL;
    }

    sr->method = NGX_HTTP_PUT;
    sr->method_name = ngx_http_mogilefs_put_method;

    /*
     * Wait for subrequest to complete
     */
    return NGX_DONE;
}