nginx / unit

NGINX Unit - universal web app server - a lightweight and versatile open source server that simplifies the application stack by natively executing application code across eight different programming language runtimes.
https://unit.nginx.org
Apache License 2.0
5.37k stars 323 forks source link

Rewrite URI into request arguments #992

Open l2dy opened 11 months ago

l2dy commented 11 months ago

I'm trying to configure Unit for Phabricator, which requires rewriting the URI into a request argument __path__ and keeping the previous request arguments.

In Nginx, this can be implemented with rewrite ^/(.*)$ /index.php?__path__=/$1 last;, but Unit does not support it.

See also #732.

hongzhidao commented 11 months ago

Hi, Take a look at this https://github.com/nginx/unit/issues/732#issuecomment-1621044391.

You might write the configuration like:

-- deleted --
{
  "match": {
    "uri": "~^(?<some_var>.*)$"
  },
  "action": {
     "set": {
        "args": "/index.php?__path__=/$some_var"
      }
  }
}

Unit now doesn't support custom variables from regexp with the rewrite option. We will support it in the 1.33 version. On the 1.32 currently.

l2dy commented 11 months ago

You might write the configuration like:

{
  "match": {
    "uri": "~^(?<some_var>.*)$"
  },
  "action": {
    "rewrite": "/index.php?__path__=/$some_var"
  }
}

The previous request arguments are appended after a ?. In this case, there will be two ? in the rewritten URI.

https://github.com/nginx/unit/blob/822303e23cb489efdc4fa3ca321f8468a2dd17fa/src/nxt_http_rewrite.c#L91-L93

Nginx handles this by appending a & instead of ? in ngx_http_script.c.

hongzhidao commented 11 months ago

Sorry, I used the wrong configuration.

https://unit.nginx.org/configuration/#uri-rewrite

It does not affect the query but changes the uri and $request_uri variables.

And we have an idea of how to change the query, but it's not clear yet. It's a topic of updating variables, like:

{
  "match": {
    "uri": "~^(?<some_var>.*)$"
  },
  "action": {
     "set": {
        "args": "/index.php?__path__=/$some_var"
      }
  }
}

Anyway, we need to support custom variables with the captured regexp names. Welcome to your suggestions on it.

l2dy commented 11 months ago

The syntax looks OK, except that I don't think ~ is needed (unless it's part of syntax to enable regex).

You will need to consider what to do with the previous request arguments (i.e. existing arguments before the rewrite). Nginx has a "putting a question mark at the end of a replacement string" way of configuring it, but it's a bit too obscure.

hongzhidao commented 11 months ago

Actually, in nginx, you also can set $args variables to change the request query.

You will need to consider what to do with the previous request arguments

We intend to make the usage as concise as possible, and nginx's way is more powerful with more rules. As you showed in the source code, the rewrite in nginx is very powerful with more code lines.

tippexs commented 10 months ago

@hongzhidao as we have worked on https://github.com/nginx/unit/issues/916 we made use of njs in the rewrite part with some great success in terms of regexs. For example

{
"action": {
                "rewrite": "`${uri.replace(/^(\\/[^\\/]+)?(\\/.*\\.php)/, '$2')}`",
                "share": "/sites/$host$uri",
                "fallback": {
                    "pass": "applications/$host/index"
                }
            }
}

In this example we are using matching blocks of the regext to build a new URI. Coulnd't this help in this case?

hongzhidao commented 10 months ago

It looks like the case is related to how to change/rewrite the request query/arguments. And the rewrite option only affects the uri.

tippexs commented 10 months ago

Okay then scratch that. Let's think about enhancing the rewrite support and what release is a good fit for that.

hongzhidao commented 10 months ago

https://nginx.org/en/docs/http/ngx_http_rewrite_module.html

If a replacement string includes the new request arguments, the previous request arguments are appended after them. If this is undesired, putting a question mark at the end of a replacement string avoids having them appended, for example:

I would say the rule is complicated, It has advantages and disadvantages in terms of use and implementation cost.