您的位置:首页 > 运维架构 > Nginx

文章9:Nginx模块开发详细介绍--以HelloWorld模块为例

2015-01-24 10:46 471 查看
文章内容:

一结构体介绍


1.结构体ngx_command_t 模块的指令
1.1结构体原型
1.2结构体成员变量说明
1.3 实例
2.ngx_conf_t模块的配置结构体
2.1结构体原型
3.ngx_http_module_t结构体 模块上下文
3.1结构体原型
3.2结构体作用:
3.3实例
4.ngx_module_t结构体 模块定义
4.1结构体原型:
4.2结构体作用:
4.3实例
二.处理模块、过滤模块和负载均衡模块

2.1. 剖析处理模块(非代理)
2.1.1获得位置配置结构体
2.1.2产生回复
2.1.3发送HTTP头部
2.1.4 发送HTTP主体
2.1.5最后附上hello_world模块的完整代码

2.2剖析配置文件config

2.2.1.内容
2.2.2.作用
2.2.3.对应

三、综上所述,如何安装HelloWorld模块呢?

一、结构体介绍
1、ngx_command_t模块的指令

[align=left]1.1结构体原型[/align]
[align=left]struct ngx_command_s {[/align]
[align=left] ngx_str_t name;[/align]
[align=left] ngx_uint_t type;[/align]
[align=left] char *(* set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);[/align]
[align=left] ngx_uint_t conf;[/align]
[align=left] ngx_uint_t offset;[/align]
[align=left] void * post;[/align]
[align=left]};[/align]
1.2结构体成员变量说明:

name:是指令的字符串(也就是包含指令名称),不包含空格(有空格的话,就是命令的参数),

type:标识的集合。表明这个指令是在哪里出现是合法的、指令的参数个数。

标识一般是下面多个值的位或。

一、NGX_HTTP_MAIN_CONF:指令出现在全局配置部分是合法的

NGX_HTTP_SRV_CONF

NGX_HTTP_LOC_CONF

NGX_HTTP_UPS_CONF

二、NGX_CONF_NOARGS:指令没有参数

NGX_CONF_TAKE1:指令读入一个参数

....

NGX_CONF_TAKE7:指令读入7个参数

三、NGX_CONF_FLAG:指令读入一个布尔型数据

NGX_CONF_1MORE:指令至少读入1个参数

NGX_CONF_2MORE:指令至少读入2个参数

set:char *(* set )(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

结构体成员set是一个函数指针,用来设定模块的配置;典型地,这个函数会转化读入指令传进来的参数,然后将合适的值保存到配置结构体。这个设定函数有三个参数:

1)指向ngx_conf_t结构体的指针,包含从配置文件中指令传过来的参数

2)指向当前ngx_command_t结构体的指针

3)指向自定义模块配置结构体的指针void *conf

这个设定函数set在指令被遇到的时候就会调用。

后三个参数: 在自定义的配置结构体void *conf中,Nginx提供了多个函数用来保存特定类型的数据,这些函数包含有:

ngx_conf_set_flag_slot::将on或off转化为

ngx_conf_set_str_slot:将字符串保存为ngx_str_t类型

ngx_conf_set_num_slot:解析一个数字并保存为int类型

ngx_conf_set_size_slot:解析一个数据大小并保存为size_t类型

那这些内嵌函数怎么知道要把值保存在哪里呢?

ngx_command_t接下来的两个成员 conf和 offset正好可用。 conf告诉 Nginx把这个值是放在全局配置部分、主机配置部分还是位置配置部分(NGX_HTTP_MAIN_CONF_OFFSET,
NGX_HTTP_SRV_CONF_OFFSET或NGX_HTTP_LOC_CONF_OFFSET)。然后offset确定到底是保存在结构体的哪个位置。最后,post指向模块在读配置的时候需要的一些零碎变量。一般它是NULL。
这个ngx_command_t数组在读入ngx_null_command后停止
1.3实例

static ngx_command_t ngx_http_hello_world_commands[]={
[align=left] {[/align]
[align=left] ngx_string( "hello_world"),[/align]
[align=left] NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,[/align]
[align=left] ngx_http_hello_world,[/align]
[align=left] 0,[/align]
[align=left] 0,[/align]
[align=left] NULL[/align]
[align=left] },[/align]
[align=left] ngx_null_command[/align]
[align=left]};[/align]
2.ngx_conf_t模块的配置结构体

[align=left]2.1结构体原型[/align]
[align=left]struct ngx_conf_s {[/align]
[align=left] char * name;[/align]
[align=left] ngx_array_t * args;[/align]

[align=left] ngx_cycle_t * cycle;[/align]
[align=left] ngx_pool_t * pool;[/align]
[align=left] ngx_pool_t * temp_pool;[/align]
[align=left] ngx_conf_file_t * conf_file;[/align]
[align=left] ngx_log_t * log;[/align]

[align=left] void * ctx;[/align]
[align=left] ngx_uint_t module_type;[/align]
[align=left] ngx_uint_t cmd_type;[/align]

[align=left] ngx_conf_handler_pt handler;[/align]
[align=left] char * handler_conf;[/align]
[align=left]};[/align]
3.ngx_http_module_t结构体 模块上下文

[align=left]3.1结构体原型[/align]
[align=left]typedef struct {[/align]
[align=left] ngx_int_t (* preconfiguration)(ngx_conf_t *cf);//在读入配置文件前调用[/align]
[align=left] ngx_int_t (* postconfiguration)(ngx_conf_t *cf);//在读入配置文件后调用[/align]

[align=left] void *(* create_main_conf)(ngx_conf_t *cf);//在创建全局部分配置时调用(比如,用来分配空间和设置默认值)[/align]
char *(* init_main_conf)(ngx_conf_t *cf, void *conf);//在初始化全局部分的配置时调用(比如,把原来的默认值用nginx.conf
读到的值来覆盖)

[align=left] void *(* create_srv_conf)(ngx_conf_t *cf);//在创建主机部分的配置时调用[/align]
[align=left] char *(* merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);//与全局部分配置合并时调用[/align]

[align=left] void *(* create_loc_conf)(ngx_conf_t *cf);//创建位置部分的配置时掉用[/align]
[align=left] char *(* merge_loc_conf )(ngx_conf_t *cf, void *prev, void *conf);//与主机部分配置合并时调用[/align]
[align=left]} ngx_http_module_t;[/align]
3.2结构体作用:

静态的ngx_http_module_t结构体,包含一大把函数引用。用来创建三个部分的配置和合并配置。一般结构体命名为ngx_http_<module_name>_module_ctx
大多数处理模块只使用最后两个:一个函数用来为特定的位置部分的配置结构体分配内存(称为ngx_http_<module name>_create_loc_conf),另外一个函数用来设定默认值和与继承过来的配置合并(称为ngx_http_<module name>_merge_loc_conf)。这个合并函数负责检验读入的数值是否有效,并设定一些默认值
3.3实例

static ngx_http_module_t ngx_http_hello_world_module_ctx={
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL[/align]
[align=left]};[/align]
4.ngx_module_t结构体 模块定义
[align=left]4.1结构体原型[/align]
[align=left]struct ngx_module_s {[/align]
[align=left] ngx_uint_t ctx_index;[/align]
[align=left] ngx_uint_t index;[/align]

[align=left] ngx_uint_t spare0;[/align]
[align=left] ngx_uint_t spare1;[/align]
[align=left] ngx_uint_t spare2;[/align]
[align=left] ngx_uint_t spare3;[/align]

[align=left] ngx_uint_t version;[/align]

void * ctx;/*
module context */
ngx_command_t * commands;/*
module directives */
ngx_uint_t type;/*
module type */

ngx_int_t (* init_master)(ngx_log_t *log);/*
init master */

ngx_int_t (* init_module)(ngx_cycle_t *cycle);/*
init module */

ngx_int_t (* init_process)(ngx_cycle_t *cycle);/*
init process */
ngx_int_t (* init_thread)(ngx_cycle_t *cycle);/*
init thread */
void (* exit_thread)(ngx_cycle_t *cycle);/*
exit thread */
void (* exit_process)(ngx_cycle_t *cycle);/*
exit process */

void (* exit_master)(ngx_cycle_t *cycle);/*
exit master */

[align=left] uintptr_t spare_hook0;[/align]
[align=left] uintptr_t spare_hook1;[/align]
[align=left] uintptr_t spare_hook2;[/align]
[align=left] uintptr_t spare_hook3;[/align]
[align=left] uintptr_t spare_hook4;[/align]
[align=left] uintptr_t spare_hook5;[/align]
[align=left] uintptr_t spare_hook6;[/align]
[align=left] uintptr_t spare_hook7;[/align]
[align=left]}; [/align]
4.2结构体作用:

这个结构体变量名为为ngx_http_<module_name>_module。

它包含模块的主要内容和指令的执行部分,也有一些回调函数(退出线程,推退出进程等等)。这些函数的定义是把数据处理关联到特定模块的关键。

在进程/线程退出的时候,模块可以添加一些回调函数来运行,但大多数模块用不到。
4.3实例:

ngx_module_t ngx_http_hello_world_module={
[align=left] NGX_MODULE_V1,[/align]
[align=left] &ngx_http_hello_world_module_ctx,[/align]
[align=left] ngx_http_hello_world_commands,[/align]
[align=left] NGX_HTTP_MODULE,[/align]
[align=left] NULL,[/align]

[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NGX_MODULE_V1_PADDING[/align]
[align=left]};[/align]
二.处理模块、过滤模块和负载均衡模块

2.1. 剖析处理模块(非代理)
处理模块一般做四样东西:获得位置配置结构体产生合适的回复发送HTTP头部发送HTTP主体。它只有一个变量--请求结构体。这个结构体有很多关于客户端请求的有用信息,比如请求方法(request
method),URI和请求头部。我们会一步一步分析整个过程。
2.1.1获得位置配置结构体
这部分很简单,所有你需要做的事根据当前的请求结构体和模块定义,调用ngx_http_get_module_loc_conf,获得当前的配置结构体。
实例:

[align=left]static char *ngx_http_hello_world (ngx_conf_t *cf,ngx_command_t *cmd, void *conf)[/align]
[align=left]{[/align]
[align=left] ngx_http_core_loc_conf_t *clcf;[/align]
[align=left] [/align]
[align=left] clcf=ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);[/align]
[align=left] clcf-> handler=ngx_http_hello_world_handler;[/align]
[align=left] return NGX_CONF_OK;[/align]
[align=left]}[/align]
2.1.2产生回复
1.结构体ngx_http_request_t
[align=left]struct ngx_http_request_s {[/align]
uint32_t signature; /*
"HTTP" */

[align=left] ngx_connection_t * connection;[/align]

void
** ctx;
void
** main_conf;
void
** srv_conf;
void
** loc_conf;

[align=left] ngx_http_event_handler_pt read_event_handler;[/align]
[align=left] ngx_http_event_handler_pt write_event_handler;[/align]

[align=left]#if (NGX_HTTP_CACHE)[/align]
[align=left] ngx_http_cache_t * cache;[/align]
[align=left]#endif[/align]

[align=left] ngx_http_upstream_t * upstream;[/align]
[align=left] ngx_array_t * upstream_states;[/align]
[align=left] /* of ngx_http_upstream_state_t */[/align]

[align=left] ngx_pool_t *pool;[/align]
[align=left] ngx_buf_t * header_in;[/align]

[align=left] ngx_http_headers_in_t headers_in;[/align]
[align=left] ngx_http_headers_out_t headers_out;[/align]

[align=left] ngx_http_request_body_t * request_body;[/align]

[align=left] time_t lingering_time;[/align]
[align=left] time_t start_sec;[/align]
[align=left] ngx_msec_t start_msec;[/align]

[align=left] ngx_uint_t method;[/align]
[align=left] ngx_uint_t http_version;[/align]

[align=left] ngx_str_t request_line;[/align]
[align=left] ngx_str_t uri;[/align]
[align=left] ngx_str_t args;[/align]
[align=left] ngx_str_t exten;[/align]
[align=left] ngx_str_t unparsed_uri;[/align]

[align=left] ngx_str_t method_name;[/align]
[align=left] ngx_str_t http_protocol;[/align]

[align=left] ngx_chain_t * out;[/align]
[align=left] ngx_http_request_t * main;[/align]
[align=left] ngx_http_request_t * parent;[/align]
[align=left] ngx_http_postponed_request_t * postponed;[/align]
[align=left] ngx_http_post_subrequest_t * post_subrequest;[/align]
[align=left] ngx_http_posted_request_t * posted_requests;[/align]

[align=left] ngx_http_virtual_names_t * virtual_names;[/align]

[align=left] ngx_int_t phase_handler;[/align]
[align=left] ngx_http_handler_pt content_handler;[/align]
[align=left] ngx_uint_t access_code;[/align]

[align=left] ngx_http_variable_value_t * variables;[/align]

[align=left]#if (NGX_PCRE)[/align]
[align=left] ngx_uint_t ncaptures;[/align]
int
* captures;
[align=left] u_char * captures_data;[/align]
[align=left]#endif[/align]

[align=left] size_t limit_rate;[/align]

[align=left] /* used to learn the Apache compatible response length without a header */[/align]
[align=left] size_t header_size;[/align]

[align=left] off_t request_length;[/align]

[align=left] ngx_uint_t err_status;[/align]

[align=left] ngx_http_connection_t * http_connection;[/align]

[align=left] ngx_http_log_handler_pt log_handler;[/align]

[align=left] ngx_http_cleanup_t * cleanup;[/align]

[align=left] unsigned subrequests:8;[/align]
[align=left] unsigned count:8;[/align]
[align=left] unsigned blocked:8;[/align]

[align=left] unsigned aio:1;[/align]

[align=left] unsigned http_state:4;[/align]

[align=left] /* URI with "/." and on Win32 with "//" */[/align]
[align=left] unsigned complex_uri:1;[/align]

[align=left] /* URI with "%" */[/align]
[align=left] unsigned quoted_uri:1;[/align]

[align=left] /* URI with "+" */[/align]
[align=left] unsigned plus_in_uri:1;[/align]

[align=left] /* URI with " " */[/align]
[align=left] unsigned space_in_uri:1;[/align]

[align=left] unsigned invalid_header:1;[/align]

[align=left] unsigned add_uri_to_alias:1;[/align]
[align=left] unsigned valid_location:1;[/align]
[align=left] unsigned valid_unparsed_uri:1;[/align]
[align=left] unsigned uri_changed:1;[/align]
[align=left] unsigned uri_changes:4;[/align]

[align=left] unsigned request_body_in_single_buf:1;[/align]
[align=left] unsigned request_body_in_file_only:1;[/align]
[align=left] unsigned request_body_in_persistent_file:1;[/align]
[align=left] unsigned request_body_in_clean_file:1;[/align]
[align=left] unsigned request_body_file_group_access:1;[/align]
[align=left] unsigned request_body_file_log_level:3;[/align]

[align=left] unsigned subrequest_in_memory:1;[/align]
[align=left] unsigned waited:1;[/align]

[align=left]#if (NGX_HTTP_CACHE)[/align]
[align=left] unsigned cached:1;[/align]
[align=left]#endif[/align]

[align=left]#if (NGX_HTTP_GZIP)[/align]
[align=left] unsigned gzip_tested:1;[/align]
[align=left] unsigned gzip_ok:1;[/align]
[align=left] unsigned gzip_vary:1;[/align]
[align=left]#endif[/align]

[align=left] unsigned proxy:1;[/align]
[align=left] unsigned bypass_cache:1;[/align]
[align=left] unsigned no_cache:1;[/align]

[align=left] /*[/align]
[align=left] * instead of using the request context data in[/align]
[align=left] * ngx_http_limit_conn_module and ngx_http_limit_req_module[/align]
[align=left] * we use the single bits in the request structure[/align]
[align=left] */[/align]
[align=left] unsigned limit_conn_set:1;[/align]
[align=left] unsigned limit_req_set:1;[/align]

[align=left]#if 0[/align]
unsigned
cacheable:1;
[align=left]#endif[/align]

[align=left] unsigned pipeline:1;[/align]
[align=left] unsigned plain_http:1;[/align]
[align=left] unsigned chunked:1;[/align]
[align=left] unsigned header_only:1;[/align]
[align=left] unsigned keepalive:1;[/align]
[align=left] unsigned lingering_close:1;[/align]
[align=left] unsigned discard_body:1;[/align]
[align=left] unsigned internal:1;[/align]
[align=left] unsigned error_page:1;[/align]
[align=left] unsigned ignore_content_encoding:1;[/align]
[align=left] unsigned filter_finalize:1;[/align]
[align=left] unsigned post_action:1;[/align]
[align=left] unsigned request_complete:1;[/align]
[align=left] unsigned request_output:1;[/align]
[align=left] unsigned header_sent:1;[/align]
[align=left] unsigned expect_tested:1;[/align]
[align=left] unsigned root_tested:1;[/align]
[align=left] unsigned done:1;[/align]
[align=left] unsigned logged:1;[/align]

[align=left] unsigned buffered:4;[/align]

[align=left] unsigned main_filter_need_in_memory:1;[/align]
[align=left] unsigned filter_need_in_memory:1;[/align]
[align=left] unsigned filter_need_temporary:1;[/align]
[align=left] unsigned allow_ranges:1;[/align]

[align=left]#if (NGX_STAT_STUB)[/align]
[align=left] unsigned stat_reading:1;[/align]
[align=left] unsigned stat_writing:1;[/align]
[align=left]#endif[/align]

[align=left] /* used to parse HTTP headers */[/align]

[align=left] ngx_uint_t state;[/align]

[align=left] ngx_uint_t header_hash;[/align]
[align=left] ngx_uint_t lowcase_index;[/align]
[align=left] u_char lowcase_header[NGX_HTTP_LC_HEADER_LEN];[/align]

[align=left] u_char * header_name_start;[/align]
[align=left] u_char * header_name_end;[/align]
[align=left] u_char * header_start;[/align]
[align=left] u_char * header_end;[/align]

[align=left] /*[/align]
[align=left] * a memory that can be reused after parsing a request line[/align]
[align=left] * via ngx_http_ephemeral_t[/align]
[align=left] */[/align]

[align=left] u_char * uri_start;[/align]
[align=left] u_char * uri_end;[/align]
[align=left] u_char * uri_ext;[/align]
[align=left] u_char * args_start;[/align]
[align=left] u_char * request_start;[/align]
[align=left] u_char * request_end;[/align]
[align=left] u_char * method_end;[/align]
[align=left] u_char * schema_start;[/align]
[align=left] u_char * schema_end;[/align]
[align=left] u_char * host_start;[/align]
[align=left] u_char * host_end;[/align]
[align=left] u_char * port_start;[/align]
[align=left] u_char * port_end;[/align]

[align=left] unsigned http_minor:16;[/align]
[align=left] unsigned http_major:16;[/align]
[align=left]};[/align]
结构体成员变量说明:

1)uri:请求路径,比如:“/query.cgi”

2) args:是在问号之后请求的参数,比如:“name=john”

3)headers_in有很多有用的东西,如cookie和浏览器信息
2.1.3发送HTTP头部

回复头部存在于被称为headers_out的结构体中。它包含在请求结构体中。这个处理函数生成头部变量,然后调用ngx_http_send_header(r)函数
ngx_http_headers_out_t结构体 加粗为有用部分
[align=left]typedef struct {[/align]
[align=left] ngx_list_t headers;[/align]

[align=left] ngx_uint_t status;[/align]
[align=left] ngx_str_t status_line;[/align]

[align=left] ngx_table_elt_t * server;[/align]
[align=left] ngx_table_elt_t * date;[/align]
[align=left] ngx_table_elt_t * content_length;[/align]
[align=left] ngx_table_elt_t *content_encoding;[/align]
[align=left] ngx_table_elt_t * location;[/align]
[align=left] ngx_table_elt_t * refresh;[/align]
[align=left] ngx_table_elt_t * last_modified;[/align]
[align=left] ngx_table_elt_t * content_range;[/align]
[align=left] ngx_table_elt_t * accept_ranges;[/align]
[align=left] ngx_table_elt_t * www_authenticate;[/align]
[align=left] ngx_table_elt_t * expires;[/align]
[align=left] ngx_table_elt_t * etag;[/align]

[align=left] ngx_str_t * override_charset;[/align]

[align=left] size_t content_type_len;[/align]
[align=left] ngx_str_t content_type;[/align]
[align=left] ngx_str_t charset;[/align]
[align=left] u_char * content_type_lowcase;[/align]
[align=left] ngx_uint_t content_type_hash;[/align]

[align=left] ngx_array_t cache_control;[/align]

[align=left] off_t content_length_n;[/align]
[align=left] time_t date_time;[/align]
[align=left] time_t last_modified_time;[/align]
[align=left]} ngx_http_headers_out_t;[/align]

举个例子,如果一个模块把Content-Type需要设定为“image/gif”,Content-Length为100,然后返回200 OK的回复,代码将是这样的:

[align=left]r->headers_out.status = NGX_HTTP_OK;[/align]
[align=left]r->headers_out.content_length_n = 100;[/align]
[align=left]r->headers_out.content_type.len = sizeof("image/gif") - 1;[/align]
[align=left]r->headers_out.content_type.data = (u_char *) "image/gif";[/align]
[align=left]ngx_http_send_header(r);[/align]
上面的设定方式针对大多数参数都是有效的。但一些头部的变量设定要比上面的例子要麻烦;比如,content_encoding含有类型(ngx_table_elt_t*),这时模块必须为它分配内存。可以用一个叫ngx_list_push的函数来做。它需要传入一个ngx_list_t变量(与数组类似),然后返回一个list中的新成员(类型是ngx_table_elt_t)。下面的代码把Content-Encoding设定为“deflate”,然后把头部发出。

[align=left]r->headers_out.content_encoding = ngx_list_push(&r-[/align]
[align=left]>headers_out.headers);[/align]
[align=left]if (r->headers_out.content_encoding == NULL) {[/align]
[align=left]return NGX_ERROR;[/align]
[align=left]}[/align]

[align=left]r->headers_out.content_encoding->hash = 1;[/align]
[align=left]r->headers_out.content_encoding->key.len = sizeof("Content-[/align]
[align=left]Encoding") - 1;[/align]
[align=left]r->headers_out.content_encoding->key.data = (u_char *) "Content-[/align]
[align=left]Encoding";[/align]
[align=left]r->headers_out.content_encoding->value.len = sizeof("deflate") -[/align]
[align=left]1;[/align]
[align=left]r->headers_out.content_encoding->value.data = (u_char *)[/align]
[align=left]"deflate";[/align]
[align=left]ngx_http_send_header(r);[/align]

当头部有多个值的时候,这个机制会经常用到;它(理论上讲)使得过滤模块添加、删除某个值而保留其他值的时候更加容易,在操纵字符串的时候,不需要把字符串重新排序。
2.1.4 发送HTTP主体

现在模块已经产生了一个回复,把它放到内存中。需要为回复分配一块特别的buffer,并把这个buffer连接到一个链表,然后调用“send body”函数发送。
这些链表有什么用?在Nginx中,处理模块和过滤模块在处理完成后产生的回复包含在缓冲中,每次产生一个buffer;每个链表成员保存指向下一个成员的指针,如果是最后的buffer,就置为NULL。这里我们简单地假定只有一个buffer成员。
首先,模块声明一块buffer和一条链表:
[align=left]ngx_buf_t *b;[/align]
[align=left]ngx_chain_t out;[/align]
第二步是分配缓冲,然后指向我们的回复数据:
[align=left]b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));[/align]
[align=left]if (b == NULL) {[/align]
[align=left]ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,[/align]
[align=left]"Failed to allocate response buffer.");[/align]
[align=left]return NGX_HTTP_INTERNAL_SERVER_ERROR;[/align]
[align=left]}[/align]
[align=left]b->pos = some_bytes; /* first position in memory of the data */[/align]
[align=left]b->last = some_bytes + some_bytes_length; /* last position */[/align]

[align=left]b->memory = 1; /* content is in read-only memory */[/align]
[align=left]/* (i.e., filters should copy it rather than rewrite in place) */[/align]
[align=left]b->last_buf = 1; /* there will be no more buffers in the request[/align]
[align=left]*/[/align]

第三步现在模块buffer添加到了链表上:
[align=left]out.buf = b;[/align]
[align=left]out.next = NULL;[/align]
第四步,,我们把主体发送出去,返回值是output_filter函数对整个链表的返回状态。
[align=left]return ngx_http_output_filter(r, &out);[/align]
完整版代码

[align=left]static ngx_int_t ngx_http_hello_world_handler( ngx_http_request_t *r)[/align]
[align=left]{[/align]
[align=left] ngx_buf_t *b;[/align]
[align=left] ngx_chain_t out;[/align]

[align=left] r-> headers_out.content_type .len = sizeof("text/plain" )-1;[/align]
[align=left] r-> headers_out.content_type .data=( u_char *) "text/plain" ;[/align]

[align=left] b=ngx_pcalloc(r-> pool,sizeof (ngx_buf_t));[/align]

[align=left] out. buf=b;[/align]
[align=left] out. next=NULL;[/align]

[align=left] b-> pos=ngx_hello_world;[/align]
[align=left] b-> last=ngx_hello_world+sizeof(ngx_hello_world);[/align]
[align=left] b-> memory=1;[/align]
[align=left] b-> last_buf=1;[/align]
[align=left] [/align]
[align=left] r-> headers_out.status =NGX_HTTP_OK;[/align]
[align=left] r-> headers_out.content_length_n =sizeof(ngx_hello_world);[/align]
[align=left] ngx_http_send_header(r);[/align]
[align=left] [/align]
[align=left] return ngx_http_output_filter(r,&out);[/align]
[align=left]}[/align]
缓冲链表是一个典型的Nginx IO模型,你必须清楚它们是如何工作的
问题:为什么会有变量last_buf,什么时候我们才能说这条链表结束了,并把next设为NULL?
回答:链表可能不完全的,比如,有多个buffer的时候,但是不是所有的buffer都在这个请求或者回复中。所以一些buffer是链表的结尾,而不是请求的结尾。这意味着模块判断是否是请求的结尾,并设置相应的值。

2.1.5最后附上hello_world模块的完整代码

[align=left]#include <ngx_config.h>[/align]
[align=left]#include <ngx_core.h>[/align]
[align=left]#include <ngx_http.h>[/align]
[align=left]#include <ngx_buf.h>[/align]
static char *ngx_http_hello_world(ngx_conf_t *cf
, ngx_command_t *cmd,void *conf);
[align=left]static ngx_command_t ngx_http_hello_world_commands []={[/align]
[align=left] {[/align]
[align=left] ngx_string( "hello_world"),[/align]
[align=left] NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,[/align]
[align=left] ngx_http_hello_world,[/align]
[align=left] 0,[/align]
[align=left] 0,[/align]
[align=left] NULL[/align]
[align=left] },[/align]
[align=left] ngx_null_command[/align]
[align=left]};[/align]
static u_char ngx_hello_world[]="hello
world";
[align=left]static ngx_http_module_t ngx_http_hello_world_module_ctx={[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL[/align]
[align=left]};[/align]
ngx_module_t ngx_http_hello_world_module={
//模块
[align=left] NGX_MODULE_V1,[/align]
[align=left] &ngx_http_hello_world_module_ctx,[/align]
[align=left] ngx_http_hello_world_commands,[/align]
[align=left] NGX_HTTP_MODULE,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NULL,[/align]
[align=left] NGX_MODULE_V1_PADDING[/align]
[align=left]};[/align]
[align=left]static ngx_int_t ngx_http_hello_world_handler( ngx_http_request_t *r)[/align]
[align=left]{[/align]
[align=left] ngx_buf_t *b;[/align]
[align=left] ngx_chain_t out;[/align]

[align=left] r-> headers_out.content_type .len = sizeof("text/plain" )-1;[/align]
[align=left] r-> headers_out.content_type .data=( u_char *) "text/plain" ;[/align]

[align=left] b=ngx_pcalloc(r-> pool,sizeof (ngx_buf_t));[/align]

[align=left] out. buf=b;[/align]
[align=left] out. next=NULL;[/align]

b-> pos=ngx_hello_world;
//自定义变量

[align=left] b-> last=ngx_hello_world+sizeof(ngx_hello_world);[/align]
[align=left] b-> memory=1;[/align]
[align=left] b-> last_buf=1;[/align]
[align=left] [/align]
[align=left] r-> headers_out.status =NGX_HTTP_OK;[/align]
[align=left] r-> headers_out.content_length_n =sizeof(ngx_hello_world);[/align]
[align=left] ngx_http_send_header(r);[/align]
[align=left] [/align]
[align=left] return ngx_http_output_filter(r,&out);[/align]
[align=left]}[/align]
[align=left]static char *ngx_http_hello_world (ngx_conf_t *cf,ngx_command_t *cmd, void *conf)[/align]
[align=left]{[/align]
[align=left] ngx_http_core_loc_conf_t *clcf;[/align]
[align=left] [/align]
[align=left] clcf=ngx_http_conf_get_module_loc_conf(cf,ngx_http_core_module);[/align]
[align=left] clcf-> handler=ngx_http_hello_world_handler;[/align]
[align=left] return NGX_CONF_OK;[/align]
[align=left]}[/align]
2.2剖析配置文件config
2.2.1.内容

ngx_addon_name=ngx_http_hello_world_module
HTTP_MODULES="$HTTP_MODULES ngx_http_hello_world_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dirx_http_hello_world_module.c"
CORE_LIBS="$CORE_LIBS -lpcre"
2.2.2.作用

通过NGX_ADDON_SRCS找到源码文件,
通过HTTP_MODULES找到模块,就可以找到ctx和command(ngx_init_cycle函数中进行),并可以对HTTP请求进行处理。
2.2.3.对应关系



三、综上所述,如何安装HelloWorld模块呢?
简要概括如下:除了第四步以外,其余都参考/article/1653059.html 中相关内容

1.下载Nginx最新代码
2.建立模块目录与代码
3.创建Makefile文件
4.直接$make && make install就可以安装带有HelloWorld模块的Nginx了
5.修改nginx.conf的内容
5.启动Nginx,在命令行输入$ curl http://localhost/hello输出hello,world就表示成功。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: