Apacheと%2Fでを調べると沢山出てくる内容なのですが、ApacheはURLから取得されるPATH_INFO変数に /
のエンコードである %2F
があると404を返します。
これ自体はAllowEncodedSlashesというパラメータをOnにしてやると処理できるようになります。
<VirtalHost> ... AllowEncodedSlashes on ... </VirtalHost>
AllowEncodedSlashes off
%2F
は404エラーAllowEncodedSlashes on
%2F
は/
にデコード
これですが、デコードしないで後ろのWEBサーバに渡して欲しいという要件に合う選択肢がありません。これが一つのハマりポイントでした。
今書いている時点では日本語のマニュアルにはこの二つのオプションまでしか書かれていないのですが、英語にマニュアル見るともう一つ NoDecode
というオプションがあります。
AllowEncodedSlashes On|Off|NoDecode http://httpd.apache.org/docs/2.4/en/mod/core.html#allowencodedslashes
これを使うことで %2F
がデコードされないで後ろの処理に渡されます。この3パターンが設定可能です。
static const char *set_allow2f(cmd_parms *cmd, void *d_, const char *arg) { core_dir_config *d = d_; if (0 == strcasecmp(arg, "on")) { d->allow_encoded_slashes = 1; d->decode_encoded_slashes = 1; /* for compatibility with 2.0 & 2.2 */ } else if (0 == strcasecmp(arg, "off")) { d->allow_encoded_slashes = 0; d->decode_encoded_slashes = 0; } else if (0 == strcasecmp(arg, "nodecode")) { d->allow_encoded_slashes = 1; d->decode_encoded_slashes = 0; } else { return apr_pstrcat(cmd->pool, cmd->cmd->name, " must be On, Off, or NoDecode", NULL); } return NULL; }
https://github.com/apache/httpd/blob/2.4.29/server/core.c#L3066-L3085
これで解決かと思ったのですが今度は %252F
という文字が渡されるようになりました。
これは %2F
を更にエンコードしたものになります。せっかく NoDecode
オプションつけて生データを渡そうとしているので、誰がエンコードしてるんだと調べたところ、 mod_proxy
でエンコードされているということがわかりました。これがもう一つのハマりポイントです。
apache2 - Need to allow encoded slashes on Apache - Stack Overflow
回避するには参考URLにあるように以下のように設定します。
ProxyPass http://backendserver:8080/example/ nocanon
マニュアルにも以下のように記載があります。
Normally, mod_proxy will canonicalise ProxyPassed URLs. But this may be incompatible with some backends, particularly those that make use of PATH_INFO. The optional nocanon keyword suppresses this and passes the URL path "raw" to the backend. https://httpd.apache.org/docs/current/en/mod/mod_proxy.html#proxypass
手元の環境では ProxyPass
ではなくRewriteRule
ディレクティブの P
フラグでProxyPassと同等のことを実装していたので、そちらにも同じもの無いか探したら NE
フラグというのがあり、こちらを利用すれば同じこと実現できます。
RewriteRule ^(.*) http://backendserver:8080/example/$1 [P,NE]