mod_headers に note 機能が追加されました

この投稿は Apache httpd Advent Calendar 2013 ではありません...

2013-11-25 に Apache httpd 2.4.7 がリリースされました。 CHANGES_2.4.7 この中に

*) mod_headers: Add 'Header note header-name note-name' for copying a response
headers value into a note. [Eric Covener]

という変更を見つけました。これは!!
Apache で Response Header を消しつつその値をログに書き出す」で書いた機能が Apache に追加されたようです。

当該部分のコードはこれ

case hdr_note:
    apr_table_setn(r->notes, process_tags(hdr, r), apr_table_get(headers, hdr->header));
    break;

私は subprocess_env にコピーしたのですが、これは notes にコピーしていますね。 notes っていうのは module 間でデータを受け渡しできるメモ用テーブルです。 mod_log_config で %{VARNAME}n として書き出すことができます。「モニカジ#3に参加してきた」で触れた @kazeburo さんの mod_copy_header もこの notes で実装されてます。(あ、Example の LogFormat のところにミスが...)

mod_headers の note は次のように使います。CGI で出力するヘッダーを扱う場合は always が必要です(これでしばらくハマりました)。Proxy だったら不要。

Header [always] note X-Foo foo
Header [always] unset X-Foo
LogFormat "... %{foo}n" xxx

Client に返したくないデータのはずなので unset をお忘れなく。返して良いヘッダーをログに書き出すだけなら %{X-Foo}o で出来ますし。

おまけ

2.4.7 の mod_headers には setifempty という機能も追加されていました。「Set If Empty」で名前の通りの機能ですね。

*) mod_headers: Add 'setifempty' command to Header and RequestHeader.
[Eric Covener]

モニカジ#3に参加してきた

3月8日(金) Monitoring Casual Talk #3 に参加してきました。
参加者全員が発表者というイベントです。ビールを飲みながらのゆるいイベントです。
今回は paperboy&co. さんの主催でした。会場の準備、二次会の準備などありがとうございました。
GMOグループの Friday Night Party がうらやましかった。きれいなお姉さんがお酒を配ってくれるなんて。

私の発表は以前このBlogにも書いた Apache で Response Header を消しつつその値をログに書き出す について。

でも、@kazeburo さんから次のようなツッコミがっ!!

ん? mod_copy_header?
ぐぐったら出てきました。
mod_copy_header ってのを書いた話 Re: Apache上のPerl FastCGIはCustomLogにデータを書くことができるか?

おぉ、こんなものが。これで良いですね。私もひとつのモジュールとして独立化させようかと思いましたが面倒なので諦めてました。

今回のモニカジの中心的な話題はサーバー台数が増えると監視の設定が大変なのでそれをどうやってツールで自動化するかというものでした。

モニカジ参加者のほとんどやTwitterでフォローしてる人とかが年下とわかり少しショックを受けたりもしましたが、また次回もよろしくお願いします。京都へ行きたいところですがちょっと無理ですね。

Apache で Response Header を消しつつその値をログに書き出す

Apache のログにアプリから返された Response Header の情報を書きたいが、クライアントには送りたくないというものがあった場合、mod_headers で unset してしまうと %{HeaderName}o では書き出せなくなってしまいます。そこで、Apache 2.4 むけに patch を書きました。

ログにユーザーを特定する内部IDを書き出したいがクライアントには返したくないという場合に便利ではないでしょうか。

Header toenv {HeaderName} {EnvName}

で、HeaderName というヘッダーの値を subprocess_env の EnvName にセットし、ヘッダーを消します。これで %{EnvName}e でログに書き出せます。

diff -uNr httpd-2.4.3.orig/modules/metadata/mod_headers.c httpd-2.4.3/modules/metadata/mod_headers.c
--- httpd-2.4.3.orig/modules/metadata/mod_headers.c	2011-12-05 09:08:01.000000000 +0900
+++ httpd-2.4.3/modules/metadata/mod_headers.c	2013-02-01 16:25:33.279766574 +0900
@@ -96,7 +96,8 @@
     hdr_unset = 'u',            /* unset header */
     hdr_echo = 'e',             /* echo headers from request to response */
     hdr_edit = 'r',             /* change value by regexp, match once */
-    hdr_edit_r = 'R'            /* change value by regexp, everymatch */
+    hdr_edit_r = 'R',           /* change value by regexp, everymatch */
+    hdr_toenv = 'E'             /* copy to subprocess_env and unset */
 } hdr_actions;
 
 /*
@@ -417,6 +418,8 @@
         new->action = hdr_merge;
     else if (!strcasecmp(action, "unset"))
         new->action = hdr_unset;
+    else if (!strcasecmp(action, "toenv"))
+        new->action = hdr_toenv;
     else if (!strcasecmp(action, "echo"))
         new->action = hdr_echo;
     else if (!strcasecmp(action, "edit"))
@@ -425,7 +428,7 @@
         new->action = hdr_edit_r;
     else
         return "first argument must be 'add', 'set', 'append', 'merge', "
-               "'unset', 'echo', 'edit', or 'edit*'.";
+               "'unset', 'toenv', 'echo', 'edit', or 'edit*'.";
 
     if (new->action == hdr_edit || new->action == hdr_edit_r) {
         if (subs == NULL) {
@@ -736,6 +739,11 @@
         case hdr_unset:
             apr_table_unset(headers, hdr->header);
             break;
+        case hdr_toenv:
+            apr_table_add(r->subprocess_env, process_tags(hdr, r),
+                          apr_table_get(headers, hdr->header));
+            apr_table_unset(headers, hdr->header);
+            break;
         case hdr_echo:
             v.r = r;
             v.hdr = hdr;

誰かの役に立つかな?