1. 程式人生 > >Openresty學習(十):Nginx內部變數的增加和使用

Openresty學習(十):Nginx內部變數的增加和使用

在Openresty學習(九)基礎上,定義新的內部變數my_method(表示請求的方法),增加對請求方法的檢查。

配置:


        location /hello {
            default_type text/html;
            check_version $server_protocol HTTP/1.1 $my_method GET;
            content_by_lua_block {
                ngx.say("HelloWorld")
            }
        }

測試:

如果是請求是HTTP 1.1協議並且請求方法是GET,則請求通過

如果請求是不是HTTP 1.1協議或者方法不是GET,則請求被禁止,返回403

原始碼:

config:

ngx_addon_name=ngx_http_check_version_module
HTTP_MODULES="$HTTP_MODULES ngx_http_check_version_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_check_version_module.c"

/private/ngx_http_check_version_module/ngx_http_check_version_module.c:

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


typedef struct {
    int variable_index;

    ngx_str_t variable_name;
    ngx_str_t allow_version_value;

    int my_method_index;
    ngx_str_t my_method_name;
    ngx_str_t allow_method_value;
} ngx_http_check_version_loc_conf_t;

static ngx_int_t ngx_http_check_version_handler(ngx_http_request_t *r);
static char *ngx_http_check_version(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_check_version_init(ngx_conf_t *cf);
static void *ngx_http_check_version_create_loc_conf(ngx_conf_t *cf);

static ngx_int_t ngx_http_check_version_add_variable(ngx_conf_t *cf);

static ngx_command_t ngx_http_check_version_commands[] =
{
        {
            ngx_string("check_version"),
            NGX_HTTP_LOC_CONF | NGX_CONF_TAKE4,
            ngx_http_check_version,
            NGX_HTTP_LOC_CONF_OFFSET,
            0,
            NULL
        },

        ngx_null_command
};

static ngx_http_module_t ngx_http_check_version_module_ctx =
{
    ngx_http_check_version_add_variable,
    ngx_http_check_version_init,

    NULL,
    NULL,

    NULL,
    NULL,

    ngx_http_check_version_create_loc_conf,
    NULL
};

ngx_module_t ngx_http_check_version_module =
{
    NGX_MODULE_V1,
    &ngx_http_check_version_module_ctx,
    ngx_http_check_version_commands,
    NGX_HTTP_MODULE,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NGX_MODULE_V1_PADDING
};

static ngx_str_t my_method = ngx_string("my_method");

static ngx_int_t ngx_http_my_method_get_handler(
        ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data)
{
    v->not_found = 0;
    v->data = r->method_name.data;
    v->len = r->method_name.len;
    v->valid = 1;

    return NGX_OK;
}

static ngx_int_t ngx_http_check_version_add_variable(ngx_conf_t *cf)
{
    ngx_http_variable_t *v = NULL;

    v = ngx_http_add_variable(cf, &my_method,NGX_HTTP_VAR_CHANGEABLE);
    if (NULL == v)
    {
        return NGX_ERROR;
    }

    v->get_handler = ngx_http_my_method_get_handler;
    v->data = 0;

   return NGX_OK;
}

static void *ngx_http_check_version_create_loc_conf(ngx_conf_t *cf)
{
    ngx_http_check_version_loc_conf_t *conf = NULL;

    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_check_version_loc_conf_t));
    if (NULL == conf)
    {
        return NULL;
    }

    conf->variable_index = -1;

    return conf;
}

static ngx_int_t ngx_http_check_version_init(ngx_conf_t *cf)
{
    ngx_http_handler_pt *h = NULL;

    ngx_http_core_main_conf_t *cmcf = NULL;

    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

    h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
    if (NULL == h)
    {
        return NGX_ERROR;
    }

    *h = ngx_http_check_version_handler;

    return NGX_OK;
    
}

static char *ngx_http_check_version(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    ngx_str_t *value = NULL;

    ngx_http_check_version_loc_conf_t *hlcf = NULL;

    hlcf = conf;

    value = cf->args->elts;

    if (cf->args->nelts != 5)
    {
        return NGX_CONF_ERROR;
    }

    if (value[1].data[0] == '$')
    {
        value[1].data++;
        value[1].len--;

        hlcf->variable_index = ngx_http_get_variable_index(cf, &value[1]);
        if (hlcf->variable_index == NGX_ERROR)
        {
            return NGX_CONF_ERROR;
        }

        hlcf->variable_name = value[1];
    }
    else
    {
        return NGX_CONF_ERROR;
    }

    hlcf->allow_version_value = value[2];

    if (value[3].data[0] == '$')
    {
        value[3].data++;
        value[3].len--;

        hlcf->my_method_index = ngx_http_get_variable_index(cf, &value[3]);
        if (hlcf->my_method_index == NGX_ERROR)
        {
            return NGX_CONF_ERROR;
        }

        hlcf->my_method_name = value[3];
    }
    else
    {
        return NGX_CONF_ERROR;
    }

    hlcf->allow_method_value = value[4];

    return NGX_CONF_OK;
}

static ngx_int_t ngx_http_check_version_handler(ngx_http_request_t *r)
{
    ngx_http_check_version_loc_conf_t *conf = NULL;
    ngx_http_variable_value_t *request_version = NULL;
    ngx_http_variable_value_t *request_method = NULL;

    conf = ngx_http_get_module_loc_conf(r, ngx_http_check_version_module);

    if (NULL == conf)
    {
        return NGX_ERROR;
    }

    if (-1 == conf->variable_index)
    {
        return NGX_DECLINED;
    }

    request_version = ngx_http_get_indexed_variable(r, conf->variable_index);
    if (NULL == request_version || request_version->not_found)
    {
        return NGX_HTTP_FORBIDDEN;
    }

    request_method = ngx_http_get_indexed_variable(r, conf->my_method_index);
    if (NULL == request_method || request_method->not_found)
    {
        return NGX_HTTP_FORBIDDEN;
    }

    ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0,
            "request version: %.*s, method: %.*s", request_version->len,
            request_version->data, request_method->len, request_method->data);

    if (request_version->len == conf->allow_version_value.len &&
        0 == ngx_strncmp(conf->allow_version_value.data,
        request_version->data, request_version->len) &&
        request_method->len == conf->allow_method_value.len &&
        0 == ngx_strncmp(conf->allow_method_value.data, request_method->data,
            request_method->len))
    {
        return NGX_DECLINED;
    }

    return NGX_HTTP_FORBIDDEN;
}