POSTされたデータをパースするApacheモジュール

CentOS5.1 上の Apache2.2のサンプル。libapreq2 を使用。
libapreq2 のインストールには、あらかじめEPELレポジトリの追加が必要。

# rpm -ivh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-1.noarch.rpm
# yum install libapreq2-devel
  • mod_mypost の作成
# apxs -g -n mypost
# cd mypost
# make
# make install

/etc/httpd/conf.d/mod_mypost.conf を以下のように作成

LoadModule mypost_module modules/mod_mypost.so

<Location /mypost>
    SetHandler mypost
</Location>
  • mod_mypost.c
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include <apreq2/apreq_param.h>
#include "apr_tables.h"
#include "ap_config.h"

static int mypost_handler(request_rec *r)
{
    apr_bucket_brigade *bb;
    int seen_eos = 0;
    char *body="";
    
    if (strcmp(r->handler, "mypost")) {
        return DECLINED;
    }
    r->content_type = "text/html";
    
    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
    do {
        apr_bucket *bucket;
        apr_status_t rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN);
        for (bucket = APR_BRIGADE_FIRST(bb); bucket != APR_BRIGADE_SENTINEL(bb); bucket = APR_BUCKET_NEXT(bucket)) {
            if (APR_BUCKET_IS_EOS(bucket)) {
                seen_eos = 1;
                break;
            }
            if (bucket->length != 0) {
                const char *data;
                apr_size_t len;
                rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
                //ap_rprintf(r, "len=%d; type=%s; %s\n", len, bucket->type->name, apr_pstrmemdup(r->pool, data, len));
                //ap_rprintf(r, "%s", apr_pstrmemdup(r->pool, data, len));
                body = apr_pstrcat(r->pool, body, data, NULL);;
            }
        }
        apr_brigade_cleanup(bb);
    } while (!seen_eos);
    
    if (!r->header_only)
        ap_rprintf(r, "%s\n", body);
    return OK;
}

static void mypost_register_hooks(apr_pool_t *p)
{
    ap_hook_handler(mypost_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA mypost_module = {
    STANDARD20_MODULE_STUFF, 
    NULL,                  /* create per-dir    config structures */
    NULL,                  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    NULL,                  /* table of config file commands       */
    mypost_register_hooks  /* register hooks                      */
};
  • apreq_body を使った改良版
#include "httpd.h"
#include "http_config.h"
#include "http_protocol.h"
#include "apreq_module.h"
#include "apreq_param.h"
#include "apreq2/apreq_module_apache2.h"
#include "apr_tables.h"
#include "ap_config.h"

static int mypost_handler(request_rec *r)
{
    if (strcmp(r->handler, "mypost")) {
        return DECLINED;
    }
    r->content_type = "text/html";
    
    apreq_handle_t *apreq;
    apreq = apreq_handle_apache2(r);    
    
    apr_table_t *param;
    apreq_body(apreq, (const apr_table_t**)&param);
    
    //to specify a value
    ap_rprintf(r, "%s\n", apreq_params_as_string(r->pool, param, "key", APREQ_JOIN_AS_IS));

    //to enumerate values
    apr_array_header_t *params = apr_table_elts(param);
    apr_table_entry_t *paramlist = (apr_table_entry_t *)params->elts;
    int i;
    for (i=0; i<params->nelts; i++){
        ap_rprintf(r, "%s==%s\n", paramlist[i].key, paramlist[i].val);
    }
    
    return OK;
}

static void mypost_register_hooks(apr_pool_t *p)
{
    ap_hook_handler(mypost_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA mypost_module = {
    STANDARD20_MODULE_STUFF, 
    NULL,                  /* create per-dir    config structures */
    NULL,                  /* merge  per-dir    config structures */
    NULL,                  /* create per-server config structures */
    NULL,                  /* merge  per-server config structures */
    NULL,                  /* table of config file commands       */
    mypost_register_hooks  /* register hooks                      */
};
  • テスト
# curl -d 'key=val&key1=val1&key2=val2' 'http://localhost/mypost'                       val
key==val
key1==val1
key2==val2