// 过滤模块处理HTTP头部的方法原型 typedef ngx_int_t (*ngx_http_output_header_filter_pt)(ngx_http_request_t *r); // 过滤模块处理HTTP包体的方法原型 typedef ngx_int_t (*ngx_http_output_body_filter_pt)(ngx_http_request_t *r, ngx_chain_t *chain);
// HTTP过滤模块链表入口 extern ngx_http_output_header_filter_pt ngx_http_top_header_filter; extern ngx_http_output_body_filter_pt ngx_http_top_body_filter;
ngx_int_t
ngx_http_send_header(ngx_http_request_t *r)
{
if (r->header_sent) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"header already sent");
return NGX_ERROR;
}
if (r->err_status) {
r->headers_out.status = r->err_status;
r->headers_out.status_line.len = 0;
}
// 从头遍历HTTP头部过滤模块
return ngx_http_top_header_filter(r);
}ngx_int_t
ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_int_t rc;
ngx_connection_t *c;
c = r->connection;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http output filter \"%V?%V\"", &r->uri, &r->args);
// 遍历HTTP包体过滤模块
rc = ngx_http_top_body_filter(r, in);
if (rc == NGX_ERROR) {
/* NGX_ERROR may be returned by any filter */
c->error = 1;
}
return rc;
}static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t
ngx_http_addition_filter_init(ngx_conf_t *cf)
{
// 从头部加入
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_addition_header_filter;
// 从头部加入
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_addition_body_filter;
return NGX_OK;
}typedef struct
{
ngx_flag_t enable; // 保存on或者off
} ngx_http_myfilter_conf_t;
typedef struct
{
ngx_int_t add_prefix;
} ngx_http_myfilter_ctx_t; // HTTP上下文结构体static ngx_http_module_t ngx_http_myfilter_module_ctx =
{
NULL, /* preconfiguration */
ngx_http_myfilter_init, /* postconfiguration */
NULL, /* create_main_conf */
NULL, /* init_main_conf */
NULL, /* create_srv_conf */
NULL, /* merge_srv_conf */
ngx_http_myfilter_create_conf, /* create_loc_conf */
ngx_http_myfilter_merge_conf /* merge_loc_conf */
};static ngx_command_t ngx_http_myfilter_commands[] =
{
{
ngx_string("myfilter"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_FLAG,
ngx_conf_set_flag_slot, // 自带的解析函数
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_myfilter_conf_t, enable),
NULL
},
ngx_null_command
};// 处理请求的头部
static ngx_int_t ngx_http_myfilter_header_filter(ngx_http_request_t *r)
{
ngx_http_myfilter_ctx_t *ctx;
ngx_http_myfilter_conf_t *conf;
//如果不是返回成功,这时是不需要理会是否加前缀的,直接交由下一个过滤模块
//处理响应码非200的情形
if (r->headers_out.status != NGX_HTTP_OK)
return ngx_http_next_header_filter(r);
//获取http上下文
ctx = ngx_http_get_module_ctx(r, ngx_http_myfilter_module);
if (ctx)
//该请求的上下文已经存在,这说明该模块已经被调用过1次,直接交由下一个过滤模块处理
return ngx_http_next_header_filter(r);
//获取存储配置项的ngx_http_myfilter_conf_t结构体
conf = ngx_http_get_module_loc_conf(r, ngx_http_myfilter_module);
//如果enable成员为0,也就是配置文件中没有配置add_prefix配置项,
//或者add_prefix配置项的参数值是off,这时直接交由下一个过滤模块处理
if (conf->enable == 0)
return ngx_http_next_header_filter(r);
//构造http上下文结构体ngx_http_myfilter_ctx_t
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_myfilter_ctx_t));
if (ctx == NULL)
return NGX_ERROR;
//add_prefix为0表示不加前缀
ctx->add_prefix = 0;
//将构造的上下文设置到当前请求中
ngx_http_set_ctx(r, ctx, ngx_http_myfilter_module);
//myfilter过滤模块只处理Content-Type是"text/plain"类型的http响应
if (r->headers_out.content_type.len >= sizeof("text/plain") - 1
&& ngx_strncasecmp(r->headers_out.content_type.data, (u_char *) "text/plain", sizeof("text/plain") - 1) == 0)
{
ctx->add_prefix = 1; //1表示需要在http包体前加入前缀
//如果处理模块已经在Content-Length写入了http包体的长度,由于
//我们加入了前缀字符串,所以需要把这个字符串的长度也加入到
//Content-Length中
if (r->headers_out.content_length_n > 0)
r->headers_out.content_length_n += filter_prefix.len;
}
//交由下一个过滤模块继续处理
return ngx_http_next_header_filter(r);
}//将在包体中添加这个前缀
static ngx_str_t filter_prefix = ngx_string("~~~~~~~This is a prefix~~~~~~~\n");
// 处理请求的包体
static ngx_int_t ngx_http_myfilter_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_http_myfilter_ctx_t *ctx;
// 获得HTTP上下文
ctx = ngx_http_get_module_ctx(r, ngx_http_myfilter_module);
//如果获取不到上下文,或者上下文结构体中的add_prefix为0或者2时,
//都不会添加前缀,这时直接交给下一个http过滤模块处理
if (ctx == NULL || ctx->add_prefix != 1)
return ngx_http_next_body_filter(r, in);
//将add_prefix设置为2,这样即使ngx_http_myfilter_body_filter再次回调时,也不会重复添加前缀
ctx->add_prefix = 2;
//从请求的内存池中分配内存,用于存储字符串前缀
ngx_buf_t* b = ngx_create_temp_buf(r->pool, filter_prefix.len);
//将ngx_buf_t中的指针正确地指向filter_prefix字符串
b->start = b->pos = filter_prefix.data;
b->last = b->pos + filter_prefix.len;
//从请求的内存池中生成ngx_chain_t链表,将刚分配的ngx_buf_t设置到
//其buf成员中,并将它添加到原先待发送的http包体前面
ngx_chain_t *cl = ngx_alloc_chain_link(r->pool);
cl->buf = b;
cl->next = in;
//调用下一个模块的http包体处理方法,注意这时传入的是新生成的cl链表
return ngx_http_next_body_filter(r, cl);
}./configure --add-module="/work/nginx/modules/mytest /work/nginx/modules/myfilter"
vim objs/ngx_modules.c
vim /usr/local/nginx/conf/nginx.conf
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
// 配置项结构体
typedef struct {
ngx_flag_t enable;
} ngx_http_myfilter_conf_t;
// 上下文结构体
typedef struct {
ngx_int_t add_prefix;
} ngx_http_myfilter_ctx_t;
ngx_module_t ngx_http_myfilter_module; // 前向声明
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
// 需要添加的前缀内容
static ngx_str_t filter_prefix = ngx_string("~~~~~~~This is a prefix~~~~~~~\n");
static ngx_int_t ngx_http_myfilter_header_filter(ngx_http_request_t *r)
{
ngx_http_myfilter_ctx_t *ctx;
ngx_http_myfilter_conf_t *conf;
if (r->headers_out.status != NGX_HTTP_OK)
return ngx_http_next_header_filter(r); // 交由下一个过滤模块处理
ctx = ngx_http_get_module_ctx(r, ngx_http_myfilter_module);
if (ctx)
return ngx_http_next_header_filter(r); // 上下文已存在,不再处理
conf = ngx_http_get_module_loc_conf(r, ngx_http_myfilter_module); // 获取配置项结构体
if (conf->enable == 0)
return ngx_http_next_header_filter(r); // 此过滤模块未打开
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_myfilter_ctx_t)); // 创建上下文结构体
if (ctx == NULL)
return NGX_ERROR;
ctx->add_prefix = 0; // 0表示不需要添加前缀
ngx_http_set_ctx(r, ctx, ngx_http_myfilter_module);
// 只处理Content-Type为text/plain类型的HTTP请求
if (r->headers_out.content_type.len >= sizeof("text/plain")-1 &&
ngx_strncasecmp(r->headers_out.content_type.data, (u_char *)"text/plain", sizeof("text/plain")-1) == 0)
{
ctx->add_prefix = 1; // 1表示需要加入前缀
if (r->headers_out.content_length_n > 0)
r->headers_out.content_length_n += filter_prefix.len; // 响应包体长度增加
}
return ngx_http_next_header_filter(r);
}
static ngx_int_t ngx_http_myfilter_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_http_myfilter_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_myfilter_module); // 获取上下文结构体
if (ctx == NULL || ctx->add_prefix != 1)
return ngx_http_next_body_filter(r, in); // 不添加前缀
ctx->add_prefix = 2; // 2表示已添加前缀
ngx_buf_t *b = ngx_create_temp_buf(r->pool, filter_prefix.len);
b->start = b->pos = filter_prefix.data;
b->last = b->pos + filter_prefix.len;
// 链入待发送包体头部
ngx_chain_t *cl = ngx_alloc_chain_link(r->pool);
cl->buf = b;
cl->next = in;
return ngx_http_next_body_filter(r, cl); // 跳到下一个过滤模块
}
// 初始化HTTP过滤模块
static ngx_int_t ngx_http_myfilter_init(ngx_conf_t *cf)
{
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_myfilter_header_filter;
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_myfilter_body_filter;
return NGX_OK;
}
// 创建存储配置项的结构体
static void* ngx_http_myfilter_create_conf(ngx_conf_t *cf)
{
ngx_http_myfilter_conf_t *mycf;
mycf = (ngx_http_myfilter_conf_t *)ngx_pcalloc(cf->pool, sizeof(ngx_http_myfilter_conf_t));
if (mycf == NULL)
return NULL;
mycf->enable = NGX_CONF_UNSET;
return mycf;
}
// 合并配置项
static char* ngx_http_myfilter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_myfilter_conf_t *prev = (ngx_http_myfilter_conf_t *)parent;
ngx_http_myfilter_conf_t *conf = (ngx_http_myfilter_conf_t *)child;
ngx_conf_merge_value(conf->enable, prev->enable, 0); // 合并函数
return NGX_CONF_OK;
}
static ngx_command_t ngx_http_myfilter_commands[] = {
{
ngx_string("myfilter"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_myfilter_conf_t, enable),
NULL,
},
ngx_null_command
};
// HTTP框架初始化时调用的八个函数
static ngx_http_module_t ngx_http_myfilter_module_ctx = {
NULL,
ngx_http_myfilter_init,
NULL,
NULL,
NULL,
NULL,
ngx_http_myfilter_create_conf,
ngx_http_myfilter_merge_conf,
};
// 定义一个HTTP模块
ngx_module_t ngx_http_myfilter_module = {
NGX_MODULE_V1, // 0,0,0,0,0,0,1
&ngx_http_myfilter_module_ctx,
ngx_http_myfilter_commands,
NGX_HTTP_MODULE,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NGX_MODULE_V1_PADDING, // 0,0,0,0,0,0,0,0,保留字段
};【Nginx】开发一个HTTP过滤模块,布布扣,bubuko.com
原文地址:http://blog.csdn.net/nestler/article/details/36663043