ngx_int_t
ngx_http_set_misc_unescape_uri(ngx_http_request_t *r, ngx_str_t *res,
    ngx_http_variable_value_t *v)
{
    size_t                   len;
    u_char                  *p;
    u_char                  *src, *dst;

    /* the unescaped string can only be smaller */
    len = v->len;

    p = ngx_palloc(r->pool, len);
    if (p == NULL) {
        return NGX_ERROR;
    }

    src = v->data; dst = p;

    ngx_unescape_uri_patched(&dst, &src, v->len, NGX_UNESCAPE_URI_COMPONENT);

    if (src != v->data + v->len) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                "set_unescape_uri: input data not consumed completely");
        return NGX_ERROR;
    }

    res->data = p;
    res->len = dst - p;

    return NGX_OK;
}
static ngx_int_t
ngx_http_eval_parse_param(ngx_http_request_t *r, ngx_http_eval_ctx_t *ctx, ngx_str_t *param) {
    u_char                    *p, *src, *dst;

    ngx_str_t                  name;
    ngx_str_t                  value;

    p = (u_char *) ngx_strchr(param->data, '=');

    if(p == NULL) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "eval: invalid param \"%V\"", param);
        return NGX_ERROR;
    }

    name.data = param->data;
    name.len = p - param->data;

    value.data = p + 1;
    value.len = param->len - (p - param->data) - 1;

    src = dst = value.data;

    ngx_unescape_uri_patched(&dst, &src, value.len, NGX_UNESCAPE_URI);

    value.len = dst - value.data;

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "eval param: \"%V\"=\"%V\"", &name, &value);

    return ngx_http_eval_set_variable_value(r, ctx, &name, &value);
}