Velocity でデフォルト HTML エスケープ

前回 は JSP でのデフォルト HTML エスケープを検証しました。今回は Velocity を見てみます。

デフォルトエスケープの設定

Velocity では ReferenceInsertionEventHandler を使ってデフォルトでの HTML エスケープを実現できます。このクラスは名前の通り参照がテンプレートに挿入される時にフックして値を操作することができます。

コード例です。完全なソースコードはこちらを参照してください。

public class MyRefrenceInsertionEventHandler
    implements ReferenceInsertionEventHandler {
  @Override
  public Object referenceInsert(String reference, Object value) {
    if (value == null) {
      return null;
    } else if (reference.endsWith("NoEscape")
            || reference.endsWith("NoEscape}")) {
      return value;
    } else if (value instanceof SafeHtml) {
      return ((SafeHtml) value).getSafeHtmlValue();
    } else {
      return escape(value.toString());
    }
  }
}

ここでの処理は以下の通りです。

  • 参照名が NoEscape で終わっていたらエスケープしない
  • 値が SafeHtml を実装していたらエスケープしない
  • それ以外の場合はエスケープする

JSP の ELResolver が EL の一部を受け取るのと違って、ReferenceInsertionEventHandler では完全な参照名を受け取れるので String 以外をエスケープできないなんてことはありません。

動作検証

JSP の時と同じモデルを使って動作を検証します。

WikiPage wikiPage = new WikiPage(
    "<strong>Tokyo</strong>",
    new WikiText("<strong>Tokyo</strong> is the capital of Japan."));

まず title の出力です。

エスケープできていますね。続いて WikiPage の出力。

WikiPage#toString() の結果をエスケープできています。前回の JSP はエスケープできていませんでした。

今度は明示的にエスケープを回避してみます。

ReferenceInsertionEventHandler で書いたように NoEscape で終わる参照名の場合はエスケープしません。

こちらも SafeHtml を実装している場合はエスケープしません。

まとめ

ReferenceInsertionEventHandler を使ってデフォルトでの HTML エスケープ、参照名とクラス定義による明示的なエスケープの回避ができました。完璧ですね。

  • 検証に使ったソースコードは github にあります
  • こちらのサイトで動作を確認できます (非常に遅いです)