<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>tmty.jp &#187; Lighttpd</title>
	<atom:link href="http://tmty.jp/tag/lighttpd/feed/" rel="self" type="application/rss+xml" />
	<link>http://tmty.jp</link>
	<description>tmtysk が前よりも、もうちょっとだけコマメに更新していくかもしれないブログ</description>
	<lastBuildDate>Tue, 08 Jun 2010 13:19:26 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<link rel="http://api.friendfeed.com/2008/03#sup" xmlns="http://www.w3.org/2005/Atom" type="application/json" href="http://friendfeed.com/api/public-sup.json#fdff53faaa"/>		<item>
		<title>lighttpdで指定のリクエストヘッダ項目を参照するプラグインを書いた</title>
		<link>http://tmty.jp/2007/08/20/lighttpd%e3%81%a7%e6%8c%87%e5%ae%9a%e3%81%ae%e3%83%aa%e3%82%af%e3%82%a8%e3%82%b9%e3%83%88%e3%83%98%e3%83%83%e3%83%80%e9%a0%85%e7%9b%ae%e3%82%92%e5%8f%82%e7%85%a7%e3%81%99%e3%82%8b%e3%83%97%e3%83%a9/</link>
		<comments>http://tmty.jp/2007/08/20/lighttpd%e3%81%a7%e6%8c%87%e5%ae%9a%e3%81%ae%e3%83%aa%e3%82%af%e3%82%a8%e3%82%b9%e3%83%88%e3%83%98%e3%83%83%e3%83%80%e9%a0%85%e7%9b%ae%e3%82%92%e5%8f%82%e7%85%a7%e3%81%99%e3%82%8b%e3%83%97%e3%83%a9/#comments</comments>
		<pubDate>Sun, 19 Aug 2007 16:25:04 +0000</pubDate>
		<dc:creator>tmtysk</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[Lighttpd]]></category>
		<category><![CDATA[Plugin]]></category>

		<guid isPermaLink="false">http://wp.tmty.jp/2007/08/20/lighttpd%e3%81%a7%e6%8c%87%e5%ae%9a%e3%81%ae%e3%83%aa%e3%82%af%e3%82%a8%e3%82%b9%e3%83%88%e3%83%98%e3%83%83%e3%83%80%e9%a0%85%e7%9b%ae%e3%82%92%e5%8f%82%e7%85%a7%e3%81%99%e3%82%8b%e3%83%97%e3%83%a9/</guid>
		<description><![CDATA[lighttpd-1.4.15 + FastCGI な環境で、HTTP リクエストヘッダ中の任意のレコードを参照して、その内容によって環境変数を設定しておきたい、という状況。apache であれば SetEnvIf ディ [...]]]></description>
			<content:encoded><![CDATA[<p>lighttpd-1.4.15 + FastCGI な環境で、HTTP リクエストヘッダ中の任意のレコードを参照して、その内容によって環境変数を設定しておきたい、という状況。apache であれば SetEnvIf ディレクティブを使うことで、</p>
<pre class="prettyprint">
SetEnvIf X-Hoge &quot;.*&quot; bar=yes
</pre>
<p>とかで設定できるが、lighttpdではこういう事ができないらしい。lighttpdの設定でSetEnvIfのような条件分岐処理を書こうとすると、<a href="http://trac.lighttpd.net/trac/wiki/Docs%3AConfiguration#conditional-configuration">マニュアルのConditional Configuration</a>によれば、</p>
<blockquote><p>
&lt;field&gt; &lt;operator&gt; &lt;value&gt; {<br />
&#8230;<br />
}
</p></blockquote>
<p>てな記述ができるのだが、&lt;field&gt; に指定できるのは $HTTP や $SERVER で参照できる、固定の変数だけのようだ。$HTTP[&quot;X-Hoge&quot;] とか試しに指定してみたけど、syntax error で無視されてしまう。</p>
<p>デフォルト提供されている mod_xx や設定方法のマニュアルを当たってみたり、あと、騙し騙し使えそうな設定方法を試行してみたが、どれもダメだった。mod_setenv を使えば環境変数の設定まではできるんだが、その手前の条件記法を拡張する事ができないみたいだ。</p>
<p>ということで、lighttpd の拡張プラグインを書いてみようと思い立った。条件記法の拡張まではできなさそう（うまくやればできるかも??）だが、デフォルト指定できない特定のHTTPリクエストヘッダを参照し、環境変数を設定する、というだけであれば、プラグインで書けそうだ。ということで、プラグイン作成の作業メモ。</p>
<p><a href="http://trac.lighttpd.net/trac/wiki/HowToWriteALighttpdPlugin">Writing Plugins のページ</a>に簡単なチュートリアルがあるので、これに従ってプラグインを書いてみた。プラグインの作成ステップは、大きく以下のような感じ。</p>
<ol>
<li>mod_skeleton.c からスケルトンコードのコピー</li>
<li>スケルトンコードを書き換える形でプラグインを記述</li>
<li>プラグインの Makefile.am の修正</li>
<li>プラグインの make .. Makefile.in の生成と作成したプラグインのプリコンパイル</li>
<li>lighttpd の configure .. &#8211;enable-maintainer-mode で Makefile を書き換える</li>
<li>lighttpd の make &#038;&#038; make install</li>
</ol>
<p>本家のチュートリアルには上記 (4) のステップが抜けているので注意（(6) も抜けてるけど）。あと、プラグインの作成には <a href="http://trac.lighttpd.net/trac/wiki/Docs%3AInternalHTTPStates">lighttpd の動作モデル</a>と、<a href="http://trac.lighttpd.net/trac/wiki/Docs%3AInternalPlugins">プラグインがフックできるインタフェース（エントリポイント）</a>の概要くらいは見ておく必要があると思う。</p>
<p>プラグインソースコードの構成（レイアウト）は、<a href="http://trac.lighttpd.net/trac/wiki/HowToWriteALighttpdPlugin">上記のチュートリアル</a>を参照。意訳すると、</p>
<ol>
<li>プラグイン処理中で使用する構造体の定義</li>
<li>構造体の初期化処理</li>
<li>configuration file の parse 処理 .. set_defaults</li>
<li>プラグインが条件分岐中で適用された場合の処理 .. patch-function</li>
<li>プラグインのメイン処理</li>
<li>プラグインの初期化処理(プラグイン中で定義した関数と、プラグインインタフェースとの対応はここで定義する) .. plugin_init</li>
</ol>
<p>こんなかんじの構成になっている。</p>
<p>あとは、既存のプラグインソースなどを参考に、プラグインを書いていく。今回書いたプラグイン mod_addenv.c は、こんなかんじ。</p>
<pre class="prettyprint">
#include <stdlib.h>
#include <string.h>
#include "base.h"
#include "log.h"
#include "buffer.h"
#include "plugin.h"
/* plugin config for all request/connections */
typedef struct {
int handled;
} handler_ctx;
typedef struct {
array *match;
} plugin_config;
typedef struct {
PLUGIN_DATA;
plugin_config **config_storage;
plugin_config conf;
} plugin_data;
static handler_ctx * handler_ctx_init() {
handler_ctx * hctx;
hctx = calloc(1, sizeof(*hctx));
hctx->handled = 0;
return hctx;
}
static void handler_ctx_free(handler_ctx *hctx) {
free(hctx);
}
/* init the plugin data */
INIT_FUNC(mod_addenv_init) {
plugin_data *p;
p = calloc(1, sizeof(*p));
return p;
}
/* detroy the plugin data */
FREE_FUNC(mod_addenv_free) {
plugin_data *p = p_d;
UNUSED(srv);
if (!p) return HANDLER_GO_ON;
if (p->config_storage) {
size_t i;
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
array_free(s->match);
free(s);
}
free(p->config_storage);
}
free(p);
return HANDLER_GO_ON;
}
/* handle plugin config and check values */
SETDEFAULTS_FUNC(mod_addenv_set_defaults) {
plugin_data *p = p_d;
size_t i = 0;
config_values_t cv[] = {
{ "addenv.env", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
if (!p) return HANDLER_ERROR;
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
s = calloc(1, sizeof(plugin_config));
s->match    = array_init();
cv[0].destination = s->match;
p->config_storage[i] = s;
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
}
return HANDLER_GO_ON;
}
#define PATCH(x)
p->conf.x = s->x;
static int mod_addenv_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
PATCH(match);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
if (buffer_is_equal_string(du->key, CONST_STR_LEN("addenv.env"))) {
PATCH(match);
}
}
}
return 0;
}
#undef PATCH
URIHANDLER_FUNC(mod_addenv_uri_handler) {
plugin_data *p = p_d;
size_t i, j;
handler_ctx *hctx;
if (con->plugin_ctx[p->id]) {
hctx = con->plugin_ctx[p->id];
} else {
hctx = handler_ctx_init();
con->plugin_ctx[p->id] = hctx;
}
if (hctx->handled) {
return HANDLER_GO_ON;
}
hctx->handled = 1;
mod_addenv_patch_connection(srv, con, p);
for (i = 0; i < con->request.headers->used; i++) {
data_string *dsh;
dsh = (data_string *)con->request.headers->data[i];
if(dsh->key->used &#038;&#038; dsh->value->used &#038;&#038; (0 == strcasecmp(dsh->key->ptr, "X-HOGE"))) {
for (j = 0; j < p->conf.match->used; j++) {
data_string *ds = (data_string *)p->conf.match->data[j];
data_string *ds_dst;
if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
ds_dst = data_string_init();
}
buffer_copy_string_buffer(ds_dst->key, ds->key);
buffer_copy_string_buffer(ds_dst->value, ds->value);
array_insert_unique(con->environment, (data_unset *)ds_dst);
}
}
}
/* not found */
return HANDLER_GO_ON;
}
REQUESTDONE_FUNC(mod_addenv_reset) {
plugin_data *p = p_d;
UNUSED(srv);
if (con->plugin_ctx[p->id]) {
handler_ctx_free(con->plugin_ctx[p->id]);
con->plugin_ctx[p->id] = NULL;
}
return HANDLER_GO_ON;
}
/* this function is called at dlopen() time and inits the callbacks */
int mod_addenv_plugin_init(plugin *p) {
p->version     = LIGHTTPD_VERSION_ID;
p->name        = buffer_init_string("addenv");
p->init        = mod_addenv_init;
p->handle_uri_clean  = mod_addenv_uri_handler;
p->set_defaults  = mod_addenv_set_defaults;
p->cleanup     = mod_addenv_free;
p->handle_request_done = mod_addenv_reset;
p->data        = NULL;
return 0;
}
</pre>
<p>このソースを mod_addenv.c として保存し、lighttpd-1.4.15/src 以下で make したあと、./configure &#8211;enable-maintainer-mode &#038;&#038; make &#038;&#038; make install する。既存の環境がある場合は、テスト用に &#8211;prefix 指定して違うところに入れた方がいいかも。あとは lighttpd.conf で、</p>
<pre class="prettyprint">
server.modules = ( &quot;mod_addenv&quot; )
addenv.env = (
&nbsp;&quot;bar&quot; => &quot;yes&quot;
)
</pre>
<p>とか設定しておけば、lighttpd でも上述の SetEnvIf のような効果が得られる。X-HOGE をソース中に書いているのがダサいな。なんとかしたい。</p>
<p>ところで、プラグインの記述方法は、ちょっと癖があるようにも思えたが、こういうモノなのだろうか。まあ、一度やってみておいて損は無いかな、とはおもった。他にもいろいろ使い道ありそうだし。<br />
<br/><br/><strong>関連していそうなエントリ:</strong>
<ul class="similar-posts">
<li><a href="http://tmty.jp/2007/09/25/ubuntu-ivtv-102-gv-mvprx2-%e3%81%a7%e3%83%86%e3%83%ac%e3%83%93%e8%a6%96%e8%81%b4%e3%81%a7%e3%81%8d%e3%81%9f/" rel="bookmark" title="2007 年 9 月 25 日">ubuntu + ivtv-1.0.2 + GV-MVP/RX2 でテレビ視聴できた</a></li>
</ul>
<p><!-- Similar Posts took 26.401 ms --></p>
]]></content:encoded>
			<wfw:commentRss>http://tmty.jp/2007/08/20/lighttpd%e3%81%a7%e6%8c%87%e5%ae%9a%e3%81%ae%e3%83%aa%e3%82%af%e3%82%a8%e3%82%b9%e3%83%88%e3%83%98%e3%83%83%e3%83%80%e9%a0%85%e7%9b%ae%e3%82%92%e5%8f%82%e7%85%a7%e3%81%99%e3%82%8b%e3%83%97%e3%83%a9/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.688 seconds -->
