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]