へぼい日記
Gearmanのはまりどころ
- 2011/1/22 土曜日 21:19:36
- perl
最近Gearmanに入門しているのですが、いろいろとはまったのでメモ。
$worker->workは”Do one job”ではなくDo job loop
$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への示唆が含まれているので必見ですです
X-Content-Type-Options: nosniffのつけ方
- 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 つかわないやつは死ねばいいのに!
日本の休日をPerlから求める
- 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系は信頼できるものを政府が出してくれるとうれしいなーというところ。
XslateはSyntaxを変えても基本的には実運用上の速度は変わらない
- 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% --
Path::AttrRouterにHTTPメソッド制限できる機能を追加してみた
- 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とかで作ってみようかなーと考え中。
PlackにおけるCSRFとDNS-Rebinding対策
- 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::Middleware::Header
- 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側で対応してくれました
patternがemptyな場合には前回成功時のpatternが使われるというハマりポイント
- 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を動的に生成してたりする時に空になっちゃうケースなんかがあると思うので、その場合はマッチ処理自体を回避するようにしたほうがよいかと思われます。
最初バグかと思いました。
Casual Talks#1でLTしてきました
- 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さんお疲れ様でした。
JSocketを使ってPOSTもストリーミングするPlackアプリ
- 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をお使いください。
- 検索
- フィード
- メタ情報