nginx $ uri é url decodificado

6

Estou usando nginx como proxy reverso e tenho 2 regras como:

location ~ ^/indirect {
  rewrite ^/indirect(.*) /foobar$1;
}

location ~ ^/foobar {
  set $url http://example.com/something/index.php?var1=hello&access=$scheme://$host$uri;
  proxy_pass $url;
}

Então, como você pode ver, estou passando a variável $uri como um parâmetro para a página com proxy (a variável $uri é nginx, veja o http core module documentação).

O problema é que, se eu visitar http://example.com/foobar/hello%20world , a variável $uri contém /foobar/hello world (como você pode ver, o %20 foi substituído por seu valor decodificado url, um espaço). E, em seguida, o nginx retorna o código de status http 400 (solicitação incorreta) antes de executar a linha proxy_pass (o backend não é contatado).

Também está disponível a variável $request_uri , que mantém o URI de solicitação original como emitido pelo cliente, portanto, nesse caso, ele manteria o valor correto, com a sequência %20 . Mas eu não posso usar isso porque se um cliente passar pelo caminho /indirect , $request_uri conteria /indirect/... enquanto eu quero que o access param passado para o backend seja sempre /foobar/... .

Existem várias regras parecidas com indirect (isso é para um servidor DAV / calDAV / cardDAV e há vários clientes que se conectam a vários caminhos, então eu preciso dessas regras parecidas com indirect ), não é possível fazer o proxy_pass , e há clientes que vão diretamente para o caminho /foobar .

Então, existe alguma maneira de obter $uri sem decodificá-lo?

possíveis coisas que não são aceitáveis:

  • enviando a solicitação com codificação dupla, pois a solicitação pode vir de um cliente sem controle
  • especificando o URL final várias vezes em uma regra indireta e também na URL "direta", pois causa problemas de manutenção.
por Carlos Campderrós 05.11.2012 / 15:24

2 respostas

1

A única maneira que encontrei é usar o HttpSetMiscModule da seguinte forma:

location ~
 ^/indirect {
  set_escape_uri $key $1;
  rewrite ^/indirect(.*) /foobar$key;
}

location ~ ^/foobar {
  set_escape_uri $key $uri;
  set $url http://example.com/something/index.php?var1=hello&access=$scheme://$host$key;
  proxy_pass $url;
}

Se alguém souber de uma maneira melhor (sem precisar compilar o nginx com módulos externos, porque eu não tenho acesso root) por favor me avise!

    
por 28.07.2015 / 14:05
1

Com nginx/1.2.1 , não consegui reproduzir seu problema de %20 , uma vez decodificado em um espaço, de causar qualquer 400 Bad Request dentro do nginx; talvez seja proveniente do upstream?

Independentemente disso, na verdade não é tão difícil usar o autômato de estado finito fornecido pela diretiva rewrite para Pare de $uri de conter a solicitação decodificada, mas ainda assim execute todos os tipos de transformações da solicitação.

link

A ideia é que quando você altera $uri no lugar, ele não é re-decodificado. E, como você sabe, já temos o código não codificado em $request_uri . O que resta é simplesmente definir um para o outro e chamá-lo por um dia.

server {
    listen 2012;
    location /a {
        rewrite ^/a(.*) /f$1 last;
    }
    location /i {
        rewrite ^ $request_uri;
        rewrite ^/i(.*) /f$1 last;
        return 400; #if the second rewrite won't match
    }
    location /f {
        set $url http://127.0.0.1:2016/s?v=h&a=$scheme://$host$uri;
        proxy_pass $url;
    }
}

server {
    listen 2016;
    return 200 $request_uri\n;
}

E, sim, a parte rewrite ^ $request_uri; acima faz o truque:

% echo localhost:2012/{a,i,f}/h%20w | xargs -n1 curl
/s?v=h&a=http://localhost/f/h w
/s?v=h&a=http://localhost/f/h%20w
/s?v=h&a=http://localhost/f/h w
%

(Se você quiser que a coisa "direta" não seja decodificada, então provavelmente será mais fácil apenas torná-la "indireta" também.)

    
por 03.06.2016 / 10:44