nginxをリバースプロキシとして使用しており、次のような2つのルールがあります。
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;
}
ご覧のとおり、プロキシされたページに$uri
変数をパラメータとして渡しています($uri
変数はnginx変数です。 http core module
を参照してください)。 =ドキュメント)。
問題は、http://example.com/foobar/hello%20world
にアクセスすると、$uri
変数に/foobar/hello world
が含まれていることです(ご覧のとおり、%20
はURLデコードされた値であるスペースに置き換えられています)。そして、nginxは、proxy_pass行を実行する前にhttpステータスコード400(不正なリクエスト)を返します(そこに接続されているバックエンドはありません)。
変数$request_uri
も使用できます。これは、クライアントによって発行された元の要求URIを保持するため、この場合は%20
シーケンスで正しい値を保持します。しかし、クライアントが/indirect
パスを通過する場合、$request_uri
には/indirect/...
が含まれるため、これを使用することはできませんが、バックエンドに渡されるaccess
パラメータは常に/foobar/...
。
複数のindirect
に似たルールがあります(これはDAV/calDAV/cardDAVサーバー用であり、複数のパスに接続する複数のクライアントがそこにあるため、これらのindirect
に似たルールが必要です)、そこでproxy_pass
を実行することは現実的ではなく、/foobar
パスに直接アクセスするクライアントがあります。
それで、URLデコードせずに$uri
を取得する方法はありますか?
受け入れられない可能性のあること:
nginx/1.2.1
では、%20
の問題を再現できませんでした。スペースにデコードすると、nginx内で 400 Bad Request
が発生します。おそらくそれは上流から来ているのでしょうか?
とにかく、実際に rewrite
ディレクティブを介して提供される有限状態オートマトンを使用して、デコードされた要求が$uri
に含まれないようにしながらも、リクエストのあらゆる種類の変換。
アイデアは、$uri
を適切に変更しても、再デコードされないことです。そして、ご存知のように、デコードされていないものは$request_uri
に既にあります。あとは、一方を他方に設定し、それを1日と呼ぶだけです。
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;
}
そして、はい、上のrewrite ^ $request_uri;
の部分でうまくいきます:
% 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
%
(「直接」のものもデコードされないようにしたい場合は、「間接」にすることもおそらく最も簡単です。)
私が見つけた唯一の方法は、 HttpSetMiscModule を使用することです:
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;
}
誰かがより良い方法を知っている場合(ルートアクセス権がないため、外部モジュールでnginxをコンパイルする必要はありません)、私に知らせてください!