1

I am trying to reverse proxy in nginx, rewriting a front end page like "/a/b?page=2" into a backend request to "/a/b%3fpage=2"

I cannot figure out how to get nginx to make reverse proxy requests which include "%3f".

With the following config:

rewrite ^/one$ /a%3fb;
rewrite ^/two$ /a?b;
rewrite ^/three$ /a\?b;
  • /one makes a backend request like GET /a%253fb HTTP/1.0
  • /two makes a backend request like GET /a?b HTTP/1.0
  • /three makes a backend request like GET /a\?b HTTP/1.0

How can I get a backend request like GET /a%3fb HTTP/1.0?

Rich
  • 15,048
  • 2
  • 66
  • 119
  • @RichardSmith I think it is distinct. The best I can find in the RFC is that you [only decode 'unreserved characters' for normalisation](https://tools.ietf.org/html/rfc3986#section-6.2.2.2), and ? is a reserved character. Certainly Chrome treats them differently, e.g. `new URL("http://www.example.com/a%3fb").pathname === '/a%3fb'` whereas `new URL("http://www.example.com/a?b").pathname === '/a'`. – Rup Apr 02 '19 at 16:12
  • 1
    It seems to be possible, but not using the `rewrite` directive. Appending the URI (or a variable containing the URI) to the `proxy_pass` directive will pass it upstream unmolested. – Richard Smith Apr 02 '19 at 16:42
  • @RichardSmith -- the difference is that "`/a/b?page=2`" has a path of "`/a/b`" and a querystring, whereas `/a/b%3fpage=2` has a path of "`/a/b%3fpage=2`" and no query string. On most webservers, the latter would serve a file named "`b?page=2`" (for filesystems that allow "?" in file names) – Rich Apr 02 '19 at 16:46
  • See also https://serverfault.com/questions/874637/nginx-reverse-proxy-with-query-parameter-modification – Rich Apr 04 '19 at 09:12
  • See also https://stackoverflow.com/questions/8130692/how-can-query-string-parameters-be-forwarded-through-a-proxy-pass-with-nginx – Rich Apr 04 '19 at 09:13

1 Answers1

1

Thanks to @Richard Smith's comment, I was able to fix this for my specific case with the following code:

location / {

  set $backend_uri $request_uri;
  if ($args ~* "page=(\d+)") {
    set $page $1;
    set $backend_uri $uri%3fpage=$1;
  }

  proxy_pass http://example.com$backend_uri;
}

I think that I might also have been able to do something more general with the lua rewrite directive, but I was unable to install mod-lua on an Amazon Linux 2 machine, see https://serverfault.com/questions/961337/how-to-install-nginx-mod-lua-on-amazon-linux-2

Rich
  • 15,048
  • 2
  • 66
  • 119