値を文字列結合で埋め込んだ WHERE 句に、シングルクォートを含む入力を渡すと、条件が常に真になって全ユーザーの行が返る。手元の SQLite で攻撃を再現し、なぜ起きるのかを確かめます。
Query クラスに WHERE・ORDER BY・LIMIT を足すたびに、コンストラクタの引数が1つずつ増えて7個になる。どれが必須か分からず、次の句を足す余地もない状態を、実際のコードで確かめます。
テーブル名を受け取って「SELECT * FROM users」を返すだけの Query クラスを Perl と Moo で作り、SQLite で動かします。全8回で SQL クエリビルダーに育てる出発点で、この素朴な文字列結合が次回から問題を起こします。
Perl と Moo でアクセスログ解析ツールを作りながら、継承でフィルターを足すとクラスが掛け算に増える問題に当たり、包んで重ねる Decorator パターンで組み替える全8回の連載の目次です。困りごとからも選べます。
シリーズの最終回。pipeline.json に Decorator の並びと引数を書き、PipelineBuilder で読み込んで積み上げます。新しい機能はクラスを1つ作って JSON に1要素足すだけで、既存コードは変えずに済む(開放閉鎖原則)ことを確かめます。
404 Not Found が指定回数以上連続したら STDERR に警告を出す AlertDecorator を作ります。連続回数を状態として持ち、ログはそのまま次へ流す、副作用を持つ Decorator の書き方を確かめます。
総リクエスト数・ステータスコード別の件数・総転送サイズを集計したい。ログを除外せずに通過させながら数える StatsAggregatorDecorator を作り、既存のクラスを変えずに機能を足せることを確かめます。
継承で増え続けたフィルタークラスを、包んで重ねる形に組み替える。Moo::Role で next_log を共通の契約にし、中身を委譲する LogDecorator と around 修飾子で、IP と 404 のフィルターを自由に組み合わせます(Decorator)。
IP フィルターに 404 検出を組み合わせようとすると、IPAndStatusFilteredLogParser のような組み合わせごとのクラスが必要になる。条件が増えるたびにクラス数が掛け算で増え、親の修正が全サブクラスに響きかねない問題を、実際のコードで確かめます。
特定の IP アドレスからのアクセスだけを抽出したい。LogParser を継承して next_log をオーバーライドし、条件に合う行まで読み飛ばす IPFilteredLogParser を作ります。次回、この継承が行き詰まります。
アクセスログを文字列のまま扱うと、「ステータスコードが200以外の行」を探す処理も書きにくい。Combined Log Format を名前付きキャプチャでパースし、ハッシュリファレンスで返す LogParser クラスを作ります。
Perl 入学式で習った open と while を Moo のクラスに包み、アクセスログを1行ずつ返す LogReader クラスを作ります。全8回で組み上げるログ解析パイプラインの土台です。
サイトを足すたびにコピペで増えていく Web スクレイパーを、Perl と Moo の継承で1つの設計にまとめていく全10回の案内板です。関数化・基底クラス・オーバーライド・フックメソッドと順に積み上げ、最後にその設計が Template Method パターンだったことを確かめます。
ここまで作ってきたスクレイパーの設計は、GoF の Template Method パターンだった。定義と実装を対応させ、Hollywood Principle(呼ぶのは親の側)、Strategy パターンとの使い分け、Factory Method との関係を Perl と Moo のコードで整理します。
ニュース・天気予報・商品情報の3つのスクレイパーを、1本のスクリプトから一括で実行する。サイトの追加、ログの追加、タイムアウトの設定といった変更がそれぞれどこを直せば済むのかを表にし、コピペ版との処理の流れの違いを振り返ります。