该模块可实现如下的功能,在浏览器输入http://你的IP/lcw.text,能够读出你在根目录下创建的lcw.txt里面的内容,并在前面加上一句字符串where there is a will,there is a way!

代码如下:

//start from the very beginning,and to create greatness
//@author: Chuangwei Lin
//@E-mail:979951191@qq.com
//@brief: 一个简单的nginx的HTTP过滤模块 #include <ngx_config.h>//包含必要的头文件
#include <ngx_core.h>
#include <ngx_http.h>
//建立ngx_http_lcwfilter_conf_t结构体用于存储配置项
typedef struct
{
ngx_flag_t enable;
} ngx_http_lcwfilter_conf_t;
//建立ngx_http_lcwfilter_ctx_t结构体作为HTTP上下文结构
typedef struct
{
ngx_int_t add_prefix;
} ngx_http_lcwfilter_ctx_t; //定义静态指针用于指向下一个过滤模块的HTTP头部处理方法
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
//定义静态指针用于指向下一个过滤模块的HTTP包体处理方法
static ngx_http_output_body_filter_pt ngx_http_next_body_filter; //将在包体中添加这个前缀
static ngx_str_t filter_prefix = ngx_string("where there is a will,there is a way!"); //先声明函数
static ngx_int_t ngx_http_lcwfilter_init(ngx_conf_t *cf);
static ngx_int_t ngx_http_lcwfilter_header_filter(ngx_http_request_t *r);
static ngx_int_t ngx_http_lcwfilter_body_filter(ngx_http_request_t *r, ngx_chain_t *in);
static void* ngx_http_lcwfilter_create_conf(ngx_conf_t *cf);
static char *ngx_http_lcwfilter_merge_conf(ngx_conf_t *cf, void *parent, void *child);
//ngx_command_t定义模块的配置文件参数
static ngx_command_t ngx_http_lcwfilter_commands[] =
{
{
//配置项名称
ngx_string("lcw_add_prefix"),
//配置项类型,将指定配置项可以出现的位置
//例如出现在server{}或location{}中,以及他可以携带的参数个数(现在有一个参数)
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_FLAG,
//ngx_command_t结构体中的set成员,
//当在某个配置块中出现lcw_add_prefix配置项时,Nginx将会调用ngx_conf_set_flag_slot方法
ngx_conf_set_flag_slot,//这个是预设函数,用于解析配置项,不用我们自己实现
//在配置文件中的偏移量conf
NGX_HTTP_LOC_CONF_OFFSET,
//offset通常用于使用预设的解析方法解析配置项,需要与conf配合使用
//解析配置后将配置项参数解析到ngx_http_lcwfilter_conf_t上下文结构体的enable成员中
offsetof(ngx_http_lcwfilter_conf_t, enable),
//配置项读取后的处理方法,必须是ngx_conf_post_t结构的指针
NULL
},
//ngx_null_command是一个空的ngx_command_t结构,用来表示数组的结尾
ngx_null_command
};
//ngx_http_module_t的8个回调方法,因为目前没有什么工作是必须在HTTP框架初始化
//时完成的,所以暂时不必实现ngx_http_module_t的8个回调方法
static ngx_http_module_t ngx_http_lcwfilter_module_ctx =
{
NULL, // preconfiguration解析配置文件前调用
ngx_http_lcwfilter_init,//postconfiguration 完成配置文件解析后调用 NULL, // create main configuration当需要创建数据结构用于存储main级别的
//(直属于http{}块的配置项)的全局配置项时
NULL, // init main configuration常用于初始化main级别的配置项 NULL, // create server configuration当需要创建数据结构用于存储srv级别的
//(直属于server{}块的配置项)的配置项时
NULL, // merge server configuration用于合并main级别和srv级别下的同名配置项 ngx_http_lcwfilter_create_conf,// create location configuration 当需要创建数据结构用于存储loc级别的
//(直属于location{}块的配置项)的配置项时
ngx_http_lcwfilter_merge_conf// merge location configuration 用于合并srv和loc级别下的同名配置项
};
//定义lcwfilter模块
//lcwfilter模块在编译时会被加入到ngx_modules全局数组中
//Nginx在启动时,会调用所有模块的初始化回调方法
//HTTP框架初始化时会调用ngx_http_module_t中的8个方法
//HTTP模块数据结构
ngx_module_t ngx_http_lcwfilter_module =
{
NGX_MODULE_V1,//该宏为下面的ctx_index,index,spare0,spare1,spare2,spare3,version变量
//提供了初始化的值:0,0,0,0,0,0,1
//ctx_index表示当前模块在这类模块中的序号
//index表示当前模块在所有模块中的序号,Nginx启动时会根据ngx_modules数组设置各模块的index值
//spare0 spare系列的保留变量,暂未使用
//spare1
//spare2
//spare3
//version模块的版本,便于将来的扩展,目前只有一种,默认为1
&ngx_http_lcwfilter_module_ctx, //ctx用于指向一类模块的上下文结构
ngx_http_lcwfilter_commands, //commands将处理nginx.conf中的配置项
NGX_HTTP_MODULE, //模块的类型,与ctx指针紧密相关,取值范围是以下5种:
//NGX_HTTP_MODULE,NGX_CORE_MODULE,NGX_CONF_MODULE,NGX_EVENT_MODULE,NGX_MAIL_MODULE
//以下7个函数指针表示有7个执行点会分别调用这7种方法,对于任一个方法而言,如果不需要nginx在某个是可执行它
//那么简单地将他设为空指针即可
NULL, //master进程启动时回调init_master
NULL, //init_module回调方法在初始化所有模块时被调用,在master/worker模式下,
//这个阶段将在启动worker子进程前完成
NULL, //init_process回调方法在正常服务前被调用,在master/worker模式下,
//多个worker子进程已经产生,在每个worker子进程的初始化过程会调用所有模块的init_process函数
NULL, //由于nginx暂不支持多线程模式,所以init thread在框架代码中没有被调用过
NULL, // exit thread,也不支持
NULL, //exit process回调方法将在服务停止前调用,在master/worker模式下,worker进程会在退出前调用它
NULL, //exit master回调方法将在master进程退出前被调用
NGX_MODULE_V1_PADDING //这里是8个spare_hook变量,是保留字段,目前没有使用,Nginx提供了NGX_MODULE_V1_PADDING宏来填充
};
/******************************************************
函数名:ngx_http_lcwfilter_init(ngx_conf_t *cf)
参数:
功能:初始化HTTP过滤模块
*******************************************************/
static ngx_int_t ngx_http_lcwfilter_init(ngx_conf_t *cf)
{
//插入到头部处理方法链表的首部
ngx_http_next_header_filter = ngx_http_top_header_filter;
ngx_http_top_header_filter = ngx_http_lcwfilter_header_filter;//这个方法在下面实现
//插入到包体处理方法链表的首部
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_lcwfilter_body_filter;//这个方法也在下面实现
return NGX_OK;
}
/******************************************************
函数名:ngx_http_lcwfilter_header_filter(ngx_http_request_t *r)
参数:
功能:HTTP头部处理方法
*******************************************************/
static ngx_int_t ngx_http_lcwfilter_header_filter(ngx_http_request_t *r)
{
//这个函数主要是获取配置项参数,并根据参数设置HTTP上下文
ngx_http_lcwfilter_ctx_t *ctx;//用于获取HTTP上下文结构
ngx_http_lcwfilter_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_lcwfilter_module);
if (ctx)
{
//该请求的上下文已经存在,这说明
// ngx_http_lcwfilter_header_filter已经被调用过1次,
//直接交由下一个过滤模块处理
return ngx_http_next_header_filter(r);
}
//获取存储配置项的ngx_http_lcwfilter_conf_t结构体
conf = ngx_http_get_module_loc_conf(r, ngx_http_lcwfilter_module);
//如果enable成员为0,也就是配置文件中没有配置lcw_add_prefix配置项,
//或者lcw_add_prefix配置项的参数值是off,这时直接交由下一个过滤模块处理
if (conf->enable == 0)
{
return ngx_http_next_header_filter(r);
}
//这里已经确认配置
//构造http上下文结构体ngx_http_lcwfilter_ctx_t
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lcwfilter_ctx_t));
if (ctx == NULL)
{
return NGX_ERROR;
}
//add_prefix为0表示不加前缀
ctx->add_prefix = 0;
//将构造的上下文设置到当前请求中
ngx_http_set_ctx(r, ctx, ngx_http_lcwfilter_module);
//lcwfilter过滤模块只处理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)
{
//1表示需要在http包体前加入前缀
ctx->add_prefix = 1;
//如果处理模块已经在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);
}
/******************************************************
函数名:ngx_int_t ngx_http_lcwfilter_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
参数:
功能:HTTP包体处理方法
*******************************************************/
static ngx_int_t ngx_http_lcwfilter_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_http_lcwfilter_ctx_t *ctx;//上下文结构
ctx = ngx_http_get_module_ctx(r, ngx_http_lcwfilter_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_lcwfilter_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);
}
/******************************************************
函数名:ngx_http_lcwfilter_create_conf(ngx_conf_t *cf)
参数:
功能:用于创建数据结构用于存储配置项的结构体
*******************************************************/
static void* ngx_http_lcwfilter_create_conf(ngx_conf_t *cf)
{
ngx_http_lcwfilter_conf_t *mycf;
//创建存储配置项的结构体
mycf = (ngx_http_lcwfilter_conf_t *)ngx_pcalloc(cf->pool, sizeof(ngx_http_lcwfilter_conf_t));
if (mycf == NULL)
{
return NULL;
}
//ngx_flat_t类型的变量,如果使用预设函数ngx_conf_set_flag_slot
//解析配置项参数,必须初始化为NGX_CONF_UNSET
mycf->enable = NGX_CONF_UNSET;
return mycf;
}
/******************************************************
函数名:ngx_http_lcwfilter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
参数:
功能:用于合并同名的配置项
*******************************************************/
static char *ngx_http_lcwfilter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_lcwfilter_conf_t *prev = (ngx_http_lcwfilter_conf_t *)parent;
ngx_http_lcwfilter_conf_t *conf = (ngx_http_lcwfilter_conf_t *)child;
//合并ngx_flat_t类型的配置项enable
ngx_conf_merge_value(conf->enable, prev->enable, 0);
return NGX_CONF_OK;
}

主要的配置块如下:

 location / {
root /;
lcw_add_prefix on;
}

然后在根目录创建文件lcw.txt,或者是其他我可以,我只在里面写了lcw三个字符

运行结果:

Nginx模块开发(5)————开发简单的HTTP过滤模块的更多相关文章

  1. 《深入理解Nginx》阅读与实践(四):简单的HTTP过滤模块

    一.Nginx的HTTP过滤模块特征 一个请求可以被任意个HTTP模块处理: 在普通HTTP模块处理请求完毕并调用ngx_http_send_header()发送HTTP头部或调用ngx_http_o ...

  2. 简单的HTTP过滤模块

    简单的HTTP过滤模块 一.Nginx的HTTP过滤模块特征 一个请求可以被任意个HTTP模块处理: 在普通HTTP模块处理请求完毕并调用ngx_http_send_header()发送HTTP头部或 ...

  3. 【Nginx】开发一个HTTP过滤模块

    与HTTP处理模块不同.HTTP过滤模块的工作是对发送给用户的HTTP响应做一些加工. server返回的一个响应能够被随意多个HTTP过滤模块以流水线的方式依次处理.HTTP响应分为头部和包体,ng ...

  4. Nginx:HTTP过滤模块

    参考资料<深入理解Nginx> HTTP过滤模块也是一种HTTP模块,与普通HTTP处理模块不同在于: 1.一个请求仅由一个HTTP处理模块处理,而可以被任意个HTTP过滤模块处理 2.普 ...

  5. Nginx 的过滤模块是干啥用的?

    上一篇文章我写了 Nginx 的 11 个阶段,很多人都说太长了.这是出于文章完整性的考虑的,11 个阶段嘛,一次性说完就完事了.今天这篇文章比较短,看完没问题. 过滤模块的位置 之前我们介绍了 Ng ...

  6. 简单深入Joomla!3.1.5模块_组件开发(一)

    简单深入Joomla!3.1.5模块_组件开发 主要内容: 1, 模块(访问数据库,链接到组件,数据基本流向) 2, 组件CRUD(MVC模式,访问数据库,表单提交,AJAX提交,数据基本流向) 3, ...

  7. Tornado开发技巧,简单了解tornado

    tornado基础入门(一)——简单了解tornado 参考:http://demo.pythoner.com/itt2zh/ch1.html tornado是一个轻量级的web框架,是一个用pyth ...

  8. 基于ngx_lua模块的waf开发实践

    0x00 常见WAF简单分析 WAF主要分为硬件WAF和软件防火墙,硬件WAF如绿盟的NSFOCUS Web Application Firewall,软件防火墙比较有名的是ModSecurity,再 ...

  9. Python开发【第六篇】:模块

    模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个函数才 ...

随机推荐

  1. MySQL中的事务和MVCC

    本篇博客参考掘金小册--MySQL 是怎样运行的:从根儿上理解 MySQL 以及极客时间--MySQL实战45讲. 虽然我们不是DBA,可能对数据库没那么了解,但是对于数据库中的索引.事务.锁,我们还 ...

  2. Python操作rabbitmq系列(四):根据类型订阅消息

    在上一章中,所有的接收端获取的所有的消息.这一章,我们将讨论,一些消息,仍然发送给所有接收端.其中,某个接收端,只对其中某些消息感兴趣,它只想接收这一部分消息.如下图:C1,只对error感兴趣,C2 ...

  3. 页面存在多个url,使用jmeter进行遍历操作

    有一次遇见一个问题:进入网站后,有多个相同的url,但是仅url后面的路径中id有区别,如下图:这时我想要遍历点击查看url详情内容:那么就可以使用一个“逻辑控制器---foreach控制器” 如下: ...

  4. 内存对齐 align

    /* 地址对齐:指的是存放数据的首地址%N==0,而且整个结构体的大小%M(结构体的有效对齐值)==0 1 数据类型的自身对齐值:char:1 short:2 int,flolat,double:4 ...

  5. 利用numpy实现多维数组操作图片

    1.上次介绍了一点点numpy的操作,今天我们来介绍它如何用多维数组操作图片,这之前我们要了解一下色彩是由blue ,green ,red 三种颜色混合而成,0:表示黑色 ,127:灰色 ,255:白 ...

  6. SVN版本控制器的使用说明(详细过程)

    SVN使用教程总结  SVN简介: 为什么要使用SVN? 程序员在编写程序的过程中,每个程序员都会生成很多不同的版本,这就需要程序员有效的管理代码,在需要的时候可以迅速,准确取出相应的版本. Subv ...

  7. 详解 Web基本概念

    作为本专栏的第一篇博文,本人将带领同学们初步了解什么是Web,以及有关Web学习的一些基本知识点 那么,话不多说,开始主题的讲解吧: 首先,本人来解释下什么是Web: 概念: 使用浏览器进行访问的应用 ...

  8. 面试官:兄弟,说说Java到底是值传递还是引用传递

    二哥,好久没更新面试官系列的文章了啊,真的是把我等着急了,所以特意过来催催.我最近一段时间在找工作,能从二哥的文章中学到一点就多一点信心啊! 说句实在话,离读者 trust you 发给我这段信息已经 ...

  9. selenium 时间等待的方法

    一.强制等待固定秒数 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } 执行到sl ...

  10. Java环境下 selenium webDriver + chrome浏览器搭建与调试

    一.首先下载selenium webDriver jar包,下载地址如下: http://selenium-release.storage.googleapis.com/index.html 二.下载 ...