夜勿眠 发表于 2016-12-24 11:48:46

Nginx Modules 开发学习

       nginx 模块开发,咱们先从模块分析入手,nginx的模块支持hook(钩子功能),我们可以在以下几个地方添加钩子:


[*]Just before the server reads the config file
读取配置文件时
[*]For every configuration directive for the location and server for which it appears;
读取到server或是location 配置的时候
[*]When Nginx initializes the main configuration
初始化主配置的时候
[*]When Nginx initializes the server (i.e., host/port) configuration
初始化server 配置的时候
[*]When Nginx merges the server configuration with the main configuration
使用主配置,合并server配置的时候
[*]When Nginx initializes the location configuration
初始化location配置的时候
[*]When Nginx merges the location configuration with its parent server configuration
使用server配置,合并location配置的时候
[*]When Nginx's master process starts
nginx 主进程启动的时候
[*]When a new worker process starts
nginx 启动一个新的工作进程的时候
[*]When a worker process exits
nginx 工作进程退出的时候
[*]When the master exits
nginx 主进程退出的时候
[*]Handling a request
接收的请求的时候
[*]Filtering response headers
过滤 response headers 的时候,gzip就是这个时候hook的
[*]Filtering the response body
过滤 response body 的时候,gzip就是这个时候hook的
[*]Picking a backend server
选择一个后台服务器的时候,在upstream 中选择
[*]Initiating a request to a backend server
初始化一个访问后台服务器的请求的时候
[*]
Re-initiating a request to a backend server
重新初始化一个访问后台服务器的请求的时候
[*]Processing the response from a backend server
处理从后台返回的response的时候
[*]Finishing an interaction with a backend server
与后台服务器交互结束的时候
  

  下面我们分析以下nginx memcache的模块,下载nginx源码,cd src/http/modules/,在moudels 目录下,你能找到nginx所有core modules ,这里我们分析ngx_http_memcached_module.c 文件
  


#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
//配置定义
typedef struct {
ngx_http_upstream_conf_t   upstream;
ngx_int_t                  index;
} ngx_http_memcached_loc_conf_t;
//request 定义
typedef struct {
size_t                     rest;
ngx_http_request_t      *request;
ngx_str_t                  key;
} ngx_http_memcached_ctx_t;

  已下是nginx 的 hood定义

static ngx_int_t ngx_http_memcached_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_memcached_reinit_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r);
static ngx_int_t ngx_http_memcached_filter_init(void *data);
static ngx_int_t ngx_http_memcached_filter(void *data, ssize_t bytes);
static void ngx_http_memcached_abort_request(ngx_http_request_t *r);
static void ngx_http_memcached_finalize_request(ngx_http_request_t *r,
ngx_int_t rc);
  使用upstream 时定义的参数

static ngx_conf_bitmask_tngx_http_memcached_next_upstream_masks[] = {
{ ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
{ ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
{ ngx_string("invalid_response"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
{ ngx_string("not_found"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
{ ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
{ ngx_null_string, 0 }
};

  memcache nginx  自定义命令

static ngx_command_tngx_http_memcached_commands[] = {
{ ngx_string("memcached_pass"),
NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
ngx_http_memcached_pass,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
{ ngx_string("memcached_bind"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_upstream_bind_set_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_memcached_loc_conf_t, upstream.local),
NULL },
{ ngx_string("memcached_connect_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_memcached_loc_conf_t, upstream.connect_timeout),
NULL },
{ ngx_string("memcached_send_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_memcached_loc_conf_t, upstream.send_timeout),
NULL },
{ ngx_string("memcached_buffer_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_memcached_loc_conf_t, upstream.buffer_size),
NULL },
{ ngx_string("memcached_read_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_memcached_loc_conf_t, upstream.read_timeout),
NULL },
{ ngx_string("memcached_next_upstream"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_conf_set_bitmask_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream),
&ngx_http_memcached_next_upstream_masks },
ngx_null_command
};

   Nginx 命令结构

struct ngx_command_s {
ngx_str_t             name;
ngx_uint_t            type;
char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_uint_t            conf;
ngx_uint_t            offset;
void               *post;
};
  自定义命令配置说明:
  type :

      NGX_HTTP_MAIN_CONF:可出现在 http 的主作用域;
NGX_HTTP_SRV_CONF:可出现在 http 的 server 作用域;
NGX_HTTP_LOC_CONF:可出现在 http 的 location 作用域;
NGX_HTTP_UPS_CONF:可出现在 http 的 upstream 作用域;
NGX_HTTP_SIF_CONF:可出现在判断语句里;
NGX_CONF_NOARGS:指令没有参数;
NGX_CONF_TAKE1:指令读入1个参数;
NGX_CONF_TAKE2:指令读入2个参数;
......
NGX_CONF_TAKE7:指令读入7个参数;
NGX_CONF_FLAG:指令读入1个布尔型数据(“on”或“off”);
NGX_CONF_1MORE:指令至少读入1个参数;
NGX_CONF_2MORE:指令至少读入2个参数;


   http 上下文定义:


[*]
static ngx_http_module_tngx_http_memcached_module_ctx = {
NULL,                                  /* preconfiguration */
NULL,                                  /* postconfiguration */
NULL,                                  /* create main configuration */
NULL,                                  /* init main configuration */
NULL,                                  /* create server configuration */
NULL,                                  /* merge server configuration */
ngx_http_memcached_create_loc_conf,    /* create location configuration */
ngx_http_memcached_merge_loc_conf      /* merge location configuration */
};

ngx_module_tngx_http_memcached_module = {
NGX_MODULE_V1,
&ngx_http_memcached_module_ctx,      /* module context */
ngx_http_memcached_commands,         /* module directives */
NGX_HTTP_MODULE,                     /* module type */
NULL,                                  /* init master */
NULL,                                  /* init module */
NULL,                                  /* init process */
NULL,                                  /* init thread */
NULL,                                  /* exit thread */
NULL,                                  /* exit process */
NULL,                                  /* exit master */
NGX_MODULE_V1_PADDING
};

 
http 上下文结构定义:

typedef struct {
ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);
ngx_int_t   (*postconfiguration)(ngx_conf_t *cf);
void       *(*create_main_conf)(ngx_conf_t *cf);
char       *(*init_main_conf)(ngx_conf_t *cf, void *conf);
void       *(*create_srv_conf)(ngx_conf_t *cf);
char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
void       *(*create_loc_conf)(ngx_conf_t *cf);
char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;
  

我们跟进看一下 create  and merge loc config:




static void *
ngx_http_memcached_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_memcached_loc_conf_t*conf;
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_memcached_loc_conf_t));
if (conf == NULL) {
return NULL;
}
/*
* set by ngx_pcalloc():
*
*   conf->upstream.bufs.num = 0;
*   conf->upstream.next_upstream = 0;
*   conf->upstream.temp_path = NULL;
*   conf->upstream.uri = { 0, NULL };
*   conf->upstream.location = NULL;
*/
conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
/* the hardcoded values */
conf->upstream.cyclic_temp_file = 0;
conf->upstream.buffering = 0;
conf->upstream.ignore_client_abort = 0;
conf->upstream.send_lowat = 0;
conf->upstream.bufs.num = 0;
conf->upstream.busy_buffers_size = 0;
conf->upstream.max_temp_file_size = 0;
conf->upstream.temp_file_write_size = 0;
conf->upstream.intercept_errors = 1;
conf->upstream.intercept_404 = 1;
conf->upstream.pass_request_headers = 0;
conf->upstream.pass_request_body = 0;
conf->index = NGX_CONF_UNSET;
return conf;
}

static char *
ngx_http_memcached_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_memcached_loc_conf_t *prev = parent;
ngx_http_memcached_loc_conf_t *conf = child;
ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
prev->upstream.connect_timeout, 60000);
ngx_conf_merge_msec_value(conf->upstream.send_timeout,
prev->upstream.send_timeout, 60000);
ngx_conf_merge_msec_value(conf->upstream.read_timeout,
prev->upstream.read_timeout, 60000);
ngx_conf_merge_size_value(conf->upstream.buffer_size,
prev->upstream.buffer_size,
(size_t) ngx_pagesize);
ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
prev->upstream.next_upstream,
(NGX_CONF_BITMASK_SET
|NGX_HTTP_UPSTREAM_FT_ERROR
|NGX_HTTP_UPSTREAM_FT_TIMEOUT));
if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
|NGX_HTTP_UPSTREAM_FT_OFF;
}
if (conf->upstream.upstream == NULL) {
conf->upstream.upstream = prev->upstream.upstream;
}
if (conf->index == NGX_CONF_UNSET) {
conf->index = prev->index;
}
return NGX_CONF_OK;
}








接下来我们进入handler:

static char *
ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_memcached_handler;
return NGX_CONF_OK;
}
  

static ngx_int_t
ngx_http_memcached_handler(ngx_http_request_t *r)
{
ngx_int_t                     rc;
ngx_http_upstream_t            *u;
ngx_http_memcached_ctx_t       *ctx;
ngx_http_memcached_loc_conf_t*mlcf;
if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
return NGX_HTTP_NOT_ALLOWED;
}
rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return rc;
}
if (ngx_http_set_content_type(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (ngx_http_upstream_create(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
u = r->upstream;
ngx_str_set(&u->schema, "memcached://");
u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module;
mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
u->conf = &mlcf->upstream;
u->create_request = ngx_http_memcached_create_request;
u->reinit_request = ngx_http_memcached_reinit_request;
u->process_header = ngx_http_memcached_process_header;
u->abort_request = ngx_http_memcached_abort_request;
u->finalize_request = ngx_http_memcached_finalize_request;
ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t));
if (ctx == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ctx->rest = NGX_HTTP_MEMCACHED_END;
ctx->request = r;
ngx_http_set_ctx(r, ctx, ngx_http_memcached_module);
u->input_filter_init = ngx_http_memcached_filter_init;
u->input_filter = ngx_http_memcached_filter;
u->input_filter_ctx = ctx;
r->main->count++;
ngx_http_upstream_init(r);
return NGX_DONE;
}

 

以上 memcache处理均在以下方法中进行:

u->create_request = ngx_http_memcached_create_request;
u->reinit_request = ngx_http_memcached_reinit_request;
u->process_header = ngx_http_memcached_process_header;
u->abort_request = ngx_http_memcached_abort_request;
u->finalize_request = ngx_http_memcached_finalize_request;

   u->input_filter_init = ngx_http_memcached_filter_init;
u->input_filter = ngx_http_memcached_filter;
u->input_filter_ctx = ctx;
 







以上是对memcached nginx模块进行的分析,小刀我也是初始,有写的不好的地方,请大家多多指教,接下来我们在看一个 not modified moudel 这个相对就容易很多。

/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/

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

static ngx_int_t ngx_http_test_precondition(ngx_http_request_t *r);
static ngx_int_t ngx_http_test_not_modified(ngx_http_request_t *r);
static ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf);

static ngx_http_module_tngx_http_not_modified_filter_module_ctx = {
NULL,                                  /* preconfiguration */
ngx_http_not_modified_filter_init,   /* postconfiguration */
NULL,                                  /* create main configuration */
NULL,                                  /* init main configuration */
NULL,                                  /* create server configuration */
NULL,                                  /* merge server configuration */
NULL,                                  /* create location configuration */
NULL                                 /* merge location configuration */
};

ngx_module_tngx_http_not_modified_filter_module = {
NGX_MODULE_V1,
&ngx_http_not_modified_filter_module_ctx, /* module context */
NULL,                                  /* module directives */
NGX_HTTP_MODULE,                     /* module type */
NULL,                                  /* init master */
NULL,                                  /* init module */
NULL,                                  /* init process */
NULL,                                  /* init thread */
NULL,                                  /* exit thread */
NULL,                                  /* exit process */
NULL,                                  /* exit master */
NGX_MODULE_V1_PADDING
};

static ngx_http_output_header_filter_ptngx_http_next_header_filter;

static ngx_int_t
ngx_http_not_modified_header_filter(ngx_http_request_t *r)
{
if (r->headers_out.status != NGX_HTTP_OK
|| r != r->main
|| r->headers_out.last_modified_time == -1)
{
return ngx_http_next_header_filter(r);
}
if (r->headers_in.if_unmodified_since) {
return ngx_http_test_precondition(r);
}
if (r->headers_in.if_modified_since) {
return ngx_http_test_not_modified(r);
}
return ngx_http_next_header_filter(r);
}

static ngx_int_t
ngx_http_test_precondition(ngx_http_request_t *r)
{
time_tiums;
iums = ngx_http_parse_time(r->headers_in.if_unmodified_since->value.data,
r->headers_in.if_unmodified_since->value.len);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http iums:%d lm:%d", iums, r->headers_out.last_modified_time);
if (iums >= r->headers_out.last_modified_time) {
return ngx_http_next_header_filter(r);
}
return ngx_http_filter_finalize_request(r, NULL,
NGX_HTTP_PRECONDITION_FAILED);
}

static ngx_int_t
ngx_http_test_not_modified(ngx_http_request_t *r)
{
time_t                     ims;
ngx_http_core_loc_conf_t*clcf;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->if_modified_since == NGX_HTTP_IMS_OFF) {
return ngx_http_next_header_filter(r);
}
ims = ngx_http_parse_time(r->headers_in.if_modified_since->value.data,
r->headers_in.if_modified_since->value.len);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http ims:%d lm:%d", ims, r->headers_out.last_modified_time);
if (ims != r->headers_out.last_modified_time) {
if (clcf->if_modified_since == NGX_HTTP_IMS_EXACT
|| ims < r->headers_out.last_modified_time)
{
return ngx_http_next_header_filter(r);
}
}
r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
r->headers_out.status_line.len = 0;
r->headers_out.content_type.len = 0;
ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r);
if (r->headers_out.content_encoding) {
r->headers_out.content_encoding->hash = 0;
r->headers_out.content_encoding = NULL;
}
return ngx_http_next_header_filter(r);
}

static ngx_int_t
ngx_http_not_modified_filter_init(ngx_conf_t *cf)
{
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_not_modified_header_filter;
return NGX_OK;
}

 

自定义返回时设置cookie:




1. mkdir author

2. cd author

3. 创建一个文件叫 config 内容如下




ngx_addon_name=nginx_add_author_filter_module
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES nginx_add_author_filter_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/author.c"
4../configure --add-module=/Users/liuzheng/nginx/addOn/ 




/*
* Copy right (C) Liuzheng Wiyun author.c
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>

static ngx_int_t ngx_http_add_author_filter_init(ngx_conf_t *cf);
static ngx_int_t ngx_http_add_author_header_filter(ngx_http_request_t *r);
static ngx_http_module_t nginx_add_author_filter_module_ctx = {
NULL,                                  /* preconfiguration */
ngx_http_add_author_filter_init,   /* postconfiguration */
NULL,                                  /* create main configuration */
NULL,                                  /* init main configuration */
NULL,                                  /* create server configuration */
NULL,                                  /* merge server configuration */
NULL,                                  /* create location configuration */
NULL                                 /* merge location configuration */
};

ngx_module_tnginx_add_author_filter_module = {
NGX_MODULE_V1,
&nginx_add_author_filter_module_ctx, /* module context */
NULL,                                  /* module directives */
NGX_HTTP_MODULE,                     /* module type */
NULL,                                  /* init master */
NULL,                                  /* init module */
NULL,                                  /* init process */
NULL,                                  /* init thread */
NULL,                                  /* exit thread */
NULL,                                  /* exit process */
NULL,                                  /* exit master */
NGX_MODULE_V1_PADDING
};

static ngx_http_output_header_filter_ptngx_http_next_header_filter;

static ngx_int_t
ngx_http_add_author_header_filter(ngx_http_request_t *r)
{
ngx_table_elt_t*set_cookie;
set_cookie = ngx_list_push(&r->headers_out.headers);
if (set_cookie == NULL) {
return NGX_ERROR;
}
set_cookie->hash = 1;
ngx_str_set(&set_cookie->key, "Set-Cookie");
ngx_str_set(&set_cookie->value, "author=liuzheng");
return ngx_http_next_header_filter(r);
}

static ngx_int_t
ngx_http_add_author_filter_init(ngx_conf_t *cf)
{
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_add_author_header_filter;
return NGX_OK;
}

 





[*]
Connection:

keep-alive
[*]
Date:

Mon, 13 Aug 2012 08:39:51 GMT
[*]
Last-Modified:

Mon, 27 Feb 2012 09:14:41 GMT
[*]
Server:

nginx/1.2.3
[*]
Set-Cookie:

author=liuzheng



页: [1]
查看完整版本: Nginx Modules 开发学习