出力されたコンテンツをoutput filterで覗き見る

最近覗き系が多い気がしますが、解決したのでまとめておきます。


まずはソースから、デバッグ用にモジュールを1ついい加減に作ってしまいました。

static int outputfilter(ap_filter_t* f, apr_bucket_brigade* bb)
{
    request_rec* r = f->r;
    apr_bucket* backet;
    apr_size_t length = 0;
    apr_status_t read_status;

    for (backet = APR_BRIGADE_FIRST(bb);
        backet != APR_BRIGADE_SENTINEL(bb);
        backet = APR_BUCKET_NEXT(backet))
    {
        const char *str;

        if (APR_BUCKET_IS_EOS(backet))
        {
            return ap_pass_brigade(f->next, bb);
        }

        read_status = apr_bucket_read(backet, &str, &length, APR_BLOCK_READ);
        if (read_status != APR_SUCCESS)
        {
            ERROR("apr_bucket_read error [\d]", read_status);
            return read_status;
        }

        total_length += length;

        if (length > 0)
        {
            char* temp = (char*)apr_palloc(r->pool, total_length);
            if (content != NULL) memcpy(temp, content, total_length - length);
            memcpy(temp + total_length - length, str, length);
            content = temp;
        }
    }

    FUNC_TRACE("total_length = %d", total_length);
    return ap_pass_brigade(f->next, bb);
}


まず1つ目のポイントがid:hkrnさんから教えていただいた、bucketのイテレートです。
APR_BRIGADE_FOREACHマクロは避けたほうがよいらしい(see http://www.schumann.cx/docs/apr-util/group__APR__Util__Bucket__Brigades.html#a80)
ので、別のマクロを利用して、forループでイテレートします。


2つ目のポイントは、1リクエストに対して、output filterが複数回呼ばれるので、覗き見するコンテンツを格納する変数がグローバルになっている点。
(マルチスレッドモードでApacheを動作させる場合は、この方法は正しくありません。tableなどに格納すべきでしょう。)


あと、id:higepon:20051121:1132566569で問題となっていた、出力が途中で切れしまう問題だが、原因が判明しました。
出力を覗くために、ap_log_errorでエラーログに出力していたのですが、こいつが長いコンテンツを途中でぶった切っていました(泣。