nginx 编写简单HTTP模块以及nginx http handler的hello world示例编写
2018-01-19 09:55
706 查看
编写nginx http handler模块以便开发自己模块,本文提供hello编写到编译的详细步骤 , 文章最后提供整个示例代码
command中用于处理配置项参数的set 方法,函数名格式写法ngx_http_xxxxx,如下所示:
NGX_CONF_TAKE1:配置指令接受1个参数。
NGX_CONF_TAKE2:配置指令接受2个参数。
NGX_CONF_TAKE3:配置指令接受3个参数。
NGX_CONF_TAKE4:配置指令接受4个参数。
NGX_CONF_TAKE5:配置指令接受5个参数。
NGX_CONF_TAKE6:配置指令接受6个参数。
NGX_CONF_TAKE7:配置指令接受7个参数。
可以组合多个属性,比如一个指令即可以不填参数,也可以接受1个或者2个参数。那么就是NGX_CONF_NOARGS|NGX_CONF_TAKE1|NGX_CONF_TAKE2。如果写上面三个属性在一起,你觉得麻烦,那么没有关系,nginx提供了一些定义,使用起来更简洁。NGX_CONF_TAKE12:配置指令接受1个或者2个参数。
NGX_CONF_TAKE13:配置指令接受1个或者3个参数。
NGX_CONF_TAKE23:配置指令接受2个或者3个参数。
NGX_CONF_TAKE123:配置指令接受1个或者2个或者3参数。
NGX_CONF_TAKE1234:配置指令接受1个或者2个或者3个或者4个参数。
NGX_CONF_1MORE:配置指令接受至少一个参数。
NGX_CONF_2MORE:配置指令接受至少两个参数。
NGX_CONF_MULTI: 配置指令可以接受多个参数,即个数不定。
NGX_CONF_BLOCK:配置指令可以接受的值是一个配置信息块。也就是一对大括号括起来的内容。里面可以再包括很多的配置指令。比如常见的server指令就是这个属性的。
NGX_CONF_FLAG:配置指令可以接受的值是”on”或者”off”,最终会被转成bool值。
NGX_CONF_ANY:配置指令可以接受的任意的参数值。一个或者多个,或者”on”或者”off”,或者是配置块。 最后要说明的是,无论如何,nginx的配置指令的参数个数不可以超过NGX_CONF_MAX_ARGS个。目前这个值被定义为8,也就是不能超过8个参数值。
下面介绍一组说明配置指令可以出现的位置的属性。NGX_DIRECT_CONF:可以出现在配置文件中最外层。例如已经提供的配置指令daemon,master_process等。
NGX_MAIN_CONF: http、mail、events、error_log等。
NGX_ANY_CONF: 该配置指令可以出现在任意配置级别上。 对于我们编写的大多数模块而言,都是在处理http相关的事情,也就是所谓的都是NGX_HTTP_MODULE,对于这样类型的模块,其配置可能出现的位置也是分为直接出现在http里面,以及其他位置。
NGX_HTTP_MAIN_CONF: 可以直接出现在http配置指令里。
NGX_HTTP_SRV_CONF: 可以出现在http里面的server配置指令里。
NGX_HTTP_LOC_CONF: 可以出现在http server块里面的location配置指令里。
NGX_HTTP_UPS_CONF: 可以出现在http里面的upstream配置指令里。
NGX_HTTP_SIF_CONF: 可以出现在http里面的server配置指令里的if语句所在的block中。
NGX_HTTP_LMT_CONF: 可以出现在http里面的limit_except指令的block中。
NGX_HTTP_LIF_CONF: 可以出现在http server块里面的location配置指令里的if语句所在的block中。
set: 这是一个函数指针,当nginx在解析配置的时候,如果遇到这个配置指令,将会把读取到的值传递给这个函数进行分解处理。因为具体每个配置指令的值如何处理,只有定义这个配置指令的人是最清楚的。来看一下这个函数指针要求的函数原型。
对于下列回调方法 :init_module、init_process、exit_process、exit_master,调用它们的 是 Nginx 的框架代码。换句话说,这 4 个回调方法与 HTTP 框架无关,即使 nginx.conf 中没 有配置 http {...} 这种开启 HTTP 功能的配置项,这些回调方法仍然会被调用。因此,通常 开发 HTTP 模块时都把它们设为 NULL 空指针。这样,当 Nginx 不作为 Web 服务器使用时, 不会执行 HTTP 模块的任何代码。
定义 HTTP 模块时,最重要的是要设置 ctx 和 commands 这两个成员。对于 HTTP 类型 的模块来说,ngx_module_t 中的 ctx 指针必须指向 ngx_http_module_t 接口(HTTP 框架的要 求)。下面先来分析 ngx_http_module_t 结构体的成员。
HTTP 框架在读取、重载配置文件时定义了由 ngx_http_module_t 接口描述的 8 个阶段, HTTP 框架在启动过程中会在每个阶段中调用 ngx_http_module_t 中相应的方法。当然,如果 ngx_http_module_t 中的某个回调方法设为 NULL 空指针,那么 HTTP 框架是不会调用它的。
编写http handler模块的几个组成部分讲解:
1、ngx_command_t
示例:static ngx_command_t ngx_http_mytest_commands[] = { { ngx_string("mytest"), NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS, ngx_http_mytest, NGX_HTTP_LOC_CONF_OFFSET, 0, NULL }, ngx_null_command };在nginx.conf 中编写的配置项 mytest 来说, nginx 首先会遍历所有的模块(modules),而对于每个模块, 会遍历他所对应的ngx_command_t 数组, 试图找到关于我们的配置项mytest 的解析方式。
command中用于处理配置项参数的set 方法,函数名格式写法ngx_http_xxxxx,如下所示:
static char * ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_loc_conf_t *clcf; //首先找到mytest配置项所属的配置块,clcf貌似是location块内的数据 //结构,其实不然,它可以是main、srv或者loc级别配置项,也就是说在每个 //http{}和server{}内也都有一个ngx_http_core_loc_conf_t结构体 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); //http框架在处理用户请求进行到NGX_HTTP_CONTENT_PHASE阶段时,如果 //请求的主机域名、URI与mytest配置项所在的配置块相匹配,就将调用我们 //实现的ngx_http_mytest_handler方法处理这个请求 clcf->handler = ngx_http_mytest_handler; return NGX_CONF_OK; }关于ngx_http_conf_get_module_loc_conf 的定义可以参考: http://lxr.nginx.org/source/src/http/ngx_http_config.h#0065 本质: 就是设置ngx_http_mytest_handler, 匹配项被选中的时候, 应该如何解析。ngx_command_t的定义,位于src/core/ngx_conf_file.h中。
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; };name: 配置指令的名称。type: 该配置的类型,其实更准确一点说,是该配置指令属性的集合。nginx提供了很多预定义的属性值(一些宏定义),通过逻辑或运算符可组合在一起,形成对这个配置指令的详细的说明。下面列出可在这里使用的预定义属性值及说明。NGX_CONF_NOARGS:配置指令不接受任何参数。
NGX_CONF_TAKE1:配置指令接受1个参数。
NGX_CONF_TAKE2:配置指令接受2个参数。
NGX_CONF_TAKE3:配置指令接受3个参数。
NGX_CONF_TAKE4:配置指令接受4个参数。
NGX_CONF_TAKE5:配置指令接受5个参数。
NGX_CONF_TAKE6:配置指令接受6个参数。
NGX_CONF_TAKE7:配置指令接受7个参数。
可以组合多个属性,比如一个指令即可以不填参数,也可以接受1个或者2个参数。那么就是NGX_CONF_NOARGS|NGX_CONF_TAKE1|NGX_CONF_TAKE2。如果写上面三个属性在一起,你觉得麻烦,那么没有关系,nginx提供了一些定义,使用起来更简洁。NGX_CONF_TAKE12:配置指令接受1个或者2个参数。
NGX_CONF_TAKE13:配置指令接受1个或者3个参数。
NGX_CONF_TAKE23:配置指令接受2个或者3个参数。
NGX_CONF_TAKE123:配置指令接受1个或者2个或者3参数。
NGX_CONF_TAKE1234:配置指令接受1个或者2个或者3个或者4个参数。
NGX_CONF_1MORE:配置指令接受至少一个参数。
NGX_CONF_2MORE:配置指令接受至少两个参数。
NGX_CONF_MULTI: 配置指令可以接受多个参数,即个数不定。
NGX_CONF_BLOCK:配置指令可以接受的值是一个配置信息块。也就是一对大括号括起来的内容。里面可以再包括很多的配置指令。比如常见的server指令就是这个属性的。
NGX_CONF_FLAG:配置指令可以接受的值是”on”或者”off”,最终会被转成bool值。
NGX_CONF_ANY:配置指令可以接受的任意的参数值。一个或者多个,或者”on”或者”off”,或者是配置块。 最后要说明的是,无论如何,nginx的配置指令的参数个数不可以超过NGX_CONF_MAX_ARGS个。目前这个值被定义为8,也就是不能超过8个参数值。
下面介绍一组说明配置指令可以出现的位置的属性。NGX_DIRECT_CONF:可以出现在配置文件中最外层。例如已经提供的配置指令daemon,master_process等。
NGX_MAIN_CONF: http、mail、events、error_log等。
NGX_ANY_CONF: 该配置指令可以出现在任意配置级别上。 对于我们编写的大多数模块而言,都是在处理http相关的事情,也就是所谓的都是NGX_HTTP_MODULE,对于这样类型的模块,其配置可能出现的位置也是分为直接出现在http里面,以及其他位置。
NGX_HTTP_MAIN_CONF: 可以直接出现在http配置指令里。
NGX_HTTP_SRV_CONF: 可以出现在http里面的server配置指令里。
NGX_HTTP_LOC_CONF: 可以出现在http server块里面的location配置指令里。
NGX_HTTP_UPS_CONF: 可以出现在http里面的upstream配置指令里。
NGX_HTTP_SIF_CONF: 可以出现在http里面的server配置指令里的if语句所在的block中。
NGX_HTTP_LMT_CONF: 可以出现在http里面的limit_except指令的block中。
NGX_HTTP_LIF_CONF: 可以出现在http server块里面的location配置指令里的if语句所在的block中。
set: 这是一个函数指针,当nginx在解析配置的时候,如果遇到这个配置指令,将会把读取到的值传递给这个函数进行分解处理。因为具体每个配置指令的值如何处理,只有定义这个配置指令的人是最清楚的。来看一下这个函数指针要求的函数原型。
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
2、定义ngx_http_module_t 接口
这部分的代码, 是用于http框架的, 相当于http框架的回掉函数, 由于这里并不需要框架做任何操作,格式ngx_http_xxxxx_module_ctx。static ngx_http_module_t ngx_http_mytest_module_ctx = { NULL, /* preconfiguration */ NULL, /* 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 */ };
3、ngx_module_t模块的定义
示例: 格式ngx_http_xxxx_module只需要简单的设置3个项目: ctx(指向模块的上下文), commands, type(模块类型)ngx_module_t ngx_http_mytest_module = { NGX_MODULE_V1, &ngx_http_mytest_module_ctx, /* module context */ ngx_http_mytest_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 };来参考一下深入理解nginx书中对http模块数据结构的理解:
定义 HTTP 模块方式很简单,例如: ngx_module_t ngx_http_mytest_module; 其中,ngx_module_t 是一个 Nginx 模块的数据结构(详见 8.2 节)。下面来分析一下 Nginx 模块中所有的成员,如下所示: typedef struct ngx_module_s ngx_module_t; struct ngx_module_s { /* 下面的 ctx_index、index、spare0、spare1、spare2、spare3、version 变量不需要在定义时赋值, 可以用 Nginx 准备好的宏 NGX_MODULE_V1 来定义,它已经定义好了这 7 个值。 #define NGX_MODULE_V1 0, 0, 0, 0, 0, 0, 1 对于一类模块(由下面的 type 成员决定类别)而言,ctx_index 表示当前模块在这类模块中的序号。这 个成员常常是由管理这类模块的一个 Nginx 核心模块设置的,对于所有的 HTTP 模块而言,ctx_index 是由核心模 块 ngx_http_module 设置的。ctx_index 非常重要,Nginx 的模块化设计非常依赖于各个模块的顺序,它们既用 于表达优先级,也用于表明每个模块的位置,借以帮助 Nginx 框架快速获得某个模块的数据(HTTP 框架设置 ctx_ index 的过程参见 10.7 节)*/ ngx_uint_t ctx_index; /*index 表示当前模块在 ngx_modules 数组中的序号。注意,ctx_index 表示的是当前模块在一类模 块中的序号,而 index 表示当前模块在所有模块中的序号,它同样关键。Nginx 启动时会根据 ngx_modules 数组 设置各模块的 index 值。例如: ngx_max_module = 0; for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = ngx_max_module++; } */ ngx_uint_t index; //spare 系列的保留变量,暂未使用 ngx_uint_t spare0; ngx_uint_t spare1; ngx_uint_t spare2; ngx_uint_t spare3; // 模块的版本,便于将来的扩展。目前只有一种,默认为 1 ngx_uint_t version; /*ctx 用于指向一类模块的上下文结构体,为什么需要 ctx 呢?因为前面说过,Nginx 模块有许多种类, 不同类模块之间的功能差别很大。例如,事件类型的模块主要处理 I/O 事件相关的功能,HTTP 类型的模块主要处理 HTTP 应用层的功能。这样,每个模块都有了自己的特性,而 ctx 将会指向特定类型模块的公共接口。例如,在 HTTP 模块中,ctx 需要指向 ngx_http_module_t 结构体 */ void *ctx; //commands 将处理 nginx.conf 中的配置项,详见第 4 章 ngx_command_t *commands; /*type 表示该模块的类型,它与 ctx 指针是紧密相关的。在官方 Nginx 中,它的取值范围是以下 5 种 : NGX_HTTP_MODULE、NGX_CORE_MODULE、NGX_CONF_MODULE、NGX_EVENT_MODULE、NGX_MAIL_MODULE。这 5 种模块间的关系参考图 8-2。实际上,还可以自定义新的模块类型 */ ngx_uint_t type; /* 在 Nginx 的启动、停止过程中,以下 7 个函数指针表示有 7 个执行点会分别调用这 7 种方法(参见 8.4 节~ 8.6 节)。对于任一个方法而言,如果不需要 Nginx 在某个时刻执行它,那么简单地把它设为 NULL 空指针 即可 */ /* 虽然从字面上理解应当在 master 进程启动时回调 init_master,但到目前为止,框架代码从来不会 调用它,因此,可将 init_master 设为 NULL */ ngx_int_t (*init_master)(ngx_log_t *log); /*init_module 回调方法在初始化所有模块时被调用。在 master/worker 模式下,这个阶段将在启动 worker 子进程前完成 */ ngx_int_t (*init_module)(ngx_cycle_t *cycle); /* init_process 回调方法在正常服务前被调用。在 master/worker 模式下,多个 worker 子进程已经产 生,在每个 worker 进程的初始化过程会调用所有模块的 init_process 函数 */ ngx_int_t (*init_process)(ngx_cycle_t *cycle); /* 由于 Nginx 暂不支持多线程模式,所以 init_thread 在框架代码中没有被调用过,设为 NULL*/ ngx_int_t (*init_thread)(ngx_cycle_t *cycle); // 同上,exit_thread 也不支持,设为 NULL void (*exit_thread)(ngx_cycle_t *cycle); /* exit_process 回调方法在服务停止前调用。在 master/worker 模式下,worker 进程会在退出前调用它 */ void (*exit_process)(ngx_cycle_t *cycle); // exit_master 回调方法将在 master 进程退出前被调用 void (*exit_master)(ngx_cycle_t *cycle); /* 以下 8 个 spare_hook 变量也是保留字段,目前没有使用,但可用 Nginx 提供的 NGX_MODULE_V1_ PADDING 宏来填充。看一下该宏的定义:#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0*/ uintptr_t spare_hook0; uintptr_t spare_hook1; uintptr_t spare_hook2; 第 3 章 开发一个简单的 HTTP 模块 87 uintptr_t spare_hook3; uintptr_t spare_hook4; uintptr_t spare_hook5; uintptr_t spare_hook6; uintptr_t spare_hook7; };定义一个 HTTP 模块时,务必把 type 字段设为 NGX_HTTP_MODULE。
对于下列回调方法 :init_module、init_process、exit_process、exit_master,调用它们的 是 Nginx 的框架代码。换句话说,这 4 个回调方法与 HTTP 框架无关,即使 nginx.conf 中没 有配置 http {...} 这种开启 HTTP 功能的配置项,这些回调方法仍然会被调用。因此,通常 开发 HTTP 模块时都把它们设为 NULL 空指针。这样,当 Nginx 不作为 Web 服务器使用时, 不会执行 HTTP 模块的任何代码。
定义 HTTP 模块时,最重要的是要设置 ctx 和 commands 这两个成员。对于 HTTP 类型 的模块来说,ngx_module_t 中的 ctx 指针必须指向 ngx_http_module_t 接口(HTTP 框架的要 求)。下面先来分析 ngx_http_module_t 结构体的成员。
HTTP 框架在读取、重载配置文件时定义了由 ngx_http_module_t 接口描述的 8 个阶段, HTTP 框架在启动过程中会在每个阶段中调用 ngx_http_module_t 中相应的方法。当然,如果 ngx_http_module_t 中的某个回调方法设为 NULL 空指针,那么 HTTP 框架是不会调用它的。
4.编写config文件,编译代码的时候用
config文件和编写c文件放在同一个文件下:比如我放在:[root@hadoop2 nginx-1.13.8]# pwd /root/nginx-1.13.8 [root@hadoop2 nginx-1.13.8]# cd mytesthttp/ [root@hadoop2 mytesthttp]# ll total 16 -rw-r--r-- 1 root root 163 Jan 18 09:56 config -rw-r--r-- 1 root root 8915 Jan 18 15:52 ngx_http_mytest_module.c [root@hadoop2 mytesthttp]#其中config文件内容基本下面的形式:
ngx_addon_name=ngx_http_mytest_module HTTP_MODULES="$HTTP_MODULES ngx_http_mytest_module" NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_mytest_module.c"$ngx_addon_dir 这个值是执行configure 时候添加的选线--add-module提供的:--add-module=/root/nginx-1.13.8/mytesthttp执行nginx目录下configure生成makefile,--prefix=/root/nginx-1.13.8/bin提供nginx的安装路径,随便设置成你自己的想安装到的目录都是可以的。
./configure \ --prefix=/root/nginx-1.13.8/bin \ --user=root\ --group=root\ --add-module=/root/nginx-1.13.8/mytesthttp \ --with-http_stub_status_module \ --with-http_flv_module \ --with-http_stub_status_module \ --with-http_gzip_static_module \ --with-http_gunzip_module \ --with-pcre \ --with-debug
5.配置nginx配置文件nginx.conf。一般nginx的conf文件在安装路径目录下(--prefix提供的那个路径):
添加内容参考如下:server { listen 8017; server_name localhost; access_log logs/get.log main; #access_log off; location / { root html; index index.html index.htm; } location /hello { mytest; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }访问示例:
http://192.168.0.153:8017/hello/mytest整体code参考:(结合文章理解)
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#define PB_SIZE (1024 * 2)
#define CONTENT_TYPE "application/json;charset=GB2312"
static char* ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r);
static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
static ngx_command_t ngx_http_mytest_commands[] =
{
{
ngx_string("mytest"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_HTTP_LMT_CONF | NGX_CONF_NOARGS,
ngx_http_mytest,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL
},
ngx_null_command
};
static ngx_http_module_t ngx_http_mytest_module_ctx = { NULL, /* preconfiguration */ NULL, /* 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_t ngx_http_mytest_module = { NGX_MODULE_V1, &ngx_http_mytest_module_ctx, /* module context */ ngx_http_mytest_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 };
static char *ngx_http_mytest(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_mytest_handler;
return NGX_CONF_OK;
}
static ngx_int_t ngx_http_mytest_handler(ngx_http_request_t *r)
{
static char uri[PB_SIZE];
static char decode[PB_SIZE];
static char args[PB_SIZE];
char* src;
char* dst;
int status=NGX_HTTP_OK;
//int reply_len=0;
//char *reply=0;
ngx_int_t rc;
ngx_chain_t out;
//post handle
if ((r->method & (NGX_HTTP_POST|NGX_HTTP_HEAD)))
{
//get body
rc = ngx_http_read_client_request_body(r, ngx_http_read_client_request_body_handler);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
return rc;
}
return NGX_DONE;
}
//get handle
else if ((r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD)))
{
//get uri
if (r->uri.len>=PB_SIZE)
return NGX_HTTP_NOT_ALLOWED;
ngx_memcpy(uri,r->uri.data,r->uri.len);
uri[r->uri.len]=0;
src = uri;
dst = decode;
ngx_unescape_uri((u_char**)&dst, (u_char**)&src, r->uri.len, 0);
ngx_memcpy(uri,decode,dst - decode);
uri[dst - decode] = '\0';
//get args
if (r->args.len>=PB_SIZE)
return NGX_HTTP_NOT_ALLOWED;
ngx_memcpy(args,r->args.data,r->args.len);
args[r->args.len]=0;
src = args;
dst =decode;
ngx_unescape_uri((u_char**)&dst, (u_char**)&src, r->args.len, 0);
ngx_memcpy(args,decode,dst - decode);
args[dst - decode] = '\0';
//reply=request(uri,args,&status,&reply_len);
ngx_str_t response = ngx_string("Hello World!");
if (status!=NGX_HTTP_OK)
{
return status;
}
ngx_str_t type =ngx_string(CONTENT_TYPE);
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_type = type;
//r->headers_out.content_length_n = reply_len;
r->headers_out.content_length_n = response.len;
ngx_buf_t *b = ngx_create_temp_buf(r->pool, response.len);
if(b == NULL)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ngx_memcpy(b->pos, response.data, response.len);
b->last = b->pos+response.len;
b->last_buf = 1;
out.buf = b;
out.next = NULL;
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only)
{
return rc;
}
return ngx_http_output_filter(r, &out);
}
else
{
return NGX_HTTP_NOT_ALLOWED;
}
}
static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
{
static char uri[PB_SIZE];
static char decode[PB_SIZE];
char* body = NULL;
int body_size = 0;
char* src;
char* dst;
//char *reply=0;
int status=NGX_HTTP_OK;
//int reply_len=0;
ngx_int_t rc;
ngx_chain_t out;
ngx_chain_t* bufs = r->request_body->bufs;
ngx_buf_t* buf = NULL;
uint8_t* data_buf = NULL;
size_t content_length = 0;
size_t body_length = 0;
//get uri
if (r->uri.len>=PB_SIZE)
{
ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
ngx_memcpy(uri,r->uri.data,r->uri.len);
uri[r->uri.len]=0;
src = uri;
dst = decode;
ngx_unescape_uri((u_char**)&dst, (u_char**)&src, r->uri.len, 0);
ngx_memcpy(uri,decode,dst - decode);
uri[dst - decode] = '\0';
//get body
if (r->request_body == NULL)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "reqeust_body:null");
ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
if ( r->headers_in.content_length == NULL )
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "r->headers_in.content_length == NULL");
ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
content_length = atoi( (char*)(r->headers_in.content_length->value.data) );
data_buf = ( uint8_t* )ngx_palloc( r->pool , content_length + 1 );
size_t buf_length = 0;
while ( bufs )
{
buf = bufs->buf;
bufs = bufs->next;
buf_length = buf->last - buf->pos ;
if( body_length + buf_length > content_length )
{
memcpy( data_buf + body_length, buf->pos, content_length - body_length);
body_length = content_length ;
break;
}
memcpy( data_buf + body_length, buf->pos, buf->last - buf->pos );
body_length += buf->last - buf->pos;
}
if ( body_length )
{
data_buf[body_length] = 0;
}
body = (char *)data_buf;
body_size = body_length;
//int sequence = getSequence(r);
//reply = mypost(uri, body, body_size,sequence,&status, &reply_len);
//ÕâÀïmypostÆäʵ¾ÍÊÇÀ©Õ¹´¦ÀípostÌá½»±íµ¥Êý¾Ýbody£¬¿ÉÒÔ°Ñ´æµ½dbÖÐÖ®ÀàµÄÆäËûÈÎÒâÒµÎñÂß¼
ngx_str_t response = ngx_string("Hello World!");
if(status != NGX_HTTP_OK)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Post failed.");
ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
ngx_str_t type =ngx_string(CONTENT_TYPE);
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_type = type;
//r->headers_out.content_length_n = reply_len;
r->headers_out.content_length_n = response.len;
ngx_buf_t *b = ngx_create_temp_buf(r->pool, response.len);
if(b == NULL)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to allocate response buffer.");
ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
ngx_memcpy(b->pos, response.data, response.len);
b->last = b->pos+response.len;
b->last_buf = 1;
out.buf = b;
out.next = NULL;
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Failed to do ngx_http_send_header.");
ngx_http_finalize_request(r,NGX_HTTP_INTERNAL_SERVER_ERROR);
return ;
}
ngx_http_finalize_request(r,ngx_http_output_filter(r, &out));
return;
}
相关文章推荐
- nginx 编写简单HTTP模块 hello world
- Nginx编写HTTP模块:第一个Nginx HTTP模块 “Hello World!”
- Nginx源码分析与实践---(一)编写一个简单的Http模块
- Nginx编写HTTP模块:“Hello World”的第二种写法(HTTP模块介入阶段的2种方法)
- Nginx开发一个简单的HTTP过滤模块
- Nginx之一:实现简单HTTP模块helloworld
- Nginx开发一个简单的HTTP过滤模块
- nginx HTTP模块的hello world
- Nginx之一:实现简单HTTP模块helloworld
- nginx的http模块配置接口以及http框架配置内存布局
- Linux(Centos)之安装Nginx及注意事项 阅读目录 1.Nginx的简单说明 2.准备工作 3.安装SSL功能需要openssl库以及gzip模块需要的zlib库 4.安装 rewri
- Nginx之一:实现简单HTTP模块helloworld
- Nginx模块开发(5)————开发简单的HTTP过滤模块
- nginx的HTTP模块编写
- Python中使用urllib2模块编写爬虫的简单上手示例
- Nginx之一:实现简单HTTP模块helloworld
- HttpHandler简单示例
- nginx的HTTP模块编写
- 为Lua5.3编写C模块简单示例
- Nginx之一:实现简单HTTP模块helloworld