はじまり
CPANに上がってるモジュール、一つ一つの粒度が小さいから読みやすいし、ドキュメントもテストもしっかり揃ってて挙動を把握しやすくて、自分にとっては最高の教科書だった
OSSで公開されているソースコードは、最高の教科書ですよね。 Perlにはなじみがないので、卑近な例としてJavaScriptの場合を考えてみます。
npmからJavaScriptのライブラリを探してソースコードを読む
例えばHTMLエスケープの実装が知りたいとき
HTML文字列を生成する際に、ユーザー入力をそのまま出力するとタグが生成されてHTMLが壊れることがあります。 というかXSSの脆弱性です。そこでHTMLエスケープをしたいなと思うのですが・・・どう実装したら漏れなく対応できるかわからない状況を仮定しましょう。
npmリポジトリを検索
JavaScriptではnpm | build amazing thingsというパッケージリポジトリが主流です。 まずはここで検索します。
HTMLエスケープしたいので、雑にhtml
とescape
で検索してみましょう。
https://www.npmjs.com/search?q=html%20escape
224パッケージも出てきて、どれを見たらいいか迷います。
まずは一番うえのhtml-escaper
から見てみましょう。
https://www.npmjs.com/package/html-escaper
まずダウンロード数を確認します。 700万とか異次元の数値が出ています。 広く使われているようです。
参考までに2番目のxss
パッケージも見てみましょう。
90万件と十分に使われています。 が、html-escaperは一桁多いので、HTMLエスケープ用のパッケージとしては、html-escaperがもっとも広く使われていると推測できます。
つぎにhtml-escaperの実装を見てみましょう。
右側のHomepage
の欄にGitHubへのリンクがあります。
GitHubで実装を探す
https://github.com/WebReflection/html-escaper
JavaScriptのライブラリはindex.js
がエントリポイントになっていることが多いので、inedx.jsを見てみましょう。
一番下までスクロールすると、次のようにexports
にescape
とunescape
を代入している箇所が見つかります。
JavaScriptのCommonJSというパッケージでは、exports
オブジェクトを使って、定義した関数を公開します。
このescape
の実装が見つかれば、HTMLエスケープの実装がわかりそうです。
少し上にスクロールすると、次のように41行目でescape
が定義されている場所が見つかりました。
escape関数の実装を読む
次の定義からescape
はreplace関数を呼んでいることがわかります。
const escape = es => replace.call(es, ca, pe)
このreplaceは何でしょうか?
24行目でconst {replace} = '';
と定義されています。
これはつまりString.prototype.replaceです。
分割代入を使って、組み込み関数への参照を取得する方法を初めて見ました。驚きです。勉強になりますね。
replace
をcall
で呼び出しているので、es.replace(ca, pe)
と同じです。
es => replace.call(es, ca, pe)
とアロー関数で定義されているので、次の関数定義と同じです。
function espace(es) { return es.replace(ca, pe) }
第一引数ca
は何でしょうか?28行目で定義されていいます。
const ca = /[&<>'"]/g;
第二引数pe
は何でしょうか?30〜37行目を見てみましょう。
const esca = { '&': '&', '<': '<', '>': '>', "'": ''', '"': '"' }; const pe = m => esca[m];
置き換えたい文字列をキーにして、置き換え後の文字列を返す関数です。 String.prototype.replaceは第二引数に関数を指定できます。 MDNでは次のように説明されています。
新しい部分文字列を生成するために実行される関数で、regexp や substr でマッチしたものを置き換えるのに使われます。この関数に渡される引数は下記の「引数としての関数の指定」で述べられています。
つまり、escape
関数は引数で与えられた文字列で、esca
マップに定義された文字の組み合わせで置き換えることがわかりました。
&
, <
,>
, "
, '
を置換できれば、十分有効にHTMLエスケープとして動きそうだと推測できます。
やりました。 ここまでで、HTMLエスケープの仕様を調べずに、HTMLエスケープの仕様をなんとなく把握しました。
オチ
いい感じにOSSのライブラリから実装を見つけられないときは、 大体「HTMLエスケープの実装が知りたい」みたいないい感じのゴールを設定できていない時なんですよね・・・。