How to get nginx to do a redirect to url-encoded query parameter How to get nginx to do a redirect to url-encoded query parameter nginx nginx

How to get nginx to do a redirect to url-encoded query parameter


Actually, proxy_pass does normalisation by default, but it only affects $uri part. Thus you only need to decode the beginning of the passed string to get it working:

  location / {    if ( $arg_redirect = '') {      return 400 "Missing redirect directive in request";    }    if ( $arg_redirect ~ (.+)%3A%2F%2F(.+) ){ # fix :// between scheme and destination      set $arg_redirect $1://$2;    }    if ( $arg_redirect ~ (.+?)%3A(.*) ){ # fix : between destination and port      set $arg_redirect $1:$2;    }    if ( $arg_redirect ~ (.+?)%2F(.*) ){ # fix / after port, the rest will be decoded by proxy_pass      set $arg_redirect $1/$2;    }    proxy_pass $arg_redirect;  }

With the above I managed to access http://localhost/?redirect=http%3A%2F%2F127.0.0.1%3A81%2Fsfoo%20something%2Fs

The solution seems dirty and the only alternative using default modules is map (even less cleaner in my opinion). I'd rather split redirect argument into pieces: scheme (http or https), destination, port, and uri. With that you would be able to construct full address without rewriting:

proxy_pass $arg_scheme://$arg_dest:$arg_port/$arg_uri


Ok, there is very weird and curious solution

server {  listen 80;  resolver x.x.x.x;  location /basepath {    if ($arg_redirect = '') {      return 400 "Missing redirect directive in request";    }    proxy_pass http://127.0.0.1:80/basepath/$arg_redirect;  }  location ~ ^/basepath/(?<proto>\w+):/(?<redir>.+)$ {    proxy_pass $proto://$redir;  }}

Nginx does not encode path with variables in proxy_pass and send it as is. So, I make $arg_* part of proxy_pass uri, send request to self and nginx will receive new request which will be decoded.

But because Nginx will clean path and replace // to / I split protocol part in regexp.

And ... I would never recommend using this solution, but it works :)


try like this and let me know if it works

  location /basepath {        if ( $arg_redirect = '') {           return 400 "Missing redirect directive in request";         }        set_unescape_uri $decodedredirect $arg_redirect;        proxy_pass $decodedredirect;        proxy_intercept_errors on;        error_page 301 302 307 = @handle_redirects;    }