sotarokを勝手に祝う会

sotarokを勝手に祝う会に行ってまいりました!

僭越ながらこのたびはLTをさせていただいたので、その内容の紹介をさせていただきたく。(日立風)

皆様ご存知のことと思いますが、OSSコミュニティーにおいて、開発者が結婚する際には、新郎と新婦に

オリジナル○○○○○○○○○○○

を贈呈するという慣習があります。

はい、もちろん

オリジナルApacheモジュール

ですね。

というわけで、今回は

  • mod_sotarok
  • mod_mikko

を作らせていただきました。

mod_sotarok-mod_mikko at github.com

mod_sotarok.c:

/* 
 * Copyright (c) 2010 Moriyoshi Koizumi
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_main.h"
#include "http_protocol.h"
#include "http_request.h"
#include "util_script.h"
#include "http_connection.h"

#include "apr_strings.h"

#include <stdio.h>

module AP_MODULE_DECLARE_DATA sotarok_module;

static const char *data[] = {
    "VAAAAAgAAAABAAEAAAADAAEAAQAAAAIAAQADAAAAAgABAAQAAAACAAEABAAAAAIAAQABAAAAAwABAAEAAAAH",
    "AAEAAQAAAAMAAQABAAAAAQABAAUAAAABAAEABAAAAAIAAQAEAAAAAwABAAMAAAACAAEAAQAAAAMAAQABAAAA",
    "AgABAAQAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAABAAEAAQAAAAMAAQABAAAAAQABAAEAAAADAAEAAQAA",
    "AAEAAQABAAAAAwABAAEAAAABAAEAAQAAAAMAAQABAAAABwABAAEAAAADAAEAAQAAAAEAAQABAAAABQABAAEA",
    "AAADAAEAAQAAAAEAAQABAAAAAwABAAEAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAABAAEAAQAAAAcAAQAB",
    "AAAAAwABAAEAAAADAAEAAQAAAAEAAQABAAAAAwABAAEAAAABAAEAAQAAAAMAAQABAAAAAQABAAEAAAADAAEA",
    "AQAAAAIAAQABAAAAAQABAAEAAAAIAAEAAQAAAAEAAQABAAAAAQABAAEAAAABAAEAAQAAAAUAAQABAAAAAwAB",
    "AAEAAAABAAEAAQAAAAMAAQABAAAAAwABAAEAAAADAAEAAgAAAAIAAQABAAAAAQABAAEAAAAHAAEAAQAAAAMA",
    "AQAFAAAAAQABAAUAAAABAAEABAAAAAIAAQAEAAAAAwABAAEAAAABAAEAAQAAAAgAAQABAAAAAQABAAEAAAAB",
    "AAEAAQAAAAEAAQAEAAAAAgABAAEAAAADAAEAAQAAAAEAAQABAAAAAwABAAEAAAADAAEAAQAAAAMAAQABAAAA",
    "AQABAAEAAAABAAEAAQAAAAEAAQABAAAAAQABAAMAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAABAAEAAQAA",
    "AAMAAQABAAAAAQABAAEAAAAFAAEAAQAAAAcAAQABAAAACQABAAEAAAABAAEAAQAAAAEAAQABAAAAAQABAAEA",
    "AAAFAAEAAQAAAAMAAQABAAAAAQABAAEAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAACAAEAAgAAAAEAAQAB",
    "AAAAAwABAAEAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAABAAEAAQAAAAMAAQABAAAAAQABAAEAAAAFAAEA",
    "AQAAAAcAAQABAAAACQABAAEAAAABAAEAAQAAAAEAAQABAAAAAQABAAEAAAAFAAEAAQAAAAMAAQABAAAAAQAB",
    "AAEAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAADAAEAAQAAAAEAAQABAAAAAwABAAEAAAAHAAEAAQAAAAMA",
    "AQABAAAAAQABAAEAAAADAAEAAQAAAAEAAQABAAAABQABAAEAAAAHAAEAAQAAAAoAAQABAAAAAQABAAEAAAAC",
    "AAEABQAAAAEAAQAEAAAAAgABAAQAAAADAAEAAwAAAAIAAQABAAAAAwABAAEAAAACAAEABAAAAAMAAQABAAAA",
    "AwAAAFQAAAAAAA=="
};

static int sotarok_handler(request_rec *r)
{
    int i;
    if (strcmp(r->handler, "sotarok-handler")) {
        return DECLINED;
    }

    ap_set_content_type(r, "text/plain; charset=US-ASCII");
    if (r->header_only) return OK;
    for (i = 0; i < sizeof(data) / sizeof(data[0]); i++) {
        ap_rputs(data[i], r);
        ap_rputs("\n", r);
    }
    return OK;
}

static void sotarok_register_hooks(apr_pool_t *p)
{
    ap_hook_handler(sotarok_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA sotarok_module =
{
    STANDARD20_MODULE_STUFF,
    NULL,                   /* per-directory config creator */
    NULL,                   /* dir config merger */
    NULL,                   /* server config creator */
    NULL,                   /* server config merger */
    NULL,                   /* command table */
    sotarok_register_hooks    /* set up other request processing hooks */
};

mod_mikko.c

/* 
 * Copyright (c) 2010 Moriyoshi Koizumi
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <assert.h>
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_main.h"
#include "http_protocol.h"
#include "http_request.h"
#include "util_script.h"
#include "http_connection.h"

#include "apr_strings.h"

#include <stdio.h>

module AP_MODULE_DECLARE_DATA mikko_module;

static unsigned int read_u32le(const char *p)
{
    return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}

static unsigned int read_u16le(const char *p)
{
    return p[0] | (p[1] << 8);
}

static char *base64_decode_all(apr_pool_t *pool, const char *buf, apr_size_t buf_len, apr_size_t *result_len)
{
    const char *p, *e = buf + buf_len;
    char *result, *q;
    q = result = apr_palloc(pool, (buf_len / 3) * 4);
    p = buf;
    while (p < e) {
        int l = apr_base64_decode(q, p);
        if (l == 0)
            p++;
        else {
            assert(l > 0);
            q += l;
            p += ((l + 2) / 3) * 4;
        }
    }

    *result_len = q - result;
    return result;
}

static apr_status_t mikko_do_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
{
    static const char prologue[] = "<html>\n\
<head>\n\
  <title>Happy Wedding!</title>\n\
  <style type=\"text/css\">\n\
.colored { color: red; }\n\
.uncolored { color: lightgray; }\n\
</style>\n\
</head>\n\
<body>\n\
<pre>";
    static const char epilogue[] = "</pre>\n\
</body>\n\
</html>\n";
    static const char span_colored_open[] = "<span class=\"colored\">";
    static const char span_uncolored_open[] = "<span class=\"uncolored\">";
    static const char span_close[] = "</span>";
    apr_status_t err = APR_SUCCESS;
    char *buf = 0;
    apr_size_t buf_len = 0;
    char *decoded_data = 0;
    unsigned int width, height;
    const char *p, *pe;
    const char *q;

    err = apr_brigade_pflatten(bb, &buf, &buf_len, f->r->pool);
    if (err)
        return err;
    apr_brigade_cleanup(bb);

    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_immortal_create(
        prologue, sizeof(prologue) - 1, f->c->bucket_alloc));

    {
        apr_size_t decoded_len;
        p = decoded_data = base64_decode_all(f->r->pool, buf, buf_len, &decoded_len);
        pe = decoded_data + decoded_len;
    }

    if (p >= pe)
        goto error;
    width = read_u32le(p), p += 4;
    if (p >= pe)
        goto error;
    height = read_u32le(p), p += 4;
   
    q = buf; 
    for (;;) { 
        int v, c;
        if (p >= pe)
            goto error;
        v = read_u16le(p), p += 2;
        if (p >= pe)
            goto error;
        c = read_u16le(p), p += 2;
        if (!c)
            break;
        if (v) {
            APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_immortal_create(
                span_colored_open, sizeof(span_colored_open) - 1, f->c->bucket_alloc));
            APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_transient_create(q, c,
                f->c->bucket_alloc));
            APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_immortal_create(
                span_close, sizeof(span_close) - 1, f->c->bucket_alloc));
        } else {
            APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_immortal_create(
                span_uncolored_open, sizeof(span_uncolored_open) - 1, f->c->bucket_alloc));
            APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_transient_create(q, c,
                f->c->bucket_alloc));
            APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_immortal_create(
                span_close, sizeof(span_close) - 1, f->c->bucket_alloc));
        }
        q += c;
        while (*q == '\n') {
            APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_transient_create(q, 1,
                f->c->bucket_alloc));
            q++;
        }
    }

    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_immortal_create(
        span_uncolored_open, sizeof(span_uncolored_open) - 1, f->c->bucket_alloc));
    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_transient_create(
        q, buf_len - (q - buf), f->c->bucket_alloc));
    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_immortal_create(
        span_close, sizeof(span_close) - 1, f->c->bucket_alloc));

    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_immortal_create(
        epilogue, sizeof(epilogue) - 1, f->c->bucket_alloc));

    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(f->c->bucket_alloc));

    f->r->content_type = "text/html; charset=US-ASCII";

    return ap_pass_brigade(f->next, bb);
error:
    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_immortal_create(
        "error", sizeof("error") - 1, f->c->bucket_alloc));
    APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(f->c->bucket_alloc));
    return ap_pass_brigade(f->next, bb);
}

static void mikko_register_hooks(apr_pool_t *p)
{
    ap_register_output_filter("MIKKO_OUT", mikko_do_out_filter, NULL, AP_FTYPE_RESOURCE);
}

module AP_MODULE_DECLARE_DATA mikko_module =
{
    STANDARD20_MODULE_STUFF,
    NULL,                   /* per-directory config creator */
    NULL,                   /* dir config merger */
    NULL,                   /* server config creator */
    NULL,                   /* server config merger */
    NULL,                   /* command table */
    mikko_register_hooks    /* set up other request processing hooks */
};

mod_sotarokを次のように組み込んで

LoadModule sotarok_module .libs/mod_sotarok.so

Listen 8080

<Location />
    SetHandler sotarok-handler
</Location>

PidFile /tmp/httpd.pid
LockFile /tmp/accept.lock
ErrorLog /tmp/error_log

Apacheにリクエストを投げると、次のような文字列が帰ってきます。

VAAAAAgAAAABAAEAAAADAAEAAQAAAAIAAQADAAAAAgABAAQAAAACAAEABAAAAAIAAQABAAAAAwABAAEAAAAH
AAEAAQAAAAMAAQABAAAAAQABAAUAAAABAAEABAAAAAIAAQAEAAAAAwABAAMAAAACAAEAAQAAAAMAAQABAAAA
AgABAAQAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAABAAEAAQAAAAMAAQABAAAAAQABAAEAAAADAAEAAQAA
AAEAAQABAAAAAwABAAEAAAABAAEAAQAAAAMAAQABAAAABwABAAEAAAADAAEAAQAAAAEAAQABAAAABQABAAEA
AAADAAEAAQAAAAEAAQABAAAAAwABAAEAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAABAAEAAQAAAAcAAQAB
AAAAAwABAAEAAAADAAEAAQAAAAEAAQABAAAAAwABAAEAAAABAAEAAQAAAAMAAQABAAAAAQABAAEAAAADAAEA
AQAAAAIAAQABAAAAAQABAAEAAAAIAAEAAQAAAAEAAQABAAAAAQABAAEAAAABAAEAAQAAAAUAAQABAAAAAwAB
AAEAAAABAAEAAQAAAAMAAQABAAAAAwABAAEAAAADAAEAAgAAAAIAAQABAAAAAQABAAEAAAAHAAEAAQAAAAMA
AQAFAAAAAQABAAUAAAABAAEABAAAAAIAAQAEAAAAAwABAAEAAAABAAEAAQAAAAgAAQABAAAAAQABAAEAAAAB
AAEAAQAAAAEAAQAEAAAAAgABAAEAAAADAAEAAQAAAAEAAQABAAAAAwABAAEAAAADAAEAAQAAAAMAAQABAAAA
AQABAAEAAAABAAEAAQAAAAEAAQABAAAAAQABAAMAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAABAAEAAQAA
AAMAAQABAAAAAQABAAEAAAAFAAEAAQAAAAcAAQABAAAACQABAAEAAAABAAEAAQAAAAEAAQABAAAAAQABAAEA
AAAFAAEAAQAAAAMAAQABAAAAAQABAAEAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAACAAEAAgAAAAEAAQAB
AAAAAwABAAEAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAABAAEAAQAAAAMAAQABAAAAAQABAAEAAAAFAAEA
AQAAAAcAAQABAAAACQABAAEAAAABAAEAAQAAAAEAAQABAAAAAQABAAEAAAAFAAEAAQAAAAMAAQABAAAAAQAB
AAEAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAADAAEAAQAAAAEAAQABAAAAAwABAAEAAAAHAAEAAQAAAAMA
AQABAAAAAQABAAEAAAADAAEAAQAAAAEAAQABAAAABQABAAEAAAAHAAEAAQAAAAoAAQABAAAAAQABAAEAAAAC
AAEABQAAAAEAAQAEAAAAAgABAAQAAAADAAEAAwAAAAIAAQABAAAAAwABAAEAAAACAAEABAAAAAMAAQABAAAA
AwAAAFQAAAAAAA==

見たところ base64 なわけですが、これをデコードしてみると、

$ php -r 'echo bin2hex(base64_decode(file_get_contents("/tmp/out.txt")));'
 
540000000800000001000100000003000100010000000200010003000000020001000400000002000100040000000200010001000000030001000100000007000100010000000300010001000000010001000500000001000100040000000200010004000000030001000300000002000100010000000300010001000000020001000400000003000100010000000300010001000000030001000100000001000100010000000300010001000000010001000100000003000100010000000100010001000000030001000100000001000100010000000300010001000000070001000100000003000100010000000100010001000000050001000100000003000100010000000100010001000000030001000100000003000100010000000300010001000000030001000100000001000100010000000700010001000000030001000100000003000100010000000100010001000000030001000100000001000100010000000300010001000000010001000100000003000100010000000200010001000000010001000100000008000100010000000100010001000000010001000100000001000100010000000500010001000000030001000100000001000100010000000300010001000000030001000100000003000100020000000200010001000000010001000100000007000100010000000300010005000000010001000500000001000100040000000200010004000000030001000100000001000100010000000800010001000000010001000100000001000100010000000100010004000000020001000100000003000100010000000100010001000000030001000100000003000100010000000300010001000000010001000100000001000100010000000100010001000000010001000300000003000100010000000300010001000000030001000100000001000100010000000300010001000000010001000100000005000100010000000700010001000000090001000100000001000100010000000100010001000000010001000100000005000100010000000300010001000000010001000100000003000100010000000300010001000000030001000100000002000100020000000100010001000000030001000100000003000100010000000300010001000000030001000100000001000100010000000300010001000000010001000100000005000100010000000700010001000000090001000100000001000100010000000100010001000000010001000100000005000100010000000300010001000000010001000100000003000100010000000300010001000000030001000100000003000100010000000100010001000000030001000100000007000100010000000300010001000000010001000100000003000100010000000100010001000000050001000100000007000100010000000a0001000100000001000100010000000200010005000000010001000400000002000100040000000300010003000000020001000100000003000100010000000200010004000000030001000100000003000000540000000000

のように、何か意味ありげなオクテット列が続いていることが分かります。

では、mod_mikko.so を組み込んでみましょう。

LoadModule sotarok_module .libs/mod_sotarok.so
LoadModule mikko_module .libs/mod_mikko.so

Listen 8080

<Location />
    SetHandler sotarok-handler
    SetOutputFilter MIKKO_OUT
</Location>

PidFile /tmp/httpd.pid
LockFile /tmp/accept.lock
ErrorLog /tmp/error_log

出力:

VAAAAAgAAAABAAEAAAADAAEAAQAAAAIAAQADAAAAAgABAAQAAAACAAEABAAAAAIAAQABAAAAAwABAAEAAAAH
AAEAAQAAAAMAAQABAAAAAQABAAUAAAABAAEABAAAAAIAAQAEAAAAAwABAAMAAAACAAEAAQAAAAMAAQABAAAA
AgABAAQAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAABAAEAAQAAAAMAAQABAAAAAQABAAEAAAADAAEAAQAA
AAEAAQABAAAAAwABAAEAAAABAAEAAQAAAAMAAQABAAAABwABAAEAAAADAAEAAQAAAAEAAQABAAAABQABAAEA
AAADAAEAAQAAAAEAAQABAAAAAwABAAEAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAABAAEAAQAAAAcAAQAB
AAAAAwABAAEAAAADAAEAAQAAAAEAAQABAAAAAwABAAEAAAABAAEAAQAAAAMAAQABAAAAAQABAAEAAAADAAEA
AQAAAAIAAQABAAAAAQABAAEAAAAIAAEAAQAAAAEAAQABAAAAAQABAAEAAAABAAEAAQAAAAUAAQABAAAAAwAB
AAEAAAABAAEAAQAAAAMAAQABAAAAAwABAAEAAAADAAEAAgAAAAIAAQABAAAAAQABAAEAAAAHAAEAAQAAAAMA
AQAFAAAAAQABAAUAAAABAAEABAAAAAIAAQAEAAAAAwABAAEAAAABAAEAAQAAAAgAAQABAAAAAQABAAEAAAAB
AAEAAQAAAAEAAQAEAAAAAgABAAEAAAADAAEAAQAAAAEAAQABAAAAAwABAAEAAAADAAEAAQAAAAMAAQABAAAA
AQABAAEAAAABAAEAAQAAAAEAAQABAAAAAQABAAMAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAABAAEAAQAA
AAMAAQABAAAAAQABAAEAAAAFAAEAAQAAAAcAAQABAAAACQABAAEAAAABAAEAAQAAAAEAAQABAAAAAQABAAEA
AAAFAAEAAQAAAAMAAQABAAAAAQABAAEAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAACAAEAAgAAAAEAAQAB
AAAAAwABAAEAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAABAAEAAQAAAAMAAQABAAAAAQABAAEAAAAFAAEA
AQAAAAcAAQABAAAACQABAAEAAAABAAEAAQAAAAEAAQABAAAAAQABAAEAAAAFAAEAAQAAAAMAAQABAAAAAQAB
AAEAAAADAAEAAQAAAAMAAQABAAAAAwABAAEAAAADAAEAAQAAAAEAAQABAAAAAwABAAEAAAAHAAEAAQAAAAMA
AQABAAAAAQABAAEAAAADAAEAAQAAAAEAAQABAAAABQABAAEAAAAHAAEAAQAAAAoAAQABAAAAAQABAAEAAAAC
AAEABQAAAAEAAQAEAAAAAgABAAQAAAADAAEAAwAAAAIAAQABAAAAAwABAAEAAAACAAEABAAAAAMAAQABAAAA
AwAAAFQAAAAAAA==

というわけで、

sotarok & komikko、おめでとうございます!末永くお幸せに!