《深入理解ngx》—— 模块基础
1. configure 添加模块
1.1 添加一个 http 模块
在./src/test下创建config
内容如下
# 定义模块名称
1 ngx_addon_name=ngx_http_test_module
# 向http类添加 新模块
2 HTTP_MODULES="$HTTP_MODULES ngx_http_test_module"
# 添加源文件
3 NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_test_module.c"
如果添加过滤模块则为
2 HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES ngx_http_test_module"
1.2 原理分析
1.2.1 加载config配置
--add-module就是 设置 NGX_ADDONS,
并且一次只能设置一个,所以要添加多个模块,需要使用多个 --add-module
343 --add-module=*) NGX_ADDONS="$NGX_ADDONS $value" ;;
当 NGX_ADDONS 不为空,则加载相关 config ,以设置变量
1197 if test -n "$NGX_ADDONS"; then
1198
1199 echo configuring additional modules
1200
1201 for ngx_addon_dir in $NGX_ADDONS
1202 do
1203 echo "adding module in $ngx_addon_dir"
1204
1205 ngx_module_type=
1206 ngx_module_name=
1207 ngx_module_incs=
1208 ngx_module_deps=
1209 ngx_module_srcs=
1210 ngx_module_libs=
1211 ngx_module_order=
1212 ngx_module_link=ADDON
1213
1214 if test -f $ngx_addon_dir/config; then
1215 . $ngx_addon_dir/config
1216
1217 echo " + $ngx_addon_name was configured"
1218
1219 else
1220 echo "$0: error: no $ngx_addon_dir/config was found"
1221 exit 1
1222 fi
1223 done
1224 fi
1.2.2 生成ngx_modules.c
1286 modules="$CORE_MODULES $EVENT_MODULES"
1295 if [ $HTTP = YES ]; then
1296 modules="$modules $HTTP_MODULES $HTTP_FILTER_MODULES \
1297 $HTTP_AUX_FILTER_MODULES $HTTP_INIT_FILTER_MODULES"
1298
1299 NGX_ADDON_DEPS="$NGX_ADDON_DEPS \$(HTTP_DEPS)"
1300 fi
1301
1383 cat << END > $NGX_MODULES_C
1384
1385 #include <ngx_config.h>
1386 #include <ngx_core.h>
1387
1388 $NGX_PRAGMA
1389
1390 END
1391
1392 for mod in $modules
1393 do
1394 echo "extern ngx_module_t $mod;" >> $NGX_MODULES_C
1395 done
1396
1397 echo >> $NGX_MODULES_C
1398 echo 'ngx_module_t *ngx_modules[] = {' >> $NGX_MODULES_C
1399
1400 for mod in $modules
1401 do
1402 echo " &$mod," >> $NGX_MODULES_C
1403 done
1404
1405 cat << END >> $NGX_MODULES_C
1406 NULL
1407 };
1408
1409 END
1410
1411 echo 'char *ngx_module_names[] = {' >> $NGX_MODULES_C
1412
1413 for mod in $modules
1414 do
1415 echo " \"$mod\"," >> $NGX_MODULES_C
1416 done
1417
1418 cat << END >> $NGX_MODULES_C
1419 NULL
1420 };
1421
1422 END
1.2.4 生成makefile
生成编译make
407 # the addons sources
408
409 if test -n "$NGX_ADDON_SRCS"; then
410
411 ngx_cc="\$(CC) $ngx_compile_opt \$(CFLAGS) $ngx_use_pch \$(ALL_INCS)"
412
413 for ngx_src in $NGX_ADDON_SRCS
414 do
415 ngx_obj="addon/`basename \`dirname $ngx_src\``"
416
417 ngx_obj=`echo $ngx_obj/\`basename $ngx_src\` \
418 | sed -e "s/\//$ngx_regex_dirsep/g"`
419
420 ngx_obj=`echo $ngx_obj \
421 | sed -e "s#^\(.*\.\)cpp\\$#$ngx_objs_dir\1$ngx_objext#g" \
422 -e "s#^\(.*\.\)cc\\$#$ngx_objs_dir\1$ngx_objext#g" \
423 -e "s#^\(.*\.\)c\\$#$ngx_objs_dir\1$ngx_objext#g" \
424 -e "s#^\(.*\.\)S\\$#$ngx_objs_dir\1$ngx_objext#g"`
425
426 ngx_src=`echo $ngx_src | sed -e "s/\//$ngx_regex_dirsep/g"`
427
428 cat << END >> $NGX_MAKEFILE
429
430 $ngx_obj: \$(ADDON_DEPS)$ngx_cont$ngx_src
431 $ngx_cc$ngx_tab$ngx_objout$ngx_obj$ngx_tab$ngx_src$NGX_AUX
432
433 END
434 done
435
436 fi
1.2.5 生成链接
225 cat << END >> $NGX_MAKEFILE
226
227 build: binary modules manpage
228
229 binary: $NGX_OBJS${ngx_dirsep}nginx$ngx_binext
230
231 $NGX_OBJS${ngx_dirsep}nginx$ngx_binext: $ngx_deps$ngx_spacer
232 \$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_binext$n gx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link
233 $ngx_rcc
234 $ngx_long_end
235
236 modules:
237 END
2. 模块基础
2.0 ngx_module
222 struct ngx_module_s {
223 ngx_uint_t ctx_index; // index in similar modules
224 ngx_uint_t index; // index in ngx_module array
225
226 char *name;
227
228 ngx_uint_t spare0;
229 ngx_uint_t spare1;
230
231 ngx_uint_t version;
232 const char *signature;
233
234 void *ctx; // to fork different types of module
235 ngx_command_t *commands; // commands of module
236 ngx_uint_t type; // NGX_HTTP_MODULE | NGX_CORE_MODULE | NGX_EVENT_MODULE | NGX_MAIL_MODULE
237
238 ngx_int_t (*init_master)(ngx_log_t *log);
239
240 ngx_int_t (*init_module)(ngx_cycle_t *cycle);
241
242 ngx_int_t (*init_process)(ngx_cycle_t *cycle);
243 ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
244 void (*exit_thread)(ngx_cycle_t *cycle);
245 void (*exit_process)(ngx_cycle_t *cycle);
246
247 void (*exit_master)(ngx_cycle_t *cycle);
248
249 uintptr_t spare_hook0;
250 uintptr_t spare_hook1;
251 uintptr_t spare_hook2;
252 uintptr_t spare_hook3;
253 uintptr_t spare_hook4;
254 uintptr_t spare_hook5;
255 uintptr_t spare_hook6;
256 uintptr_t spare_hook7;
257 };
比较重要的属性是 ctx 和 commands
ctx用于派生具体的模块,
commands 定义模块支持的指令
2.1 ngx_http_module_t
定义http模块时, ngx_module_t->ctx 为 ngx_http_module_t
24 typedef struct {
25 ngx_int_t (*preconfiguration)(ngx_conf_t *cf);
26 ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
27
28 void *(*create_main_conf)(ngx_conf_t *cf);
29 char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
30
31 void *(*create_srv_conf)(ngx_conf_t *cf);
32 char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
33
34 void *(*create_loc_conf)(ngx_conf_t *cf);
35 char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
36 } ngx_http_module_t;
2.2 struct ngx_commands_s
77 struct ngx_command_s {
78 ngx_str_t name;
79 ngx_uint_t type; // set the area of command appears
80 char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
81 ngx_uint_t conf; // offset of cfg context
82 ngx_uint_t offset; // offset of user cfg struct
83 void *post; // the processing method after reading command
84 };
2.3 简单的http模块
以access模块为例
68 static ngx_command_t ngx_http_access_commands[] = {
69
70 { ngx_string("allow"),
71 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
72 |NGX_CONF_TAKE1,
73 ngx_http_access_rule,
/*
由于conf为loc级别,所以处理请求时,使用如下获得配置
133 alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module);
并且 ngx_http_access_rule ,的conf参数,被传入 loc级别配置
295 static char *
296 ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
297 {
298 ngx_http_access_loc_conf_t *alcf = conf;
*/
74 NGX_HTTP_LOC_CONF_OFFSET,
75 0,
76 NULL },
77
86 ngx_null_command
87 };
定义http模块上下文
91 static ngx_http_module_t ngx_http_access_module_ctx = {
92 NULL, /* preconfiguration */
/*
所有配置解析完成后调用 ngx_http_access_init
*/
93 ngx_http_access_init, /* postconfiguration */
94
95 NULL, /* create main configuration */
96 NULL, /* init main configuration */
97
98 NULL, /* create server configuration */
99 NULL, /* merge server configuration */
100
101 ngx_http_access_create_loc_conf, /* create location configuration */
102 ngx_http_access_merge_loc_conf /* merge location configuration */
103 };
绑定处理函数和处理阶段
447 static ngx_int_t
448 ngx_http_access_init(ngx_conf_t *cf)
449 {
450 ngx_http_handler_pt *h;
451 ngx_http_core_main_conf_t *cmcf;
452
453 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
454
455 h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
456 if (h == NULL) {
457 return NGX_ERROR;
458 }
459
460 *h = ngx_http_access_handler;
461
462 return NGX_OK;
463 }
处理请求时,先获得配置,根据配置处理请求
122 static ngx_int_t
123 ngx_http_access_handler(ngx_http_request_t *r)
124 {
126 ngx_http_access_loc_conf_t *alcf;
133 alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module);
模块返回给ngx,通常表示如下
NGX_OK : 本阶段处理通过,交给下个阶段模块处理
NGX_DECLINED : 本模块通过,交给本阶段下个模块处理。若本阶段所有模块都处理完了,交给下个阶段模块处理
还可以返回响应码,直接响应,不再处理
NGX_HTTP_OK
NGX_HTTP_FORBIDDEN
NGX_HTTP_NOT_FOUND
ngx对返回值的处理,需要具体分析对应的 checker 函数。
2.4 请求上下文
每个请求都不同,模块可以为请求建立一个请求会话——请求上下文。
请求上下文是挂载在 ngx_http_request_t->ctx上的,
371 struct ngx_http_request_s {
376 void **ctx; // request ctx
使用如下宏设置和获得
75 #define ngx_http_get_module_ctx(r, module) (r)->ctx[module.ctx_index]
76 #define ngx_http_set_ctx(r, c, module) r->ctx[module.ctx_index] = c;
示例,首次获得请求时,检查ctx是否设置,若未设置,则使用 r->pool分配请求上下文,后设置
115 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_addition_ctx_t));
116 if (ctx == NULL) {
117 return NGX_ERROR;
118 }
119
120 ngx_http_set_ctx(r, ctx, ngx_http_addition_filter_module);
2.4 总结
通过模块机制,可以:
1)定义配置指令
2)定义配置上下文,根据指令解析,对配置上下文赋值
3)挂载请求处理函数
4)处理请求时,根据 模块idx,获得模块的 配置上下文,根据配置上下文解析配置。
5)分配请求上下文,维护生命周期为单个请求的数据,以处理请求。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律