《深入理解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)分配请求上下文,维护生命周期为单个请求的数据,以处理请求。

posted on 2022-05-17 21:51  开心种树  阅读(378)  评论(0编辑  收藏  举报