[nginx源码分析]nginx handler 模块解析
2015-05-07 15:41
821 查看
nginx除去配置解析和初始化,就是根据请求根据状态机一步步执行流程,那么本节主要讲解首先是整个nginx对于一个客户端请求大致请求流程,其次是根据这个流程来写自己的handler模块。
nginx接受到一个client请求调用流程:
1 ngx_event_accept主要是accept连接生成并初始化connection
2 ngx_http_init_connection 函数主要设置rev和wev事件回调函数
3 ngx_http_init_request 初始化request
4 ngx_http_process_request_line 处理请求line
5 ngx_http_process_request_headers处理请求header
6 ngx_http_process_request处理请求
7 ngx_http_handler
8 ngx_http_core_run_phases
函数详细:
然后遍历整个请求状态机的11个阶段
一般我们写handler模块都是在NGX_HTTP_CONTENT_PHASE阶段,也就是说我们直接把函数挂在在NGX_HTTP_CONTENT_PHASE就ok
我们自己写一个nginx handler模块
config文件
ngx_http_read_module.c文件
nginx.conf配置文件如下
此时content handler主要功能是当用户访问/"leek"页面的时候,把文件(
nginx接受到一个client请求调用流程:
1 ngx_event_accept主要是accept连接生成并初始化connection
2 ngx_http_init_connection 函数主要设置rev和wev事件回调函数
3 ngx_http_init_request 初始化request
4 ngx_http_process_request_line 处理请求line
5 ngx_http_process_request_headers处理请求header
6 ngx_http_process_request处理请求
7 ngx_http_handler
8 ngx_http_core_run_phases
函数详细:
void ngx_http_core_run_phases(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_phase_handler_t *ph; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); ph = cmcf->phase_engine.handlers; while (ph[r->phase_handler].checker) { rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]); if (rc == NGX_OK) { return; } } }
然后遍历整个请求状态机的11个阶段
序号 | 阶段名称 | 阶段描述 |
0 | NGX_HTTP_POST_READ_PHASE | 请求头读取完成后的阶段 |
1 | NGX_HTTP_SERVER_REWRITE_PHASE | Server内请求地址重写阶段 |
2 | NGX_HTTP_FIND_CONFIG_PHASE | 配置查找阶段 |
3 | NGX_HTTP_REWRITE_PHASE | Location内请求地址重写阶段 |
4 | NGX_HTTP_POST_REWRITE_PHASE | 请求地址重写完成之后的阶段 |
5 | NGX_HTTP_PREACCESS_PHASE | 访问权限检查准备阶段 |
6 | NGX_HTTP_ACCESS_PHASE | 访问权限检查阶段 |
7 | NGX_HTTP_POST_ACCESS_PHASE | 访问权限检查完后之后的阶段 |
8 | NGX_HTTP_TRY_FILES_PHASE | 配置项try_files处理阶段 |
9 | NGX_HTTP_CONTENT_PHASE | 内容产生阶段 |
10 | NGX_HTTP_LOG_PHASE | 日志模块处理阶段 |
我们自己写一个nginx handler模块
config文件
//config 文件 ngx_addon_name=ngx_http_read_module HTTP_MODULES="$HTTP_MODULES ngx_http_read_module" NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_read_module.c"
ngx_http_read_module.c文件
/* * ===================================================================================== * * Filename: ngx_http_read_module.c * * Description: 这个一个读取一个leek文件返回给用户 * * Version: 1.0 * Created: 2013年10月10日 11时06分53秒 * Revision: none * Compiler: gcc * * Author: liyankun@baidu.com * Organization: * * ===================================================================================== */ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_http.h> #define TEST_STRING "This is a static module test string" typedef struct { ngx_str_t name; }ngx_http_test_loc_t; ngx_str_t g_buf; static void* ngx_http_leek_create_loc_conf(ngx_conf_t* cf); static char* ngx_http_leek_merge_loc_conf(ngx_conf_t* cf, void* parent, void* child); static ngx_int_t ngx_http_leekdump_handler(ngx_http_request_t *r); /* * 这个函数调用创建一个ngx_http_test_loc_t结构,进行初始化成员,然后把这个结构挂在到http->ctx->loc_conf所对应的索引下面 */ static void* ngx_http_leek_create_loc_conf(ngx_conf_t* cf) { ngx_http_test_loc_t* conf; conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_test_loc_t)); if (conf == NULL) { return NGX_CONF_ERROR; } conf->name.len = 0; conf->name.data = NULL; return conf; } /* 当读取配置文件并且解析到leek命令时候就会调用这个函数 */ char* setvalue(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_test_loc_t* temp; struct stat buf; ngx_conf_set_str_slot(cf, cmd, conf); temp = (ngx_http_test_loc_t*)conf; if (access((char*)temp->name.data, F_OK) == -1) { return NGX_CONF_ERROR; } if (stat((char*)temp->name.data, &buf)) { return NGX_CONF_ERROR; } g_buf.data = ngx_alloc(buf.st_size +1, cf->log); g_buf.data[buf.st_size] = 0; g_buf.len = buf.st_size+1; int fd = open((char*)temp->name.data, O_RDONLY); if (fd == -1) { return NGX_CONF_ERROR; } read(fd, g_buf.data, buf.st_size); return NGX_CONF_OK; } /* * ngx_string(leek) => 定义一个leek命令 * NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1 => 命令只能存在loc作用域中并且带一个参数(NGX_CONF_TAKE1) * 回调函数为setvalue * 保存在LOC数组中 * 设置name在结构体ngx_http_test_loc_t偏移 * */ static ngx_command_t ngx_http_read_commands [] = { { ngx_string("leek"), NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, setvalue, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_test_loc_t, name), NULL }, ngx_null_command }; /* * 挂在http回调函到阶段NGX_HTTP_CONTENT_PHASE */ static ngx_int_t ngx_http_read_init(ngx_conf_t *cf) { ngx_http_handler_pt *h; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); if (h == NULL) { return NGX_ERROR; } *h = ngx_http_leekdump_handler; return NGX_OK; } ngx_http_module_t ngx_http_read_module_ctx = { NULL, /* preconfiguration */ ngx_http_read_init, /* postconfiguration */ NULL, /* create main configuration */ NULL, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ ngx_http_leek_create_loc_conf, /* create location configuration */ ngx_http_leek_merge_loc_conf /* merge location configuration */ }; /* * 模块定义 */ ngx_module_t ngx_http_read_module = { NGX_MODULE_V1, &ngx_http_read_module_ctx, /* module context */ ngx_http_read_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 }; /* * 合并对多个loc进行合并,用户对用户没有设置的loc使用parent loc值 */ static char* ngx_http_leek_merge_loc_conf(ngx_conf_t* cf, void* parent, void* child) { ngx_http_test_loc_t* prev = parent; ngx_http_test_loc_t* conf = child; ngx_conf_merge_str_value(conf->name, prev->name, "Nginx"); return NGX_CONF_OK; } /* * 回调函数,当用户访问leek页面的时候,就会把命令leek 设置的参数值文件,发给客户端 * 关注两个函数 * 1 ngx_http_send_header * 2 ngx_http_output_filter */ static ngx_int_t ngx_http_leekdump_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_buf_t* b; ngx_chain_t out[3]; if (ngx_rstrncasecmp((u_char *)"/leek", r->uri.data, 5) != 0) { return NGX_DECLINED; } r->headers_out.content_type.len = sizeof("text/html") - 1; r->headers_out.content_type.data = (u_char*)"text/html"; b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); out[0].buf = b; out[0].next = NULL; b->pos = (u_char*)g_buf.data; b->last = b->pos + g_buf.len; b->memory = 1; b->last_buf = 1; r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = g_buf.len; 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[0]); } (END)
nginx.conf配置文件如下
worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root html; index index.html index.htm; } location /leek { leek "/root/hunter/nginx/ngx_gdb/conf/mime.types.default"; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
此时content handler主要功能是当用户访问/"leek"页面的时候,把文件(
/root/hunter/nginx/ngx_gdb/conf/mime.types.default)返回给用户浏览器客户端
相关文章推荐
- nginx源码分析--nginx模块解析
- Nginx源码解析- http模块分析
- Nginx源码分析 - HTTP模块篇 - ngx_http_wait_request_handler函数和HTTP Request解析过程
- Nginx源码解析- http模块分析
- Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 二
- Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 一
- FastDFS-Nginx扩展模块源码分析 -- mod_fastdfs原理解析
- nginx源码分析—模块及其初始化
- nginx源码分析(17)-模块分析(3)
- nginx源码分析-过滤模块
- nginx源码分析—core模块callback
- Nginx源码分析 - HTTP模块篇 - ngx_http_optimize_servers函数和TCP连接建立过程
- nginx源码分析——模块
- Nginx源码分析:核心模块剖析及常见问题
- Nginx源码分析-Epoll模块
- nginx源码分析——event模块
- nginx配置解析模块分析
- nginx源码分析—模块及其初始化
- nginx源码分析(15)-模块分析(1)
- Nginx源码分析 - 实战篇 - 编写一个挂载到阶段处理的模块