79

How do you determine when to use $request_uri vs $uri?

According to NGINX documentation, $request_uri is the original request (for example, /foo/bar.php?arg=baz includes arguments and can't be modified) but $uri refers to the altered URI.

If the URI doesn't change, does $uri = $request_uri?

Would it be incorrect or better or worse to use:

map $uri $new_uri {
  # do something
}

vs

map $request_uri $new_uri {
  # do something
}
teknova
  • 857
  • 1
  • 6
  • 12

2 Answers2

132

$uri is not equivalent to $request_uri.

The $uri variable is set to the URI that nginx is currently processing - but it is also subject to normalisation, including:

  • Removal of the ? and query string
  • Consecutive / characters are replace by a single /
  • URL encoded characters are decoded

The value of $request_uri is always the original URI and is not subject to any of the above normalisations.

Most of the time you would use $uri, because it is normalised. Using $request_uri in the wrong place can cause URL encoded characters to become doubly encoded.

Use $request_uri in a map directive, if you need to match the URI and its query string.

Richard Smith
  • 45,711
  • 6
  • 82
  • 81
  • 47
    Also, using `$uri` accidentally in `proxy_pass` directives opens you up to http header injection vulnerabilities. Always use `$request_uri` in proxy_pass. – fotinakis Aug 28 '18 at 17:00
  • 4
    @fotinakis, could you give an example of such injection? I can't really imagine a single scenario. – Victor Schröder Oct 04 '18 at 10:56
  • 13
    @VictorSchröder say `/static/*` is proxy_pass'd to a different destination, but accidentally uses `$uri` instead of `$request_uri`. You could navigate to `/static/X%20HTTP/1.1%0d%0aHost:hijacked-host-header%0d%0a%0d%0a` and the `Host:hijacked-host-header` header will get injected. – fotinakis Oct 04 '18 at 14:10
  • @fotinakis, so this would trigger a secondary request to the proxied host with a manipulated `Host` header? Interesting. Thanks! – Victor Schröder Oct 04 '18 at 15:53
  • 2
    @fotinakis can you fix this by setting `proxy_pass_request_headers off;` – igor Sep 26 '19 at 15:39
20

Another difference about $uri and $request_uri in proxy_cache_key is $request_uri will include anchor tags part, but $uri$is_args$args will ignore it

Do a curl operation : curl -I static.io/hello.htm?id=1#/favor/goods :

proxy_cache_key $scheme://$host$uri$is_args$args; => Cache KEY: http://static.io/hello.htm?id=1
proxy_cache_key $scheme://$host$request_uri; => Cache KEY: http://static.io/hello.htm?id=1#/favor/goods

Nginx Document: http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_uri

  • $request_uri : full original request URI (with arguments)
  • $uri: current URI in request, normalized The value of $uri may change during request processing, e.g. when doing internal redirects, or when using index files.

Proxy Cache key: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_key

lupguo
  • 1,525
  • 13
  • 13
  • 20
    No browser I know of sends the fragment identifier to the server: faqs.org/rfcs/rfc1808.html 2.4.1. Parsing the Fragment Identifier – DRC Jan 17 '20 at 18:11
  • 1
    Interesting, I haven't tested it yet but these guys say exactly the opposite, that **request_uri** does *not* include anchors: https://www.webhosting24.com/understanding-nginx-request_uri/ – Lethargos Sep 26 '21 at 20:49
  • https://serverfault.com/questions/901331/nginx-redirect-rule-with-a-anchor-tag says: "nginx never receives the part after # in the HTTP request, it is purely a HTTP client (browser) side concept. This means that the following regexp will match both /view-price-range.php#mytag and /view-price-range.php#mytag" – r3code Feb 15 '23 at 12:41