読者です 読者をやめる 読者になる 読者になる

Akihiro's Programmer Blog

Technology Notes for Personal

Amon2の流れを掴む - 5


 前回の続きから。

 今回は lib/sample/Web.pm の中身を見て行きます。


sample::Web

package sample::Web;
use strict;
use warnings;
use utf8;

 おなじみ。


use parent qw/sample Amon2::Web/;

 どうやら前回見たsampleに加えて、Amon2::Webを継承しているようです。


use File::Spec;

 OSによるセパレータの違いを吸収してくれるモジュール。

 だけど、使ってる様子はないので謎。


# dispatcher
use sample::Web::Dispatcher;
sub dispatch {
    return (sample::Web::Dispatcher->dispatch($_[0]) or die "response is not generated");
}

  Amon2::Webを見に行くと分かりますが、dispatchという抽象メソッドが定義されているので、きっちりdispatchは用意しなきゃいけないです。

 ここでは単に、sample::Web::Dispatcherで割り振られたコントローラレンダリングされたページのbodyが返ってきます。


# load plugins
__PACKAGE__->load_plugins(
    'Web::FillInFormLite',
    'Web::JSON',
    '+sample::Web::Plugin::Session',
);

 ここではプラグインをロードしています。local以下にあるプラグイン(Amon2に標準で入っているものやCartonで入れたもの)を指定する以外にも、lib以下(自分で追加したもの)を指定したい場合には+を付けます。


 Web::FillInFormLiteHTMLformに対して、値を簡単に挿入したやることが出来る機能を提供します。

any '/' => sub {
    my ($c) = @_;
    $c->FillInForm(+{ hoge => "ほげ" });

    return $c->render('index.tx');
};
<!doctype html>
<html>
  <head>
  ...
  </head>
  <body>
  ...
  <form method="POST" action="/register">
    <input name="hoge" type="text"></input>
    <input type="submit">
  </form>
  ...
  </body>
</html>

 こうすると、name="hoge"input要素に"ほげ"という値が入ります。


 また、Web::JSONjson_renderという、ハッシュリファレンスを渡すとjson形式のレスポンスを返してくれる機能を提供してくれます。APIを作る際には非常に重宝します。

 3つ目のsample::Web::Plugin::SessionSession管理機能を提供してくれます。


# setup view
use sample::Web::View;
{
    sub create_view {
        my $view = sample::Web::View->make_instance(__PACKAGE__);
        no warnings 'redefine';
        *sample::Web::create_view = sub { $view }; # Class cache.
        $view
    }
}

 create_viewdispatchと同様にAmon2::Webで抽象メソッドが定義されているので、実装しなければ行けません。

 create_viewは、Text::Xslateのオブジェクトを返しています。これはsample::Web::Viewを見に行けば分かるかと思います。このときにsample::Webのコンテキストも渡すようになっているので、configText::Xslateという名前のハッシュを用意しておけば、Text::Xslatenewするときに、その設定を読み込んでくれます。

 また、コメントにも書いてある通り、内部でメソッド自身を上書きすることで設定をキャッシュしています。これで、毎回オブジェクトを生成しなくて済むようになっています。


# for your security
__PACKAGE__->add_trigger(
    AFTER_DISPATCH => sub {
        my ( $c, $res ) = @_;
    
        # http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
        $res->header( 'X-Content-Type-Options' => 'nosniff' );

        # http://blog.mozilla.com/security/2010/09/08/x-frame-options/
        $res->header( 'X-Frame-Options' => 'DENY' );

        # Cache control.
        $res->header( 'Cache-Control' => 'private' );
    },
);

 最後にdispatch後に、httpレスポンスに対してゴニョゴニョするためのトリガを追加しています。

 ここでは主にセキュリティを強固にする設定を行っているようです。

 最初のX-Content-Type-Optitonsnosniffにしているのは、簡単に言えばXSS対策です。詳しくは下記参考サイトを参照です。

X-Content-Type-Options: nosniff つかわないやつは死ねばいいのに!


 次のX-Frame-OptionsDENYにしているのは、クリックジャッキング対策です。詳しくは下記参考サイトを参照です。

クリックジャッキング対策(Apache/IIS)


 そして最後にCache-Controlprivateにしているのは、プロキシキャッシュ対策です。詳しくは下記参考サイトを参照です。

プロキシキャッシュ対策


 具体的なhttpレスポンスは以下のような物です。


Cache-Control  private
Connection  close
Content-Length  4987
Content-Type    text/html; charset=UTF-8
Date    Sun, 06 Jul 2014 21:23:46 GMT
Server  Plack::Handler::Starlet
Set-Cookie  hss_session=1404681826%3A1fcfdaff77e8a8eab9fd0003c2466f5%3ABQgDAAAAAQiIAAAAB2NvdW50ZXI%3D%3A35356662613234346636393736656635316561656130323662653937616266393466656332336231; path=/; HttpOnly XSRF-TOKEN=1fcfdaff77e8a8eab9fd0003c2466f5; path=/
X-Content-Type-Options  nosniff
X-Frame-Options DENY



 ここまででAmon2の流れを掴むは一旦の区切りとしたいと思います。