ap_hook_translate_name() にフックをかける場合は http_request.h をインクルードしよう

  • Posted by: ちわ
  • 2009年8月11日 03:58

Apacheモジュールを開発する際にフックをかけるタイミングがたくさんありますが、そのフックの一覧と API が

[補足記事]Apache 2.0 の hook 一覧(apache module 開発事初め その3-3) - DSAS開発者の部屋
http://dsas.blog.klab.org/archives/50626863.html

にまとめられています。
リンク先の Apache のバージョンは 2.0.58 で最近の 2.2.x とは若干の違いがあるようですが本当に若干です。
ap_hook_monitor() が追加されていて、ap_hook_http_method() が ap_hook_http_scheme() に変更されているくらいでしょうか。

Downloading Apache - Japanized Apache Site から Apache のソースをダウンロードして展開したディレクトリを /path/to/httpd とすると /path/to/httpd/include 内で AP_DECLARE_HOOK を grep すればリンク先で紹介されている各種フックの説明と API が見つけられます。
どのヘッダにどのフックが宣言されているか以下にまとめます。

  • ap_mpm.h
    • ap_hook_fatal_exception()
  • http_config.h
    • ap_hook_header_parser()
    • ap_hook_pre_config()
    • ap_hook_test_config()
    • ap_hook_post_config()
    • ap_hook_open_logs()
    • ap_hook_child_init()
    • ap_hook_handler()
    • ap_hook_quick_handler()
    • ap_hook_optional_fn_retrieve()
  • http_connection.h
    • ap_hook_create_connection()
    • ap_hook_pre_connection()
    • ap_hook_process_connection()
  • http_core.h
    • ap_hook_get_mgmt_items()
  • http_log.h
    • ap_hook_error_log()
  • http_protocol.h
    • ap_hook_insert_error_filter()
    • ap_hook_post_read_request()
    • ap_hook_log_transaction()
    • ap_hook_http_scheme()
    • ap_hook_default_port()
  • http_request.h
    • ap_hook_create_request()
    • ap_hook_translate_name()
    • ap_hook_map_to_storage()
    • ap_hook_check_user_id()
    • ap_hook_fixups()
    • ap_hook_type_checker()
    • ap_hook_access_checker()
    • ap_hook_auth_checker()
    • ap_hook_insert_filter()
  • mpm_common.h
    • ap_hook_monitor()
  • scoreboard.h
    • ap_hook_pre_mpm()

コンフィグに関わるフックであれば http_config.h、コネクションに関するフックであれば http_connection.h とヘッダのファイル名でだいたいの当たりをつけることができるのではないでしょうか。中には当たりのつけづらいフックもありますが。

さて、ここまでが若干長い前置きです。
ap_hook_handler() くらいしか使わない単純なモジュールであれば特にヘッダを #include する必要はないですが、今回はリクエストされた URI をファイルシステムにマッピングするフェーズでちょっとやりたいことがあったので ap_hook_translate_name() にフックをかけようとしたら警告が出たんですね。

[travail@cabane]/home/public/git/thumb% sudo /usr/sbin/apxs -c -i mod_thumb.c
/usr/lib/apr-1/build/libtool --silent --mode=compile gcc -prefer-pic -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=generic -fasynchronous-unwind-tables -fno-strict-aliasing  -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE -pthread -I/usr/include/httpd  -I/usr/include/apr-1   -I/usr/include/apr-1   -c -o mod_thumb.lo mod_thumb.c && touch mod_thumb.slo
mod_thumb.c: In function 'thumb_register_hooks':
mod_thumb.c:189: warning: implicit declaration of function 'ap_hook_translate_name'
/usr/lib/apr-1/build/libtool --silent --mode=link gcc -o mod_thumb.la  -rpath /usr/lib/httpd/modules -module -avoid-version    mod_thumb.lo
/usr/lib/httpd/build/instdso.sh SH_LIBTOOL='/usr/lib/apr-1/build/libtool' mod_thumb.la /usr/lib/httpd/modules
/usr/lib/apr-1/build/libtool --mode=install cp mod_thumb.la /usr/lib/httpd/modules/
cp .libs/mod_thumb.so /usr/lib/httpd/modules/mod_thumb.so
cp .libs/mod_thumb.lai /usr/lib/httpd/modules/mod_thumb.la
cp .libs/mod_thumb.a /usr/lib/httpd/modules/mod_thumb.a
chmod 644 /usr/lib/httpd/modules/mod_thumb.a
ranlib /usr/lib/httpd/modules/mod_thumb.a
PATH="$PATH:/sbin" ldconfig -n /usr/lib/httpd/modules

--- SNIP ---

chmod 755 /usr/lib/httpd/modules/mod_thumb.so

3、4行目で「ap_hook_translate_name を明示的に宣言したらどうなんだい?」って言われてます。

mod_thumb.c: In function 'thumb_register_hooks':
mod_thumb.c:189: warning: implicit declaration of function 'ap_hook_translate_name'

コンパイルは完了するし Apache をリスタートしても動作に問題なさそうなんですけど、やっぱり警告は気持ち悪いので ap_hook_translate_name() が 宣言されている http_request.h を #include して警告なしにコンパイルが完了。
利用するフックによって /path/to/httpd/include 内のヘッダを #include しないと警告が出る場合がありますよというお話。

Class::MOP(0.81) と Data::Visitor::Callback(0.22) で警告

Moose が 0.74 になったのに併せて Class::MOP が 0.81 になって今まで警告なしに動いていたスクリプトで警告が出るようになった。

The compute_all_applicable_attributes method has been deprecated. Use get_all_attributes instead.
 at /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi/Class/MOP/Class.pm line 929
        Class::MOP::Class::compute_all_applicable_attributes('Class::MOP::Class::__ANON__::SERIAL::41=HASH(0x8a0b850)') called at /usr/lib/perl5/site_perl/5.8.8/Data/Visitor/Callback.pm line 42
        Data::Visitor::Callback::BUILDARGS('Data::Visitor::Callback', 'plain_value', 'CODE(0x9c09398)') called at generated method (unknown origin) line 4
        Data::Visitor::Callback::new('Data::Visitor::Callback', 'plain_value', 'CODE(0x9c09398)') called at /home/travail/public_html/SVNHOME/Shiori/bin/utils/shiori/../../../lib/Shiori/ConfigLoader.pm line 86
        Shiori::ConfigLoader::load('Shiori::ConfigLoader=HASH(0x9bf1c50)') called at /home/travail/public_html/SVNHOME/Shiori/bin/utils/shiori/../../../lib/Shiori/ConfigLoader.pm line 33
        Shiori::ConfigLoader::new('Shiori::ConfigLoader') called at /home/travail/public_html/SVNHOME/Shiori/bin/utils/shiori/../../../lib/Shiori/DateTime.pm line 44
        Shiori::DateTime::now('Shiori::DateTime') called at /home/travail/public_html/SVNHOME/Shiori/bin/utils/shiori/../../../lib/Shiori/Schema/Tag.pm line 162
        Shiori::Schema::Tag::update_shiori_count('Shiori::Schema::Tag=HASH(0x9c0a634)') called at /home/travail/public_html/SVNHOME/Shiori/bin/utils/shiori/../../../lib/Shiori/Schema/Shiori.pm line 260
        Shiori::Schema::Shiori::create_tags('Shiori::Schema::Shiori=HASH(0x9bf15d8)') called at /home/travail/public_html/SVNHOME/Shiori/bin/utils/shiori/../../../lib/Shiori/API/Shiori.pm line 97
        Shiori::API::Shiori::__ANON__() called at /usr/lib/perl5/site_perl/5.8.8/DBIx/Class/Storage/DBI.pm line 626
        DBIx::Class::Storage::DBI::txn_do('DBIx::Class::Storage::DBI::mysql=HASH(0x9a341c4)', 'CODE(0x9a35620)') called at /usr/lib/perl5/site_perl/5.8.8/DBIx/Class/Schema.pm line 734
        DBIx::Class::Schema::txn_do('Shiori::Schema=HASH(0x9a4c4d4)', 'CODE(0x9a35620)') called at /home/travail/public_html/SVNHOME/Shiori/bin/utils/shiori/../../../lib/Shiori/API/Shiori.pm line 110
        eval {...} called at /home/travail/public_html/SVNHOME/Shiori/bin/utils/shiori/../../../lib/Shiori/API/Shiori.pm line 110
        Shiori::API::Shiori::update('Shiori::API::Shiori=HASH(0x9a216e0)', 'HASH(0x9b39534)') called at ./update.pl line 24
        main::main() called at ./update.pl line 11

出力された警告の3行目を見ると

Class::MOP::Class::compute_all_applicable_attributes('Class::MOP::Class::__ANON__::SERIAL::41=HASH(0x8a0b850)') called at /usr/lib/perl5/site_perl/5.8.8/Data/Visitor/Callback.pm line 42

と言われる。
素直に Data::Visitor::Callback の42行目あたりを覗いてみると BUILDARGS の中で compute_all_applicable_attributes をコールしている。

sub BUILDARGS {
    my ( $class, @args ) = @_;

    my $args = $class->SUPER::BUILDARGS(@args);

    # ここね
    my %init_args = map { $_->init_arg => undef } $class->meta->compute_all_applicable_attributes;

    my %callbacks = map { $_ => $args->{$_} } grep { not exists $init_args{$_} } keys %$args;

Class:MOP の 0.80_01 の Changes で

- compute_all_applicable_attributes is deprecated, use get_all_attributes

となっている。

Data::Visitor の AUTHOR の Yuval は Class::MOP の CONTRIBUTOR だからそのうち直る。って言うか、Class::MOP は IRC ないのか?

追記
じゃ、42行目の

$class->meta->compute_all_applicable_attributes;

$class->meta->get_all_attributes;

に変更したらいいのかと言うとそうわけでもなく、Data::Visitor::Callback では Squirrel で Moose と Mouse の切り分けを行っていて Moose を使用していた場合は get_all_attributes でいいのだけれど、Mouse を使用していた場合は見事に

Can't locate object method "get_all_attributes" via package "Mouse::Meta::Class"

でコケる。

追追記
Can't locate object method "get_all_attributes" via package "Mouse::Meta::Class"

は Mouse を 0.20 にすると解決する。

Moose と Mouse と QueueQ4M(0.00018)

私信になりますが、改めてという意味で別記事で。あと、はてなのアカウント持っていないので。

QueueQ4M (0.00018) 動いてます。

  • Any::Moose - 0.05
  • Moose - 0.72
  • Mouse - 0.17
  • Queue::Q4M - 0.00018

の環境ですっごい動いてます。

本来ならパッチを送りたいところでしたが如何せん Mouse と Moose に不慣れなものでああいった記事を書きました。
修正ありがとうございます。

Moose と Mouse と QueueQ4M(0.00017)

Queue::Q4M をバージョン 0.00017 にアップグレードしたら 0.00016 まで動いていたスクリプトが動かなくなった。

  • Any::Moose - 0.04
  • Moose - 0.71
  • Mouse - 0.17
  • Queue::Q4M - 0.00017

Queueu::Q4M を実際に使ってるプロジェクトではモジュール化してしまってデバッグがちょこっとしずらいので、簡単なスクリプトを書いてみる。
ちなみに、そのプロジェクトでは Moose も Mouse も使っていないので use Queue::Q4M より先に Moose なり Mouse なりがロードされていることはない。

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
#use Moose;
#use Mouse;
use Queue::Q4M;

our $table = 'queue_export';

main();
exit;

sub main {
    my $q4m = Queue::Q4M->connect(
        connect_info => [
            'dbi:mysql:dbname=shiori_local;host=192.168.1.1;port=3308',
            'username', 'password'
        ]
    );
    while ( $q4m->next($table) ) {
        my $queue = $q4m->fetch_hashref( $table,
            [qw(created_on member_id type)] );
        warn Dumper($queue);
    }
}

こんなコードを実行してキューを入れてみると

[travail@mina]~% ./queue_export.pl
Attribute (__res) does not pass the type constraint because: Validation failed for 'Maybe[Queue::Q4M::Result]' failed with value Queue::Q4M::Result=ARRAY(0x9c32cac) at /usr/lib/perl5/site_perl/5.8.8/Mouse/Meta/Attribute.pm line 339
        Mouse::Meta::Attribute::verify_type_constraint_error('Mouse::Meta::Attribute=HASH(0x9c058b0)', '__res', 'Queue::Q4M::Result=ARRAY(0x9c32cac)', 'Maybe[Queue::Q4M::Result]') called at (eval 18) line 5
        Mouse::Meta::Attribute::__ANON__('Queue::Q4M=HASH(0x9be2978)', 'Queue::Q4M::Result=ARRAY(0x9c32cac)') called at /usr/lib/perl5/site_perl/5.8.8/Queue/Q4M.pm line 159
        Queue::Q4M::next('Queue::Q4M=HASH(0x9be2978)', 'queue_export') called at ./queue_export.pl line 22        main::main() called at ./queue_export.pl line 12

なんてエラーが出てきちゃう。0.00016 までは動いていたのになぁ。
0.00017 の Changes を見てみると

0.00017 - 20 Feb 2009
  - s/Squirrel/Any::Moose/g

Moose, Mouse の切り替えを Any::Moose に変えたみたい。
ということで、さっきのスクリプトの "use Moose", "use Mouse" のコメントアウトを順番にはずして試してみると、"use Moose" されているときはスクリプトが動いて、"use Mouse" されているときは動かない。

Queue::Q4M - 0.00016 の場合

  • 明示的に Moose, Mouse をロードしていない場合でも動く
  • 明示的に Moose をロードしている場合でも動く
  • 明示的に Mouse をロードしている場合でも動く

Queue::Q4M - 0.00017 の場合

  • 明示的に Moose, Mouse をロードしていない場合は動かない
  • 明示的に Moose をロードしている場合は動く
  • 明示的に Mouse をロードしている場合でも動かない

この結果は Mouse を 0.16 に下げても同じだったし、Any::Moose を 0.03 に下げてもだめだった。
と言うか、Queue::Q4M のインストールで DB につなぎにいかないでインストールしてたんですよね。面倒なので。
改めて DB つないでテストしてみたら同じエラーがちゃんと出てた。テストがちゃんと書かれててもインストールする側がちゃんと実行しなけりゃ意味ないですね。ごめんなさい、ごめんなさい。

文字実体参照(実体参照)•数値文字参照(文字参照)を RSS1.0 で表示する

Firefox でちょん切れるです。IE に至ってはパースエラー。

とあるプロジェクトで吐いた RSS がどうも調子が悪い。
その RSS はこんな感じの。

ちょん切れちゃってる RSS

4つ目の item の「Emacs の Tramp こんなに便利とは - ひげぽん OSとか作っちゃうかMona-」から下がちょん切れてる。ソースを見ても確かに20件あるのに5つ目の item の「mixi Engineers’ Blog » DBMによるテーブルデータベース その弐」以降の item が表示されない。

  4つ目の item
  <item rdf:about="http://d.hatena.ne.jp/higepon/20090126/1232937495">
    <title> Emacs の Tramp こんなに便利とは - ひげぽん OSとか作っちゃうかMona-</title>
    <link>http://d.hatena.ne.jp/higepon/20090126/1232937495</link>
    <description>便利だ。</description>
    <content:encoded>便利だ。</content:encoded>
    <dc:date>2009-01-27T03:05:52</dc:date>
    <dc:subject>emacs</dc:subject>
    <dc:subject>TIPS</dc:subject>
    <dc:subject>ssh</dc:subject>
    <dc:subject>Tramp</dc:subject>
  </item>
  5つ目の item
  <item rdf:about="http://alpha.mixi.co.jp/blog/?p=292">
    <title>mixi Engineers&#8217; Blog &raquo; DBMによるテーブルデータベース その弐</title>
    <link>http://alpha.mixi.co.jp/blog/?p=292</link>
    <description></description>
    <content:encoded></content:encoded>
    <dc:date>2009-01-27T03:04:22</dc:date>
    <dc:subject>mixi</dc:subject>
    <dc:subject>mikio</dc:subject>
    <dc:subject>DBM</dc:subject>
    <dc:subject>TokyoCabinet</dc:subject>
  </item>

RSS のソースをのぞくと気になるところを発見。mixi Engineers' Blog の &#8217;&raquo; が非常に怪しい。以前、 HTML をパースして title タグを取ろうとしたときも「うぐぅ」って言っていたような気もする。きっと今回もそれが原因だと思う。
グーグルさんで調べてみると RSS(XML) で使用できる実体参照は

  • &amp;(&)
  • &lt;(<)
  • &gt;(>)
  • &apos;(')
  • &quot;(")
のみのようです。ちなみに、これらを定義済み実体と言うそうです。

mixi Engineers' Blog の &raquo; は RSS(XML) では使用することができないので今回僕が吐いた RSS がちょん切れてしまって「うぐぅ」となっているのだろうと思います。
文字参照の &#8217; の方も多分使用できないのだと思います。

うぐぅ。
上記の使用できる実体参照・文字参照はあくまでデフォルトでということで、&#8217;&raquo; が定義された DTD を読み込めばよいそうです。
ということで、今回読み込んだ DTD はこれ。

http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd

その DTD を読み込んだ RSS がこれ。

ちょん切れちゃってない RSS

途中でちょん切れることなく表示されていますよね?XML のソースを見ると

  <item rdf:about="http://alpha.mixi.co.jp/blog/?p=292">
    <title>mixi Engineers&#8217; Blog &raquo; DBMによるテーブルデータベース その弐</title>
    <link>http://alpha.mixi.co.jp/blog/?p=292</link>
    <description></description>
    <content:encoded></content:encoded>
    <dc:date>2009-01-27T03:04:22</dc:date>
    <dc:subject>mixi</dc:subject>
    <dc:subject>mikio</dc:subject>
    <dc:subject>DBM</dc:subject>
    <dc:subject&>TokyoCabinet</dc:subject>
  </item>

&#8217;&raquo; のままですね。ちゃんと参照されているみたいです。

めでたし、めでたしと言いたいところだけれども、はてブなんかの RSS のソースを見ると &#8217; に、&raquo;» になっていますが RSS を吐く際にアプリ側で変換しているのでしょうか?
この場合、常套手段って何なんでしょう?XML だと言っているのに XHMLT の DTD を読み込むのは間違っている気がしてならない。RSS2.0 の場合はどうなのだろうか?Atom の場合は?
うぬぅ。

そうそう、僕の MT には記事を書いている途中に記事の「公開状態」がこっそり「公開」になる新機能が着いています。書いている途中に記事を保存するとうっかり PING を送信してしまいます。
その更新扱いにされている自分の記事をRSSリーダー越し眺めているときってS目線で見ればいいのかM目線で見ればいいのか複雑な気持ちになります。

追記:
W3C の RSS の構文チャックするとダメよダメダメダメ星人って言われる。

Index of all entries

Search
Feeds

Return to page top