美文网首页
nginx 源代码分析 (五)

nginx 源代码分析 (五)

作者: RonZheng2010 | 来源:发表于2021-06-20 11:13 被阅读0次

1. phases

nginx将数据处理过程划分为几个阶段(phase)。

2. ngx_http_phase_handler_pt 与 ngx_http_handler_pt

每个阶段可以挂接若干处理函数,ngx_http_core_run_phase() 按阶段调用这些函数。不管是Nginx自身的nginx_module,还是使用者的ngx_module,都可以挂接自己的处理函数。这个处理函数的原型定义是ngx_http_handler_pt。

typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);

挂接的位置是ngx_http_core_main_conf_t.phases[]数组,保存ngx_http_phase_t结构。Ngx_http_phase_t.handlers[]是一个ngx_http_phase_t数组,每个phase一个元素。Ngx_http_phase_t的成员handlers也是一个数组,该阶段的处理函数ngx_http_handler_pt都注册在这里。

实际上处理http请求时,并不是使用ngx_http_core_main_conf_t.phases[],而是ngx_http_core_main_conf_t.phase_engine。Ngx_http_phase_engint_t.handlers是一个ngx_http_phase_handler_t。

ngx_http_handler_pt只是ngx_module挂接的处理函数。Ngx_http_phase_handler_pt则是每个phase指定的校验函数。如果校验通过,校验函数才会调用处理函数。

typedef ngx_int_t (*ngx_http_phase_handler_pt)(ngx_http_request_t *r, 
ngx_http_phase_handler_t *ph);

ngx_http_phase_handler_t包括了校验函数和处理函数。

  • 成员checker是phase校验函数。
  • 成员handler是处理函数。
  • 成员next指定每个ngx_http_phase_handler_t实例在http请求处理过程中的“下一站”。

3. ngx_http_init_phases()

ngx_http_init_phases() 初始化ngx_http_core_main_conf.phases[]中的处理函数数组。

4. ngx_http_module_t::postconfiguration()

在ngx_http_module_t::postconfiguration()中,nginx模块向ngx_http_core_main_conf_t.phases中,加入自己的的处理函数。对于ngx_http_auth_basic_module模块,就是ngx_http_auth_basic_init()。

  • 调用ngx_array_push(),向NGX_HTTP_ACCESS_PHASE阶段,加入处理函数ngx_http_auth_basic_handler。

5. ngx_http_init_phase_handlers()

ngx_http_init_phase_handlers()初始化ngx_core_main_conf_t.phase_engine.handlers[]。

  • 遍历ngx_http_core_main_conf_t.phases[],计算其中的处理函数数量。
  • 调用ngx_pcalloc()分配对应的ngx_http_phase_handler_t数组,也就是ngx_core_main_conf_t.phase_engine.handlers[]。
  • 遍历ngx_http_core_main_conf_t.phases[]数组,将其中的处理函数,一一复制到ngx_http_core_main_conf_t.phase_engine.handlers[]中,同时补充相应phase的校验函数。同时每个ngx_http_phase_handler_t的下一站,也就是它的成员next。

这个过程的大致情形如下图。

  • 图左边的每个阶段为一个实线框, 每个阶段指定一个校验函数ngx_http_phase_handler_pt,一组处理函数ngx_http_handler_t。
  • 图右边,所有的ngx_http_phase_handler_t实际上是保存在同一个数组中。虚线框是为了使复制的关系看得更清楚。

6. ngx_http_block()

在ngx_http_block()中调用以上函数。

如下是缺省情况(不定制或拓展nginx的功能)下,最后ngx_http_core_main_conf_t.phase_engine.handlers[]的布局。

7. ngx_http_core_run_phases()

ngx_http_core_run_phases() 在一个循环中访问ngx_http_core_main_conf_t.phase_engine.handlers[],调用其中的校验函数和处理函数。

访问位置由ngx_http_request_t.phase_handler指定,这个值一开始为0,后来校验函数会改变它,所以ngx_http_core_run_phase()会在ngx_http_core_main_conf_t.phase_engine.handlers[]中跳转。

校验函数和处理函数的一个例子是ngx_http_core_access_phase()和ngx_http_auth_basic_handler()。

7.1 ngx_http_phase_handler_t::handler()

在ngx_http_auth_basic_handler()中,

  • 调用ngx_http_auth_basic_user(),得到用户数据。
  • 调用ngx_open_file(),打开用户数据文件。
  • 在一个循环中调用ngx_read_file(),读取用户数据文件的记录。将请求中的用户信息与记录比较,看是否匹配。

7.2 ngx_http_phase_handler_t::checker()

在ngx_http_core_access_phase()中,

  • 调用当前ngx_http_phase_handler_t实例的handler函数,这里是ngx_http_auth_basic_handler()。

  • 根据handler函数的返回结果跳转,一般有三种情况。

    • 一是handler函数的结果不能确定怎么处理请求,所以ngx_http_request_t.phase_handler递增1。这样ngx_http_core_run_phases()的下一次循环,将跳转到数组phase_engine.handlers[]的下一个元素去执行。
    • 二是handler函数的结果确定本阶段的任务已经完成,所以请求ngx_http_request_t.phase_handler设置为当前ngx_http_phase_handler_t.next的值。这样ngx_http_core_run_phases()的下一次循环,将跳到该值指向的位置。这个值在ngx_http_init_phase_handlers()确定。
    • 三是handler函数的结果确定所有任务已经结束(比如请求失败),所以返回NGX_OK。这时ngx_http_core_run_phases()会终止循环。

相关文章

网友评论

      本文标题:nginx 源代码分析 (五)

      本文链接:https://www.haomeiwen.com/subject/sqiryltx.html