ホーム

へぼい日記

Gearmanのはまりどころ

  • 投稿者: chiba
  • 2011/1/22 土曜日 21:19:36
  • perl

最近Gearmanに入門しているのですが、いろいろとはまったのでメモ。

$worker->workは”Do one job”ではなくDo job loop

Gearman::WorkerのPODには

$worker->work while 1;

みたいなサンプルが書いてあったり

Gearman::Job->work(%opts)

Do one job and returns (no value returned). You can pass "on_start" "on_complete" and "on_fail" callbacks in %opts.

って書いてあるのですが(しかもこれは、Gearman::JobではなくてGearman::Workerだし、、、)
workはオプション無しで呼ばれた場合はwhile 1なんかなくてもloopします。
work_once的な動きにしたいのであれば

$worker->work(stop_if => sub { 1 });

とすればいいです。stop_ifをmax_requests_per_child的な動きにしたい場合はkazeburoさんのgearman-starter.plを参考にするといいです。

ちなみにこれは作者にメールでパッチも送ったりもしたのですがこのRTが同じ内容。1年半ぐらい放置みたいなので直る気配なし。

Gearman::Client->job_serversはArrayRefを受け取れるけど、Gearman::Worker->job_serversは受け取れない

結構はまりました。

my $clinet = Gearman::Clinet->new;
$client->job_servers(['127.0.0.1']);

はokだけど

my $worker = Gearman::Worker->new;
$worker->job_servers(['127.0.0.1']);

は駄目。正しくは

my $worker = Gearman::Worker->new;
$worker->job_servers('127.0.0.1');

としなければならない。これもRTにあがってますね。

Gearman::Workerはfork safeじゃないんでfork後生成

まぁDBIのdbhとかと一緒ですね。いくつかのネット上の例でParallel::Preforkなんかと組み合わせて使う時に
親プロセスで$worker作って共有している例注1があったのですが、ちゃんとやるなら子供で生成すること。
一見普通に動いちゃうのですが通信がまざって変になるかもしれないです。

まとめ

あたらしくCPANモジュールを使い出す時にはPODと共にRTも一緒に見ておくとよい。

注1
ここの11pとかここ(もう直ってる)とか。ちなみにkazuhoさんの書いたものだと去年のadvent calendarのWriting a prefork server / daemon using Parallel::Preforkは子供でworker生成してます。この記事は、graceful shutdownやSIGHUPによるconfig reloadへの示唆が含まれているので必見ですです

はてなブックマーク - Gearmanのはまりどころ

X-Content-Type-Options: nosniffのつけ方

  • 投稿者: chiba
  • 2011/1/6 木曜日 12:49:29
  • security

Apache

mod_headersでできます

Header set X-Content-Type-Options nosniff

Nginx

add_header X-Content-Type-Options nosniff;

但し、上記だとproxyなんかで既にX-Content-Type-Options: nosniff;が付いていると

X-Content-Type-Options: nosniff, nosniff

のようなヘッダになってしまう。問題ないかもしれないが気になる場合はNginxHttpHeadersMoreModuleを使って

more_set_headers 'X-Content-Type-Options: nosniff';

とすると良いのかも。

Plack

Plack::Middleware::Headerを使うと簡単です。

enable 'Header', set => ['X-Content-Type-Options' => 'nosniff'];

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

はてなブックマーク - X-Content-Type-Options: nosniffのつけ方

日本の休日をPerlから求める

  • 投稿者: chiba
  • 2010/11/15 月曜日 18:11:18
  • perl

日本の休日には「国民の祝日」と「振替休日」と「国民の休日」ってのがあるのですがそれをPerlから求めるにはどうしたらいいんだという話。
#perl-casualでたずねたところいろいろと方法を教えてもらいました。
定番ネタだし、それ三週目といわれたりしたのでまとめてみますたという流れ。

そもそも休日というのは法律で決められるものなので、改正もあり最近だと2005年に改正があったりしています。
また、「国民の祝日」の中には「春分の日」や「秋分の日」のように翌年分を2月に官報で発表なんてものもあったりします。
やっかいですね。

CPANモジュールを使う

Calendar::Japanese::Holiday

最終更新日が2007年なようですが

use Calendar::Japanese::Holiday;
say isHoliday(2011, 3, 21);
say isHoliday(2011, 9, 23);

こんな感じで未来の秋分・春分の日も計算で求められているのでそれなりに信頼感はあるかと思います。
ただし、「振替休日」に関しては下記のように第三引数に1をいれないと求めてくれないので注意。

use Calendar::Japanese::Holiday;
say isHoliday(2009, 5, 6); # これだと駄目
say isHoliday(2009, 5, 6, 1); # これならOK

DateTime::Holiday::Japanese

CPANモジュールではないですが、coderepos上にfbisさん作のモジュールもあがっています。

use DateTime::Holiday::Japanese qw/is_holiday/;
say is_holiday(year => 2011, month => 3, day => 21);
say is_holiday(year => 2011, month => 9, day => 23);

Calendar::Japanese::Holidayと同様に更新は2007年からされていないようですが秋分春分の日は計算で出しています。
今日2009-2011のテストデータを追加してパスするのは確認しています。coderepos上にあるので法律変わったら誰かが更新してくれるんじゃないかという期待感あり。DateTime依存。

ネット経由で情報を定期的にとってくる

Google Calendar Data API

japanese@holiday.calendar.google.com
=> 「振替休日」「国民の休日」には非対応(「国民の祝日」カレンダーだからそれが正しいんだよ派)
outid3el0qkcrsuf89fltf7a4qbacgt9@import.calendar.google.com
=> 「振替休日」「国民の休日」にも対応。使えそう
https://www.mozilla.org/projects/calendar/holidays.htmlのJapan Holidaysと同じデータぽいのかな。

政府

「国民の祝日」についてが一番信頼できそうなネット上の情報な気もするが、別にこのページを維持すること自体を法律で定めているわけでもないし今年と来年のデータしかないのでそこまで使えるってわけでもない。「振替休日」と「国民の休日」については例だけなので将来的にどう表示されるのかも判然としない。
目視確認なら法律と官報を確認するに次いで信頼性はあるかと。

休日DBを独自に作成して運用者がメンテ

最強

まとめ

CPANモジュールの”その時点での法律計算”系は手軽さはあるが、今後の法改正を見越すと若干難ありか。
モジュール自体が毎年来年分のテストを追加してリリースされることが保障されていて、
使う側も毎年保守ができるのであれば特に問題はなさそう。
さらにモジュール自体もgithubなんかで複数人で保守されているといいなという話。
API系は信頼できるものを政府が出してくれるとうれしいなーというところ。

はてなブックマーク - 日本の休日をPerlから求める

XslateはSyntaxを変えても基本的には実運用上の速度は変わらない

  • 投稿者: chiba
  • 2010/8/13 金曜日 19:54:00
  • perl

TTの158倍速いというxslateですが、このベンチマークはSyntax::Kolonを使っています。
TT互換なSyntaxであるところの、Syntax::TTerseを使うとどうなるのかなということでhttp://github.com/nihen/p5-Text-Xslate/tree/add_tterse_benchのbenchmark/x-rich-enc.plとbenchmark/x-poor-env.plにTTerseも追加してみました。

以下結果

%perl benchmark/x-rich-env.pl
Perl/5.12.1 i686-linux
Text::Xslate/0.1056
Text::MicroTemplate/0.15
Text::MicroTemplate::Extended/0.11
Template/2.22
Text::ClearSilver/0.10.5.4
HTML::Template::Pro/0.9502
1..5
ok 1 - TTerse: Text::Xslate::Syntax::TTerse
ok 2 - TT: Template-Toolkit
ok 3 - MT: Text::MicroTemplate
ok 4 - TCS: Text::ClearSilver
ok 5 - HTP: HTML::Template::Pro
Benchmarks with 'include' (datasize=100)
          Rate     TT     MT    TCS    HTP Xslate TTerse
TT      78.6/s     --   -69%   -94%   -95%   -99%   -99%
MT       257/s   227%     --   -82%   -84%   -98%   -98%
TCS     1412/s  1697%   450%     --   -11%   -89%   -89%
HTP     1586/s  1918%   517%    12%     --   -88%   -88%
Xslate 13241/s 16752%  5054%   838%   735%     --    -1%
TTerse 13397/s 16951%  5115%   849%   745%     1%     --
%perl benchmark/x-poor-env.pl
Perl/5.12.1 i686-linux
Text::Xslate/0.1056
Template/2.22
HTML::Template/2.9
Text::MicroTemplate/0.15
Text::MicroTemplate::Extended/0.11
1..4
ok 1 - TTerse: Text::Xslate::Syntax::TTerse
ok 2 - TT: Template-Toolkit
ok 3 - MT: Text::MicroTemplate
ok 4 - HT: HTML::Template
Benchmarks with 'include' (datasize=100)
         Rate     TT TTerse Xslate     HT     MT
TT     49.5/s     --   -27%   -28%   -61%   -80%
TTerse 67.9/s    37%     --    -1%   -47%   -73%
Xslate 68.5/s    38%     1%     --   -46%   -73%
HT      127/s   157%    88%    86%     --   -50%
MT      253/s   411%   273%   269%    99%     --

このように誤差の範囲ぐらいの差しか無く同様に速い。
これはなぜかというと、Xslateは様々なSyntaxで書かれたテンプレートを共通の中間コードにコンパイルし、それをキャッシュしているためその中間コードはほぼ同一のものになるからです。
一応そのコンパイル部分には差が現れるが、ファイルキャッシュもできない環境というのはほぼありえないので実運用上、速度の差は無いと言ってよいとおもわれる。というわけでTT使ってる人は安心してTTerseに移行してみるといいと思うです。(互換性がどの程度あるのかは使ってないから知らないけど!)

ちなみにコンパイル部分のみのベンチマーク

% perl author/bench_compile.pl
Parser: Kolon v.s. TTerse
         Rate tterse  kolon
tterse 80.1/s     --   -42%
kolon   139/s    74%     --
はてなブックマーク - XslateはSyntaxを変えても基本的には実運用上の速度は変わらない

Path::AttrRouterにHTTPメソッド制限できる機能を追加してみた

  • 投稿者: chiba
  • 2010/7/10 土曜日 23:53:26
  • perl

Path::AttrRouterというtypesterさんが開発されているdispatcherがあって、Catalyst-likeなControllerのattributeを拾ってきてルーティングテーブルを作成してくれるのが便利で使っています。

で、HTTPメソッドを考慮したルーティングを行ってくれる機能が欲しかったので追加してみました。
method_supportブランチとしてforkしてgithubにあげてあります。

使い方はこんな感じです。

use Path::AttrRouter;

{
    package MyController;
    use base 'Path::AttrRouter::Controller';

    sub index :Path { print "index\n" }
    sub post :Path Method('POST') { print "post\n" }
}


my $router = Path::AttrRouter->new( search_path => 'MyController' );

my $m;

$m = $router->match('/', 'GET');
$m->dispatch; # index

$m = $router->match('/', 'POST');
$m->dispatch; # post

Methodが指定されなかったsubroutineはGET, HEADがデフォルトになるようになってます。
一応後方互換性は考慮してあり、$router->matchの第二引数が空の場合は
どのメソッドでもマッチするようになっています。

本家にとりこまれればうれしいけれど取り込まれなければ別distとして継承使って作り直すかもです。

ところで、諸事情により前職を退職していまして、ブログURLを移転しています。
RSSリーダーに登録されていた方等は再度登録お願い致しますです。
一応302飛ばすようにしてはあるんですが、RSSリーダーって自動的にそこらへん追跡してくれないんすかね。

追記(2010-07-11 17:17)
http://twitter.com/#!/typester/status/18255875606
とのことです。確かにPath::名前スペースなのでHTTPメソッドに依存するのは筋悪でした。
HTTP::AttrRouterとかで作ってみようかなーと考え中。

はてなブックマーク - Path::AttrRouterにHTTPメソッド制限できる機能を追加してみた

PlackにおけるCSRFとDNS-Rebinding対策

  • 投稿者: chiba
  • 2009/12/20 日曜日 11:32:53
  • perl

最近のwebセキュリティ界隈ではCSRFやDNS-Rebindingが話題ですが、Plackでアプリケーションサーバを立ち上げる際にこれらの対策をどのように行うかについてまとめてみました。

まず、CSRF対策ですが、拙作のPlack::Middleware::RefererCheckを使うことにより、RefererのチェックによるCSRF対策が行えます。CSRF対策としては、onetime token方式も存在しますが、個人的にはRefererチェックが導入が楽で好きではあります。Refererを送信しないクライアントを対象にしたサービスを運営される方は別途onetime token方式の対策をおこなってください。

Plack::Middleware::RefererCheckの使い方はこのようになります。(SYNOPSYSからの抜粋)

use Plack::Builder;

builder {
  enable 'RefererCheck', host => 'www.example.com', same_scheme => 1, error_app => sub { [403, [], ['Forbidden']] };
  $app;
};

# or more simply(host from $env->{HTTP_HOST} and same_scheme => 0)
# this is vulnerabilly for DNS Rebinding
builder {
  enable 'RefererCheck';
  $app;
};

さて、コード中にも書いてあるように後者のチェック用hostをHTTP_HOSTから取得する方法はDNS-Rebindingに脆弱です。しかし前者のように固定hostを設定することにより、DNS-Rebindingへの対策も同時にできることになります。尚、onetime token方式ではXHRのsame originポリシーの崩壊によりDNS-Rebindingへの対策を単体で行うことはできません。

このようにRefererCheckを固定hostで行うことによりCSRF対策においてはDNS-Rebindingに対応できますが、CSRFから保護されるページ以外についても当然DNS-Rebindingでのアクセスははじきたいところです。apache等においてはname base virtual hostを活用することにより、期待するホスト名以外のアクセスをはじくことができますが、PlackでもPlack::App::URLMap(mount)を使うことにより同様のことが可能です。

use Plack::Builder;
builder {
  mount 'http://example.com/' => builder {
    mount '/app' => $app;
    mount '/admin' => $admin_app;
 }
}

このようにすることにより、example.com以外のHOSTでのアクセスは404となります。mountは上記の例のように、hostの指定とpath_infoの指定を同時に行えるもので、apacheでいうとVirtualhostとLocationを一緒にしたような機能になります。なので、上記のコードは下記のコードと等価です。

use Plack::Builder;
builder {
  mount 'http://example.com/app/' => $app;
  mount 'http://example.com/admin/' => $admin_app;
}

もちろんホスト名を違うものをmountできますのでPlack単体でVirtualhostな運用もできます。URLMap便利ですね。

はてなブックマーク - PlackにおけるCSRFとDNS-Rebinding対策

Plack::Middleware::Header

  • 投稿者: chiba
  • 2009/12/3 木曜日 23:19:23
  • perl

Plack::Middleware::Headerをgithubに上げました。

これは、Plack::Middlewareレイヤーでレスポンスヘッダを設定するもので、Apacheでいうところのmod_headersに相当します。

使い方はこんな感じです。

use Plack::Builder;
builder {
    enable 'Header',
        set => ['X-Plack-One' => '1'],
        append => ['X-Plack-Two' => '2'],
        unset => ['X-Plack-Three'];
    $app;
};

自分はPlack::Middleware::Staticと併用してExpiresをつけたりするのに使うために作りました。IEがExpires: -1とかやっておかないとしばらくキャッシュしてIf-Modifled-Sinceなリクエストも投げてくれなくなっちゃうという弊害があったので。

あと、IE関連では、If-Modified-Sinceの値に”;length=***”という余計なものが付いてきてしまい(ここここを参照)、Middleware::ConditionalGETを有効にしても304を吐けなかったりしていたので、それを取り除くためのMiddlewareも書いてみました。こちらは名前とかがきもいのでgistレベル。

追記(2009-12-13 21:27): cpanにアップしました。あと、If-Modified-SinceのIEバグの件はmiyagawaさんがConditionalGET側で対応してくれました

はてなブックマーク - Plack::Middleware::Header

patternがemptyな場合には前回成功時のpatternが使われるというハマりポイント

  • 投稿者: chiba
  • 2009/11/26 木曜日 2:42:23
  • perl
print "match1\n" if "baz" =~ m{};
"foo" =~ m{foo};
print "match2\n" if "baz" =~ m{};

の結果は

match1

である。なぜならperldoc perlrerefに書いてある通り、

If 'pattern' is an empty string, the last successfully matched regex is used. 

であるから。

patternを動的に生成してたりする時に空になっちゃうケースなんかがあると思うので、その場合はマッチ処理自体を回避するようにしたほうがよいかと思われます。

最初バグかと思いました。

はてなブックマーク - patternがemptyな場合には前回成功時のpatternが使われるというハマりポイント

Casual Talks#1でLTしてきました

  • 投稿者: chiba
  • 2009/11/21 土曜日 22:35:56
  • perl

昨日(11/20)にperl-casualのCasual Talks#1にて拙作のFormValidator::NestedについてLTしてきました。

slideをslideshareにあげておきました。

得られた教訓
1. 実際に話し始めると早口気味になるのでスライド大目ぐらいが自分にはちょうどいいかも
2. プロジェクターにつなぐときはねじをちゃんとしめておく
3. やっぱり笑いを一つぐらいとっといたほうが場は暖かくなる
(PAUSE ID requestの際にcatalyst-pluginを作りたいと書いていたと言ったときに若干嘲笑気味の笑いはありましたがw)

自分以外も発表が初めてだという方も多かったのに、発表が皆さんうまくて非常に面白かったです。またの機会があったら今回の教訓を踏まえまた発表できたら幸いです。

主催されたyusukebeさん、会場の用意や二次会の(実質)幹事をされたnobjasさんお疲れ様でした。

はてなブックマーク - Casual Talks#1でLTしてきました

JSocketを使ってPOSTもストリーミングするPlackアプリ

  • 投稿者: chiba
  • 2009/10/20 火曜日 3:58:37
  • perl

さて、前エントリJSocketというのを作ったと書いたのですが、これは実はjavascriptで動くtwitter streamクライアントを作るならばmultipart/mixedを使うべきというのを読んで、レスポンスがpollではなくてストリーミングできるというのを知って、リクエストもやりたいよというふうに思ったのがきっかけでした。

まず、XHRでできないかを試してみたのですが、xhr.send(data)を一回読んでしまうと少なくともjavascript側ではリクエストは完了したと思ってしまって、再度xhr.send(data)しても反応はありませんでした。

そこでJSocketの登場です。JSocketを使うとhttpリクエストを断続的に送信することができます。やったですね。

で、Plack::Server::Coroを使って試しに
リアルタイムチャット
を作ってみました。どうぞお試し下さい。レスポンスもJSocketを使っていますのでmultipartに比べてboundary分お得だったりもします。テキストエリアに入力された文字がストリーミングで送信され、また他人のデータもストリーミングで受信できていると思います。ちなみに自分の発言もサーバから持ってきてるので一人でも確認できます。

ちなみにこれを1つのコネクションでやってしまおうというのがWebsocketなんだろうという認識ですね。ただwebsocketはhttpの上に一応のってますがハンドシェイク以外の部分はhttp/1.0やhttp/1.1的には正しくないでしょうし、JSocketでの二重接続であれば正しいhttpとしてふるまえるはずで、現行のapacheやproxy等でも扱える可能性があったりします。

あ、チャットのサンプルコードもgithubにあげてあります。

plackup -s Coro --app chat.psgi 

という感じでPlack::Server::Coroをお使いください。

はてなブックマーク - JSocketを使ってPOSTもストリーミングするPlackアプリ

1 2 3 4 5 6 7 8 9

ホーム

検索
フィード
メタ情報

ページの上部に戻る