Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nginx - encoding (normalizing) part of URI

Tags:

nginx

I have nginx location directive which purpose is to "remove" localization prefix from the URI for the proxy_pass directive.

For example, to make URI http://example.com/en/lalala use proxy_pass http://example.com/lalala

location ~ '^/(?<locale>[\w]{2})(/(?<rest>.*))?$' {
        ...
        proxy_pass http://example/$rest;
        ...
}

This way the rest variable will be decoded when passed to proxy_pass directeve. It seems to be an expected behavior.

The problem is when my URI contains encoded space %20 passed from client

http://example.com/lala%20lala

nginx decodes URI to

http://example.com/lala lala

I can see it in my error.log.

The question is - is it possible do use encoded rest variable somehow as it is passed from client? If I am doing something completely wrong, please, suggest the right way.

Thank you.

like image 743
Viktor Kireev Avatar asked Jul 07 '15 10:07

Viktor Kireev


3 Answers

I have had some success using the following with Confluence and other Atlassian applications behind nginx where special characters such as ( ) < > [ ] were causing issues.

location /path {
  # [... other proxy options ...]

  # set proxy path with regex
  if ($request_uri ~* "/path(/.*)") { 
    proxy_pass http://server:port/path$1;
    break;
  }

  # fallback (probably not needed)
  proxy_pass http://server:port/path;
}
like image 104
BinaryConstruct Avatar answered Oct 08 '22 00:10

BinaryConstruct


Yes, this behaviour is expected although docs also say:

If proxy_pass is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed, or the full normalized request URI is passed when processing the changed URI:

location /some/path/ {
    proxy_pass http://127.0.0.1;
}

Nginx engineers say the same: https://serverfault.com/questions/459369/disabling-url-decoding-in-nginx-proxy

However if you append $request_uri to proxy_pass (and strip locale beforehand it may work as said by Nginx engineer):

set $modified_uri $request_uri;

if ($modified_uri ~ "^/([\w]{2})(/.*)") {
set $modified_uri $1;
}

proxy_pass http://example$modified_uri;
like image 39
Anatoly Avatar answered Oct 07 '22 22:10

Anatoly


The set directive can do the trick. It keeps the encoding intact or rather encodes decoded string.

location ~ '^/(?<locale>[\w]{2})(/(?<rest>.*))?$' {
        ...
        set $encoded_rest $rest
        proxy_pass http://example/$encoded_rest;
        ...
}
like image 1
Manojkumar Khotele Avatar answered Oct 07 '22 22:10

Manojkumar Khotele