リライトバルブは、Apache HTTP Serverのmod_rewriteと非常によく似た方法でURLリライト機能を実現します。
リライトバルブ
はじめに
設定
リライトバルブは、org.apache.catalina.valves.rewrite.RewriteValve
というクラス名を使用してバルブとして設定されます。
リライトバルブは、Hostに追加されるバルブとして設定できます。設定方法については、仮想サーバーのドキュメントを参照してください。リライトディレクティブを含むrewrite.config
ファイルを使用し、そのファイルはHostの設定フォルダに配置する必要があります。
また、ウェブアプリケーションのcontext.xmlにも設定できます。その場合、バルブはリライトディレクティブを含むrewrite.config
ファイルを使用し、そのファイルはウェブアプリケーションのWEB-INFフォルダに配置する必要があります。
特殊文字を含むリライトルールを使用する
リライトバルブに提示されるURLは、リクエストマッピングに使用されるURLと同じであり、リテラルな'%'
、';'
、および/または'?'
文字は%nn
形式でエンコードされます。
リテラルな'%'
、';'
、'?'
、'&'
、または'='
文字を挿入したいリライトルールは、%nn
形式で挿入する必要があります。その他の文字は、リテラル形式または%nn
形式のいずれかで挿入できます。
これにより、リライトルールで以下のことが可能になります
- リテラルな
'?'
文字を含むURLを処理すること; - クエリ文字列を追加すること;
%nn
エンコーディングと混同されることなく、リテラルな'%'
文字を挿入すること。
ディレクティブ
rewrite.configファイルには、mod_rewriteで使用されるディレクティブ、特に中心となるRewriteRuleとRewriteCondディレクティブによく似たディレクティブのリストが含まれています。#
文字で始まる行はコメントとして扱われ、無視されます。
注: このセクションは、mod_rewriteドキュメントの改訂版であり、著作権は1995-2006 The Apache Software Foundationが所有し、Apache License, Version 2.0に基づいてライセンスされています。
RewriteCond
構文: RewriteCond TestString CondPattern
RewriteCondディレクティブは、ルール条件を定義します。RewriteRuleディレクティブの前に1つ以上のRewriteCondを置くことができます。以下のルールは、URIの現在の状態がそのパターンに一致し、かつこれらの条件が満たされた場合にのみ使用されます。
TestString は、プレーンテキストに加えて、以下の展開された構造を含むことができる文字列です。
-
RewriteRule バックリファレンス: これらは、現在の
RewriteCond
条件のセットが適用されるRewriteRule
のパターンから、グループ化された部分(括弧内)へのアクセスを提供する$N
(0 <= N <= 9) の形式のバックリファレンスです。 -
RewriteCond バックリファレンス: これらは、現在の条件セットで最後にマッチした
RewriteCond
のパターンから、グループ化された部分(やはり括弧内)へのアクセスを提供する%N
(1 <= N <= 9) の形式のバックリファレンスです。 -
RewriteMap 展開: これらは
${mapname:key|default}
の形式の展開です。RewriteMapのドキュメントで詳細を参照してください。 -
サーバー変数: これらは
%{
NAME_OF_VARIABLE}
の形式の変数であり、NAME_OF_VARIABLEは以下のリストから取得された文字列になります-
HTTPヘッダー
HTTP_USER_AGENT
HTTP_REFERER
HTTP_COOKIE
HTTP_FORWARDED
HTTP_HOST
HTTP_PROXY_CONNECTION
HTTP_ACCEPT
-
接続とリクエスト
REMOTE_ADDR
REMOTE_HOST
REMOTE_PORT
REMOTE_USER
REMOTE_IDENT
REQUEST_METHOD
SCRIPT_FILENAME
REQUEST_PATH
CONTEXT_PATH
SERVLET_PATH
PATH_INFO
QUERY_STRING
AUTH_TYPE
-
サーバー内部
DOCUMENT_ROOT
SERVER_NAME
SERVER_ADDR
SERVER_PORT
SERVER_PROTOCOL
SERVER_SOFTWARE
-
日付と時刻
TIME_YEAR
TIME_MON
TIME_DAY
TIME_HOUR
TIME_MIN
TIME_SEC
TIME_WDAY
TIME
-
特殊
THE_REQUEST
REQUEST_URI
REQUEST_FILENAME
HTTPS
これらの変数はすべて、同様の名前のHTTP MIMEヘッダーとServlet APIメソッドに対応しています。ほとんどはマニュアルまたはCGI仕様の他の場所で文書化されています。リライトバルブに特有のものは以下の通りです。
REQUEST_PATH
- マッピングに使用されるフルパスに対応します。
CONTEXT_PATH
- マップされたコンテキストのパスに対応します。
SERVLET_PATH
- サーブレットパスに対応します。
THE_REQUEST
- ブラウザからサーバーに送信された完全なHTTPリクエスト行(例: 「
GET /index.html HTTP/1.1
」)。これには、ブラウザから送信された追加のヘッダーは含まれません。 REQUEST_URI
- HTTPリクエスト行で要求されたリソース。(上記の例では、「/index.html」になります。)
REQUEST_FILENAME
- リクエストに一致するファイルまたはスクリプトへの完全なローカルファイルシステムパス。
HTTPS
- 接続がSSL/TLSを使用している場合は「on」を、そうでない場合は「off」を含みます。
-
その他注意すべき点
- 変数 SCRIPT_FILENAME と REQUEST_FILENAME は同じ値を含みます。これはApacheサーバーの内部
request_rec
構造のfilename
フィールドの値です。最初の名前は一般的に知られているCGI変数名であり、2番目はREQUEST_URI(request_rec
のuri
フィールドの値を含む)の適切な対応物です。 -
variable が任意のJavaシステムプロパティである
%{ENV:variable}
も利用可能です。 -
variable がSSL環境変数の名前である
%{SSL:variable}
は、SSL_SESSION_RESUMED
、SSL_SECURE_RENEG
、SSL_COMPRESS_METHOD
、SSL_TLS_SNI
、SSL_SRP_USER
、SSL_SRP_USERINFO
、SSL_CLIENT_VERIFY
、SSL_CLIENT_SAN_OTHER_msUPN_n
、SSL_CLIENT_CERT_RFC4523_CEA
、SSL_SERVER_SAN_OTHER_dnsSRV_n
を除いて実装されています。OpenSSLが使用されている場合、SSL_SERVER_
で始まるサーバー証明書に関連する変数は利用できません。例:%{SSL:SSL_CIPHER_USEKEYSIZE}
は128
に展開される場合があります。 -
header が任意のHTTP MIMEヘッダー名である
%{HTTP:header}
は、HTTPリクエストで送信されたヘッダーの値を取得するために常に使用できます。例:%{HTTP:Proxy-Connection}
はHTTPヘッダー「Proxy-Connection:
」の値です。
CondPattern は条件パターンであり、TestString の現在のインスタンスに適用される正規表現です。TestString は、CondPattern と照合される前にまず評価されます。
注意: CondPattern は、いくつかの追加機能を持つPerl互換の正規表現です。
- パターン文字列の前に「
!
」文字(感嘆符)を付けることで、非一致パターンを指定できます。 - CondPattern にはいくつかの特殊なバリアントがあります。実際の正規表現文字列の代わりに、以下のいずれかを使用することもできます
- 「<CondPattern」(辞書順で前にある)
CondPattern をプレーンな文字列として扱い、TestString と辞書順で比較します。TestString がCondPattern より辞書順で前にある場合にtrueとなります。 - 「>CondPattern」(辞書順で後にある)
CondPattern をプレーンな文字列として扱い、TestString と辞書順で比較します。TestString がCondPattern より辞書順で後にある場合にtrueとなります。 - 「=CondPattern」(辞書順で等しい)
CondPattern をプレーンな文字列として扱い、TestString と辞書順で比較します。TestString がCondPattern と辞書順で等しい場合(両方の文字列が文字単位で完全に等しい場合)にtrueとなります。CondPattern が""
(二重引用符2つ)の場合、TestString を空文字列と比較します。 - 「-d」(directory である)
TestString をパス名として扱い、それが存在し、かつディレクトリであるかどうかをテストします。 - 「-f」(通常のfile である)
TestString をパス名として扱い、それが存在し、かつ通常のファイルであるかどうかをテストします。 - 「-s」(size を持つ通常のファイルである)
TestString をパス名として扱い、それが存在し、かつサイズがゼロより大きい通常のファイルであるかどうかをテストします。
- 「<CondPattern」(辞書順で前にある)
RewriteCond
ディレクティブの3番目の引数として[
flags]
を追加することで、CondPattern に特殊なフラグを設定することもできます。flags は、以下のいずれかのフラグをコンマで区切ったリストです。- 「
nocase|NC
」(大文字小文字の区別なし)
これによりテストが大文字小文字を区別しなくなります。つまり、展開されたTestStringとCondPatternの両方で「A-Z」と「a-z」の違いが無視されます。このフラグは、TestStringとCondPattern間の比較にのみ有効です。ファイルシステムやサブリクエストのチェックには影響しません。 - 「
ornext|OR
」(次の条件とOR結合)
これを、暗黙のANDの代わりにローカルなORでルール条件を結合するために使用します。典型的な例このフラグがない場合、条件/ルールペアを3回書く必要があります。RewriteCond %{REMOTE_HOST} ^host1.* [OR] RewriteCond %{REMOTE_HOST} ^host2.* [OR] RewriteCond %{REMOTE_HOST} ^host3.* RewriteRule ...some special stuff for any of these hosts...
- 「
例
リクエストの「User-Agent:
」ヘッダーに基づいてサイトのホームページをリライトするには、次のようにします
RewriteCond %{HTTP_USER_AGENT} ^Mozilla.*
RewriteRule ^/$ /homepage.max.html [L]
RewriteCond %{HTTP_USER_AGENT} ^Lynx.*
RewriteRule ^/$ /homepage.min.html [L]
RewriteRule ^/$ /homepage.std.html [L]
説明: 「Mozilla」と自称するブラウザ(Netscape Navigator、Mozillaなどを含む)を使用した場合、maxホームページ(フレームやその他の特殊機能を含む可能性がある)が表示されます。Lynxブラウザ(ターミナルベース)を使用した場合、minホームページ(簡単でテキストのみのブラウジング用に設計されたバージョンである可能性がある)が表示されます。これらの条件のいずれも適用されない場合(他のブラウザを使用しているか、ブラウザが非標準の何かとして自己識別している場合)、std(標準)ホームページが表示されます。
RewriteMap
構文: RewriteMap name rewriteMapClassName optionalParameters
rewriteMapClassName
の値は、特殊な値も許可します
int:toupper
: 渡された値を大文字に変換する特殊マップint:tolower
: 渡された値を小文字に変換する特殊マップint:escape
: 渡された値をURLエスケープするint:unescape
: 渡された値をURLアンエスケープする
マップは、ユーザーが実装する必要があるインターフェースを使用して実装されます。そのクラス名はorg.apache.catalina.valves.rewrite.RewriteMap
で、そのコードは次のとおりです
package org.apache.catalina.valves.rewrite;
public interface RewriteMap {
default String setParameters(String params...); // calls setParameters(String) with the first parameter if there is only one
public String setParameters(String params);
public String lookup(String key);
}
そのようなクラス(例ではrewriteMapClassName
)の参照された実装は、setParameters(String)
を呼び出すことにより、オプションのパラメータ(上記からのoptionalParameters
、空白に注意)でインスタンス化および初期化されます。そのインスタンスは、RewriteMap
ルールの最初のパラメータとして与えられた名前で登録されます。
注: 複数のパラメータを使用できます。これらはスペースで区切る必要があります。パラメータは「"」で囲むことができます。これにより、パラメータ内にスペース文字を含めることができます。
そのマップインスタンスには、対応するRewriteRule
で設定されたルックアップ値が、lookup(String)
の呼び出しによって与えられます。実装は、与えられたデフォルトを使用すべきであることを示すためにnull
を返すか、置換値を返すことができます。
例えば、すべてのルックアップキーを大文字に変換するリライトマップ関数を実装したいとします。まず、RewriteMap
インターフェースを実装するクラスを実装することから始めます。
package example.maps;
import org.apache.catalina.valves.rewrite.RewriteMap;
public class UpperCaseMap implements RewriteMap {
@Override
public String setParameters(String params) {
// nothing to be done here
return null;
}
@Override
public String lookup(String key) {
if (key == null) {
return null;
}
return key.toUpperCase(Locale.ENGLISH);
}
}
このクラスをコンパイルし、jarファイルにまとめて${CATALINA_BASE}/lib
に配置します。
それが終わったら、RewriteMap
ディレクティブでマップを定義し、さらにそのマップをRewriteRule
で使用することができます。
RewriteMap uc example.maps.UpperCaseMap
RewriteRule ^/(.*)$ ${uc:$1}
この設定により、URLパス/index.html
へのリクエストは/INDEX.HTML
にルーティングされます。
RewriteRule
構文: RewriteRule Pattern Substitution
RewriteRuleディレクティブは、真のリライトの主力です。このディレクティブは複数回記述でき、各インスタンスが単一のリライトルールを定義します。これらのルールが定義される順序は重要です。これが実行時に適用される順序になります。
パターンはPerl互換の正規表現であり、現在のURLに適用されます。「現在」とは、このルールが適用される時点でのURLの値を意味します。これは元のリクエストされたURLとは異なる場合があります。元のURLはすでに前のルールに一致し、変更されている可能性があるためです。
セキュリティ警告: Javaの正規表現マッチングの性質上、不適切に形成された正規表現パターンは「壊滅的なバックトラック」、別名「正規表現サービス拒否 (ReDoS)」の脆弱性を持っています。したがって、RewriteRuleパターンには細心の注意を払う必要があります。一般的に、このような脆弱な正規表現を自動的に検出することは困難であるため、良い防御策としては、壊滅的なバックトラックに関する情報を少し読むことです。良い参照元は、OWASP ReDoS ガイドです。
正規表現の構文に関するヒント
Text:.
Any single character[
chars]
Character class: Any character of the class 'chars'[^
chars]
Character class: Not a character of the class 'chars' text1|
text2 Alternative: text1 or text2 Quantifiers:?
0 or 1 occurrences of the preceding text*
0 or N occurrences of the preceding text (N > 0)+
1 or N occurrences of the preceding text (N > 1) Grouping:(
text)
Grouping of text (used either to set the borders of an alternative as above, or to make backreferences, where the Nth group can be referred to on the RHS of a RewriteRule as$
N) Anchors:^
Start-of-line anchor$
End-of-line anchor Escaping:\
char escape the given char (for instance, to specify the chars ".[]()
" etc.)
正規表現に関する詳細情報については、Perl正規表現のmanページ(「perldoc perlre」)を参照してください。正規表現とそのバリアント(POSIX正規表現など)に関するより詳細な情報に興味がある場合は、以下の書籍がこのトピックに特化しています
Mastering Regular Expressions, 第2版
Jeffrey E.F. Friedl
O'Reilly & Associates, Inc. 2002
ISBN 978-0-596-00289-3
ルールでは、NOT文字(「!
」)も可能なパターン接頭辞として利用できます。これにより、パターンを否定することができます。たとえば、「現在のURLがこのパターンに一致しない場合」と指定できます。これは、否定パターンに一致させる方が簡単な例外的なケースや、最後のデフォルトルールとして使用できます。
注: NOT文字を使用してパターンを否定する場合、そのパターンにグループ化されたワイルドカード部分を含めることはできません。これは、パターンが一致しない場合(つまり、否定が一致する場合)、グループに内容がないためです。したがって、否定されたパターンを使用する場合、置換文字列で$N
を使用することはできません!
リライトルールの置換は、Patternに一致した元のURLと置換される(または置き換える)文字列です。プレーンテキストに加えて、以下を含むことができます
- RewriteRuleパターンへのバックリファレンス (
$N
) - 最後に一致したRewriteCondパターンへのバックリファレンス (
%N
) - ルール条件テスト文字列と同様のサーバー変数 (
%{VARNAME}
) - マッピング関数呼び出し (
${mapname:key|default}
)
バックリファレンスは、一致したPatternのN番目のグループの内容に置換される、$
N (N=0..9) の形式の識別子です。サーバー変数は、RewriteCond
ディレクティブのTestStringと同じです。マッピング関数はRewriteMap
ディレクティブに由来し、そこで説明されています。これら3種類の変数は上記の順序で展開されます。
すでに述べたように、すべてのリライトルールはSubstitutionに適用されます(設定ファイルで定義された順序で)。URLはSubstitutionによって完全に置き換えられ、すべてのルールが適用されるまで、またはL
フラグによって明示的に終了されるまで、リライト処理が続行されます。
特殊文字$
と%
は、バックスラッシュ文字\
を前に付けることでエスケープできます。
「-
」という特殊な置換文字列があり、これは置換なしを意味します!これは、URLにのみ一致するが何も置換しないリライトルールを提供する場合に役立ちます。これは通常、置換が発生する前に複数のパターンを適用するために、C(チェーン)フラグと組み合わせて使用されます。
新しいmod_rewriteバージョンとは異なり、Tomcatのリライトバルブは絶対URL(絶対URLを指定するには特定のredirectフラグを使用する必要がある、後述参照)や直接ファイルサービングを自動的にサポートしていません。
さらに、RewriteRule
ディレクティブの3番目の引数として[
flags]
を追加することで、Substitutionに特殊なフラグを設定できます。Flagsは、以下のいずれかのフラグをコンマで区切ったリストです。
- 「
chain|C
」(次のルールとチェイン)
このフラグは現在のルールを次のルールとチェーンします(次のルールもさらにその次のルールとチェーンできます)。これにより、次のような効果があります。ルールが一致した場合、処理は通常通り続行され、このフラグは影響を与えません。ルールが一致しない場合、後続のチェーンされたすべてのルールはスキップされます。たとえば、外部リダイレクトが発生した際に(「.www
」の部分が発生すべきではない場合)、ディレクトリごとのルールセット内で「.www
」部分を削除するために使用できます。 - 「
cookie|CO=
NAME:VAL:domain[:lifetime[:path]]」(コッキーの設定)
これはクライアントのブラウザにクッキーを設定します。クッキーの名前はNAMEで、値はVALです。domainフィールドはクッキーのドメイン(例: 「.apache.org」)、オプションのlifetimeはクッキーの有効期間(分単位)、オプションのpathはクッキーのパスです。 - 「
env|E=
VAR:VAL」(環境変数の設定)
これにより、VARという名前のリクエスト属性が値VALに設定されることを強制します。VALは展開される正規表現バックリファレンス($N
と%N
)を含むことができます。このフラグは複数回使用でき、複数の変数を設定できます。 - 「
forbidden|F
」(URLを禁止する)
これにより、現在のURLが禁止されることを強制します。直ちにHTTP 403 (FORBIDDEN) レスポンスを返します。このフラグを適切なRewriteCondと組み合わせて使用し、一部のURLを条件付きでブロックします。 - 「
gone|G
」(URLを廃止する)
これにより、現在のURLが廃止されることを強制します。直ちにHTTP 410 (GONE) レスポンスを返します。このフラグを使用して、存在しなくなったページを廃止としてマークします。 - 「
host|H
=Host」(ホストにリライトを適用)
URLをリライトするのではなく、仮想ホストがリライトされます。 - 「
last|L
」(最後のルール)
ここでリライト処理を停止し、それ以上リライトルールを適用しません。これはPerlのlast
コマンドまたはC言語のbreak
コマンドに対応します。このフラグを使用して、現在リライトされたURLが後続のルールによってさらにリライトされるのを防ぎます。例えば、ルートパスURL(「/
」)を実際のURL、例:「/e/www/
」にリライトするために使用します。 - 「
next|N
」(次のラウンド)
リライト処理を再実行します(最初のルールから再度開始)。このとき、マッチングされるURLは元のURLではなく、最後のルールによって返されたURLとなります。これはPerlのnext
コマンドまたはC言語のcontinue
コマンドに対応します。このフラグを使用してリライト処理を再開し、直ちにループの先頭に戻ります。
無限ループを作成しないように注意してください! - 「
nocase|NC
」(大文字小文字の区別なし)
これにより、Pattern が現在のURLと照合される際に、Pattern が大文字小文字を区別せず、「A-Z」と「a-z」の違いを無視します。 - 「
noescape|NE
」(出力のURIエスケープなし)
このフラグは、リライトバルブがリライト結果に通常のURIエスケープルールを適用するのを防ぎます。通常、特殊文字(「%」、「$」、「;」など)はそれぞれの16進コード(それぞれ「%25」、「%24」、「%3B」)にエスケープされますが、このフラグはこれを防ぎます。これにより、次のように出力にパーセント記号が表示されるようになりますこれにより、「RewriteRule /foo/(.*) /bar?arg=P1\%3d$1 [R,NE]
/foo/zed
」が「/bar?arg=P1=zed
」に対する安全なリクエストに変わります。 - 「
qsappend|QSA
」(クエリストリングの追加)
このフラグは、リライトエンジンに、置換文字列のクエリ文字列部分を既存の文字列に置き換えるのではなく、追加することを強制します。リライトルールを介してクエリ文字列にさらにデータを追加したい場合に使用します。 - 「
redirect|R
[=code]」(強制リダイレクト)
Substitution をhttp://thishost[:thisport]/
でプレフィックスし(これにより新しいURLがURIになる)、外部リダイレクトを強制します。codeが指定されていない場合、HTTP 302 (FOUND、以前はMOVED TEMPORARILY) レスポンスが返されます。300-399の範囲で他のレスポンスコードを使用したい場合は、適切な数値を指定するか、以下のシンボリック名のいずれかを使用してください:temp
(デフォルト)、permanent
、seeother
。URLを正規化してクライアントに返すルール(例: 「/~
」を「/u/
」に変換したり、/u/
userに常にスラッシュを追加したりする場合など)にこれを使用します。
注: このフラグを使用する場合、置換フィールドが有効なURLであることを確認してください!そうでない場合、無効な場所にリダイレクトされます。このフラグ単独では、URLの前にhttp://thishost[:thisport]/
を付加するだけで、リライトは続行されることを覚えておいてください。通常、この時点でリライトを停止し、すぐにリダイレクトしたいと思うでしょう。リライトを停止するには、「L」フラグを追加する必要があります。 - 「
skip|S
=num」(次のルールをスキップ)
現在のルールが一致した場合、このフラグはリライトエンジンに、次に続くnum個のルールをスキップするよう強制します。これは擬似的なif-then-else構造を作成するために使用します。then節の最後のルールはskip=N
となり、Nはelse節のルール数です。(これは「chain|C」フラグとは異なります!) - 「
type|T
=MIME-type」(MIMEタイプを強制)
ターゲットファイルのMIMEタイプをMIME-typeに強制します。これは、いくつかの条件に基づいてコンテンツタイプを設定するために使用できます。例えば、以下のスニペットは、.php
ファイルが.phps
拡張子で呼び出された場合、mod_php
によって表示されることを許可します。RewriteRule ^(.+\.php)s$ $1 [T=application/x-httpd-php-source]
- 「
valveSkip|VS
」(バルブをスキップ)
このフラグは、バルブの条件付き実行を設定するために使用できます。フラグが設定され、ルールが一致した場合、リライトバルブはCatalinaパイプライン内の次のバルブをスキップします。リライトバルブがパイプラインの最後のバルブである場合、このフラグは無視され、コンテナの基本バルブが呼び出されます。リライトが発生した場合、このフラグは効果がありません。