ふふーん

一緒にやりたくなったのよ!あなたと、調合を!

nginxモジュールを作ってみるやつ(その2)

uni.firis.me

前回のつづき。 ディレクティブに引数があるパターンをやってみる。

$ mkdir echo
$ vim echo/config
$ vim echo/ngx_http_echo_module.c
# echo/config

ngx_addon_name=ngx_http_echo_module
HTTP_MODULES="$HTTP_MODULES ngx_http_echo_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_echo_module.c"
/* echo/ngx_http_echo_module.c */

#include <ngx_core.h>
#include <ngx_http.h>

static void *ngx_http_echo_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_echo(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_echo_handler(ngx_http_request_t *r);

typedef struct {
    ngx_str_t text;
} ngx_http_echo_loc_conf_t;

static ngx_command_t ngx_http_echo_commands[] = {
    { ngx_string("echo"),
      NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1,
      ngx_http_echo,
      NGX_HTTP_LOC_CONF_OFFSET,
      0, NULL
    },
    ngx_null_command
};

static ngx_http_module_t ngx_http_echo_module_ctx = {
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    ngx_http_echo_create_loc_conf,
    NULL
};

ngx_module_t ngx_http_echo_module = {
    NGX_MODULE_V1,
    &ngx_http_echo_module_ctx,
    ngx_http_echo_commands,
    NGX_HTTP_MODULE,
    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
    NGX_MODULE_V1_PADDING
};

static void *ngx_http_echo_create_loc_conf(ngx_conf_t *cf) {
    ngx_http_echo_loc_conf_t *conf =
            ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_loc_conf_t));
    if (conf == NULL)
        return NULL;
    return conf;
}

static char *ngx_http_echo(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
    ngx_http_core_loc_conf_t *clcf =
            ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
    ngx_http_echo_loc_conf_t *elcf = conf;

    clcf->handler = ngx_http_echo_handler;
    elcf->text = ((ngx_str_t *)cf->args->elts)[1];

    return NGX_CONF_OK;
}

static ngx_int_t ngx_http_echo_handler(ngx_http_request_t *r) {
    ngx_http_echo_loc_conf_t *elcf =
            ngx_http_get_module_loc_conf(r, ngx_http_echo_module);
    ngx_int_t rc;
    ngx_chain_t *cl, *newline_cl;
    ngx_buf_t *buf, *newline_buf;
    ngx_str_t newline_str = ngx_string("\n");

    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD)
        return NGX_HTTP_NOT_ALLOWED;

    buf = ngx_calloc_buf(r->pool);
    if (buf == NULL)
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    buf->pos = elcf->text.data;
    buf->last = elcf->text.data + elcf->text.len;
    buf->memory = 1;

    newline_buf = ngx_calloc_buf(r->pool);
    if (newline_buf == NULL)
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    newline_buf->pos = newline_str.data;
    newline_buf->last = newline_str.data + newline_str.len;
    newline_buf->memory = 1;
    newline_buf->last_buf = 1;

    cl = ngx_alloc_chain_link(r->pool);
    if (cl == NULL)
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    cl->buf = buf;

    newline_cl = ngx_alloc_chain_link(r->pool);
    if (newline_cl == NULL)
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    newline_cl->buf = newline_buf;
    cl->next = newline_cl;

    ngx_str_set(&r->headers_out.content_type, "text/plain");
    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = elcf->text.len + newline_str.len;

    rc = ngx_http_send_header(r);
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only)
        return rc;

    return ngx_http_output_filter(r, cl);
}

ビルドする。

$ ./configure --add-module=echo
$ make
$ diff -u conf/nginx.conf{.02,}
--- conf/nginx.conf.02  2017-06-08 13:26:23.727008967 +0900
+++ conf/nginx.conf 2017-06-08 13:26:52.974061265 +0900
@@ -49,6 +49,10 @@
             hello;
         }
 
+        location /echo {
+            echo "echo module";
+        }
+
         #error_page  404              /404.html;
 
         # redirect server error pages to the static page /50x.html
$ objs/nginx -p . -c conf/nginx.conf
$ curl http://127.0.0.1:8000/echo
echo module

変数展開したいときはどうやってやるんだろう。