Nginx数据结构

作者:新溪-gordon <programfan.info#gmail.com>
时间:2014-07-29

高级模块说明

ngx_command_t:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

//
struct ngx_command_s {
  ngx_str_t   name;   // 配置项名, 无空格
  ngx_uint_t  type;   // 配置项type

  // 出现了name中制定的配置项后,将会调用set方法处理配置项参数。
  // 这个可以使用nginx预设的14个解析配置方法,也可以使用自定义的。
  char        *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);   // 指令操作

  // 因为有可能模块同时会有main,srv,loc三种配置结构体,指定这个配置项解析完后要放在哪个结构体内
  ngx_uint_t  conf;

  // 表示当前配置项在整个存储配置项的结构体中的偏移位置,可以使用offsetof(test_stru, b)来获取
  ngx_uint_t  offset;

  // 命令处理完后的回调指针,对于set的14种预设的解析配置方法
  void        *post;
}

// 说明
/*
  type:
      NGX_HTTP_MAIN_CONF
      NGX_HTTP_SRV_CONF
      NGX_HTTP_LOC_CONF
      NGX_HTTP_UP_CONF

      NGX_CONF_NOARGS
      NGX_CONF_TAKE1
      NGX_CONF_TAKE2

      NGX_CONF_FLAG
      NGX_CONF_1MORE

  set:
     参数cf: 包含传给指令的参数
     参数cmd: 指向当前的ngx_command_t结构
     参数conf: 指向custom configuration struct

      // setting particular types of values in the custom configuration sturct
      ngx_conf_set_flag_slot
      ngx_conf_set_str_slot
      ngx_conf_set_num_slot
      ngx_conf_set_size_slot

   conf:
      NGX_HTTP_MAIN_CONF_OFFSET
      NGX_HTTP_SRV_CONF_OFFSET
      NGX_HTTP_LOC_CONF_OFFSET

   post:
      ngx_conf_post_t
      ngx_conf_enum_t
      ngx_conf_bitmask_t
      null

 */

ngx_http_module_t:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

//HTTP框架在读取,重载配置文件时定义了由ngx_http_module_t接口描述的8个阶段
//这8个阶段的调用顺序应该是:
/*
create_main_conf
create_srv_conf
create_loc_conf
preconfiguration
init_main_conf
merge_srv_conf
merge_loc_conf
postconfiguration
*/
typedef struct {
  ngx_int_t   (*preconfiguration)(ngx_conf_t *cf);  //解析配置文件前调用
  ngx_int_t   (*postconfiguration)(ngx_conf_t *cf); //完成配置文件解析后调用

  void       *(*create_main_conf)(ngx_conf_t *cf);  //当需要创建数据结构用户存储main级别的全局配置项时候调用
  char       *(*init_main_conf)(ngx_conf_t *cf, void *conf); //初始化main级别配置项

  void       *(*create_srv_conf)(ngx_conf_t *cf); //当需要创建数据结构用户存储srv级别的全局配置项时候调用
  char       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); //srv覆盖策略

  void       *(*create_loc_conf)(ngx_conf_t *cf); //当需要创建数据结构用户存储loc级别的全局配置项时候调用
  char       *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf); //loc覆盖策略
} ngx_http_module_t;


ngx_module_t:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67



//参考:
//http://blog.csdn.net/livelylittlefish/article/details/6571497
#define NGX_MODULE_V1          0, 0, 0, 0, 0, 0, 1      //该宏用来初始化前7个字段  
#define NGX_MODULE_V1_PADDING  0, 0, 0, 0, 0, 0, 0, 0   //该宏用来初始化最后8个字段


//ngx_module_s是模块的定义
struct ngx_module_s {
  //对于一类模块(由下面的type成员决定类别)而言,ctx_index标示当前模块在这类模块中的序号。
  //这个成员常常是由管理这类模块的一个nginx核心模块设置的,对于所有的HTTP模块而言,ctx_index
  //是由核心模块ngx_http_module设置的。
  ngx_uint_t            ctx_index;

  //index表示当前模块在ngx_modules数组中的序号。Nginx启动的时候会根据ngx_modules数组设置各个模块的index值
  ngx_uint_t            index; 

  //spare系列的保留变量,暂未使用
  ngx_uint_t            spare0;
  ngx_uint_t            spare1;
  ngx_uint_t            spare2;
  ngx_uint_t            spare3;

  //nginx模块版本,目前只有一种,暂定为1
  //前面这7个参数使用NGX_MODULE_V1赋值
  ngx_uint_t            version;


  //模块上下文,每个模块有不同模块上下文,每个模块都有自己的特性,而ctx会指向特定类型模块的公共接口。
  //比如,在HTTP模块中,ctx需要指向ngx_http_module_t结构体。
  void                 *ctx;

  //模块命令集,将处理nginx.conf中的配置项
  // 如,在http模块中,指向ngx_command_t结构体
  ngx_command_t        *commands;


  //标示该模块的类型,和ctx是紧密相关的。它的取值范围是以下几种:
  //NGX_HTTP_MODULE,NGX_CORE_MODULE,NGX_CONF_MODULE,
  //NGX_EVENT_MODULE,NGX_MAIL_MODULE
  ngx_uint_t            type;


  //下面7个函数是nginx在启动,停止过程中的7个执行点
  ngx_int_t           (*init_master)(ngx_log_t *log);         //初始化master
  ngx_int_t           (*init_module)(ngx_cycle_t *cycle);     //初始化模块
  ngx_int_t           (*init_process)(ngx_cycle_t *cycle);    //初始化进程
  ngx_int_t           (*init_thread)(ngx_cycle_t *cycle);     //初始化线程
  void                (*exit_thread)(ngx_cycle_t *cycle);     //退出线程
  void                (*exit_process)(ngx_cycle_t *cycle);    //退出进程
  void                (*exit_master)(ngx_cycle_t *cycle);     //退出master


  //保留字段,无用,可以使用NGX_MODULE_V1_PADDING来替换
  uintptr_t             spare_hook0;
  uintptr_t             spare_hook1;
  uintptr_t             spare_hook2;
  uintptr_t             spare_hook3;
  uintptr_t             spare_hook4;
  uintptr_t             spare_hook5;
  uintptr_t             spare_hook6;
  uintptr_t             spare_hook7;


}

ngx_http_request_t:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320

//这个结构定义了一个HTTP请求。
struct ngx_http_request_s {
  uint32_t                          signature;         /* "HTTP" */

  // 这个请求对应的客户端连接
  ngx_connection_t                 *connection;  //当前request的连接

  // 指向存放所有HTTP模块的上下文结构体的指针数组
  void                            **ctx;  //上下文

  // 指向请求对应的存放main级别配置结构体的指针数组
  void                            **main_conf; //main配置

  // 指向请求对应的存放srv级别配置结构体的指针数组
  void                            **srv_conf;  //srv配置

  // 指向请求对应的存放loc级别配置结构体的指针数组
  void                            **loc_conf;  //loc配置

  /*
    在接收完HTTP头部,第一次在业务上处理HTTP请求时,HTTP框架提供的处理方法是ngx_http_process_request。
    但如果该方法无法一次处理完该请求的全部业务,在归还控制权到epoll事件模块后,该请求再次被回调时,将通过ngx_http_request_handler方法来处理,
    而这个方法中对于可读事件的处理就是调用read_event_handler处理请求。也就是说,HTTP模块希望在底层处理请求的读事件,重新实现read_evet_handler方法。
  */
  ngx_http_event_handler_pt         read_event_handler;

  /*
    与read_event_handler回调方法类似,如果ngx_http_request_handler方法判断当前事件是可写事件,则调用write_event_handler处理请求。
  */
  ngx_http_event_handler_pt         write_event_handler;

#if (NGX_HTTP_CACHE)
  ngx_http_cache_t                 *cache;
#endif

  // upstream机制用到的结构体
  ngx_http_upstream_t              *upstream;  //load-balance,如果模块是load-balance的话设置这个
  ngx_array_t                      *upstream_states;
  /* of ngx_http_upstream_state_t */

  /*
    表示这个请求的内存池,在ngx_http_free_request 方法中销毁。它与ngx_connection_t中的内存池意义不同,当请求释放时,
    TCP连接可能并没有关闭,这时请求的内存池会销毁,但ngx_connection_t的内存池不会销毁
  */
  ngx_pool_t                       *pool;     //连接池

  // 用于接收HTTP请求内容的缓冲区,主要用于接收HTTP头部
  ngx_buf_t                        *header_in;

  /*
    ngx_http_prcess_request_headers 方法在接收,解析完HTTP请求的头部后,会把解析完的每个HTTP头部加入到headers_in的headers连表中,
    同时会构造headers_in中的其他成员
  */
  ngx_http_headers_in_t             headers_in; //request的header
  /*
    HTTP模块会把想要发送到HTTP相应信息放到headers_out中,期望HTTP框架将headers_out中的成员序列化为HTTP相应包发送给用户
  */
  ngx_http_headers_out_t            headers_out; //response的header,使用ngx_http_send_header发送

  // 接收HTTP请求中包体的数据结构
  ngx_http_request_body_t          *request_body; //response的body

  // 延迟关闭连接的时间
  time_t                            lingering_time;

  /*
    当前请求初始化时的时间。如果这个请求是子请求,则该时间是自请求的生成时间;如果这个请求是用户发来的请求,则是建立起TCP连接后,第一次接收到可读事件时的时间
  */
  time_t                            start_sec;

  // 与start_sec配合使用,表示相对于start_sec秒的毫秒偏移量
  ngx_msec_t                        start_msec;

  ngx_uint_t                        method;
  ngx_uint_t                        http_version; //http的版本

  ngx_str_t                         request_line;
  ngx_str_t                         uri;  //请求的路径 eg '/query.php'
  ngx_str_t                         args; //请求的参数 eg 'name=john'
  ngx_str_t                         exten; 
  ngx_str_t                         unparsed_uri;

  ngx_str_t                         method_name;
  ngx_str_t                         http_protocol;

  /*
    表示需要发送给客户端的HTTP相应。out中保存着由headers_out中序列化后的表示HTTP头部的TCP流。在调用ngx_http_output_filter方法后,
    out中还会保存待发送的HTTP包体,它是实现异步发送的HTTP相应的关键
  */
  ngx_chain_t                      *out; //输出的chain

  /*
    当前请求既可能是用户发来的请求,也可能是派生出的子请求,而main则标识一系列相关的派生子请求的原始请求,
    我们一般可以通过main和当前请求的地址是否相等来判断当前请求是否为用户发来的原始请求。
  */
  ngx_http_request_t               *main;

  // 当前请求的父请求。注意,父请求未必是原始请求
  ngx_http_request_t               *parent;

  // 与subrequest子请求相关的功能。
  ngx_http_postponed_request_t     *postponed;
  ngx_http_post_subrequest_t       *post_subrequest;

  /*
    所有自请求都是通过posted_requests这个单链表来链接起来的,执行post子请求时调用的ngx_http_run_posted_requests
    方法就是通过遍历该单链表来执行子请求的。
  */
  ngx_http_posted_request_t        *posted_requests;

  ngx_http_virtual_names_t         *virtual_names;

  /*
    全局的ngx_http_phase_engine_t结构体中定义了一个ngx_http_phase_handler_t 回调方法组成的数组,
    而phase_handler成员则与该数组配合使用,表示请求下次应当执行以phase_handler作为序号指定的数组中的回调方法。
    HTTP框架正是以这种方式把各个HTTP模块集成起来处理请求的。
  */
  ngx_int_t                         phase_handler;

  /*
    表示NGX_HTTP_CONTENT_PHASE阶段提供给HTTP模块处理请求的一种方式,content_handler指向HTTP模块实现的请求处理方法。
  */
  ngx_http_handler_pt               content_handler;

  /*
    在NGX_HTTP_ACCESS_PHASE阶段需要判断请求是否具有访问权限时,通过access_code来传递HTTP模块的handler回调方法的返回值,
    如果access_code为0,则表示请求具备访问权限,反之则说明请求不具备访问权限
  */ 
  ngx_uint_t                        access_code;

  ngx_http_variable_value_t        *variables;

#if (NGX_PCRE)
  ngx_uint_t                        ncaptures;
  int                              *captures;
  u_char                           *captures_data;
#endif

  size_t                            limit_rate;

  /* used to learn the Apache compatible response length without a header */
  size_t                            header_size;

  // HTTP请求的全部长度,包括HTTP包体
  off_t                             request_length;

  ngx_uint_t                        err_status;

  ngx_http_connection_t            *http_connection;

  ngx_http_log_handler_pt           log_handler;

  // 在这个请求中,如果打开了某些资源,并需要在请求结束时释放,那么都需要在把定义的释放资源方法添加到cleanup成员中。
  ngx_http_cleanup_t               *cleanup;

  unsigned                          subrequests:8;

  /*
    表示当前请求的引用次数。例如,在使用subrequest功能时,依附在这个请求上的自请求数目会返回到count上,每增加一个子请求,
    count数就要加1。其中任何一个自请求派生出新的子请求时,对应的原始请求(main指针指向的请求)的count值都要加1.又如,
    当我们接收HTTP包体的时候,由于这也是一个异步调用,所以count上也需要加1,这样在结束请求时,就不会在count引用计数未清零时销毁请求。
  */
  unsigned                          count:8;

  // 标志位,目前仅由aio使用
  unsigned                          blocked:8;

  // 标志位,为1表示当前请求正在使用异步文件IO
  unsigned                          aio:1;

  unsigned                          http_state:4;

  /* URI with "/." and on Win32 with "//" */
  unsigned                          complex_uri:1;

  /* URI with "%" */
  unsigned                          quoted_uri:1;

  /* URI with "+" */
  unsigned                          plus_in_uri:1;

  /* URI with " " */
  unsigned                          space_in_uri:1;

  unsigned                          invalid_header:1;

  unsigned                          add_uri_to_alias:1;
  unsigned                          valid_location:1;
  unsigned                          valid_unparsed_uri:1;

  // 标志位,为1表示URL发生过rewrite重写
  unsigned                          uri_changed:1;

  /*
    表示使用rewrite重写URL的次数。因为目前最多可以更改10次,所以uri_changes初始化为11,而每重写URL一次就把uri_changes减1,
    一旦uri_changes等于0,则向用户返回失败
  */
  unsigned                          uri_changes:4;

  unsigned                          request_body_in_single_buf:1;
  unsigned                          request_body_in_file_only:1;
  unsigned                          request_body_in_persistent_file:1;
  unsigned                          request_body_in_clean_file:1;
  unsigned                          request_body_file_group_access:1;
  unsigned                          request_body_file_log_level:3;

  unsigned                          subrequest_in_memory:1;
  unsigned                          waited:1;

#if (NGX_HTTP_CACHE)
  unsigned                          cached:1;
#endif

#if (NGX_HTTP_GZIP)
  unsigned                          gzip_tested:1;
  unsigned                          gzip_ok:1;
  unsigned                          gzip_vary:1;
#endif

  unsigned                          proxy:1;
  unsigned                          bypass_cache:1;
  unsigned                          no_cache:1;

  /*
   * instead of using the request context data in
   * ngx_http_limit_zone_module and ngx_http_limit_req_module
   * we use the single bits in the request structure
   */
  unsigned                          limit_zone_set:1;
  unsigned                          limit_req_set:1;

#if 0
  unsigned                          cacheable:1;
#endif

  unsigned                          pipeline:1;
  unsigned                          plain_http:1;
  unsigned                          chunked:1;
  unsigned                          header_only:1;

  // 标志位,为1表示当前请求是keepalive请求
  unsigned                          keepalive:1;

  // 延迟关闭标志位,为1表示需要延迟关闭。例如在接收完HTTP头部时如果发现包体存在,该标志位会设置1,而放弃接收包体会设为0
  unsigned                          lingering_close:1;

  // 标志位,为1表示正在丢弃HTTP请求中的包体
  unsigned                          discard_body:1;

  // 标志位,为1表示请求的当前状态是在做内部跳转
  unsigned                          internal:1;
  unsigned                          error_page:1;
  unsigned                          ignore_content_encoding:1;
  unsigned                          filter_finalize:1;
  unsigned                          post_action:1;
  unsigned                          request_complete:1;
  unsigned                          request_output:1;

  // 标志位,为1表示发送给客户端的HTTP相应头部已经发送。在调用ngx_http_send_header方法后,若已经成功地启动相应头部发送流程,
  // 该标志位就会置1,用来防止反复地发送头部。
  unsigned                          header_sent:1;
  unsigned                          expect_tested:1;
  unsigned                          root_tested:1;
  unsigned                          done:1;
  unsigned                          logged:1;

  // 表示缓冲中是否有待发送内容的标志位
  unsigned                          buffered:4;

  unsigned                          main_filter_need_in_memory:1;
  unsigned                          filter_need_in_memory:1;
  unsigned                          filter_need_temporary:1;
  unsigned                          allow_ranges:1;

#if (NGX_STAT_STUB)
  unsigned                          stat_reading:1;
  unsigned                          stat_writing:1;
#endif

  /* used to parse HTTP headers */

  // 状态机解析HTTP时使用stats来表示当前的解析状态。
  ngx_uint_t                        state;

  ngx_uint_t                        header_hash;
  ngx_uint_t                        lowcase_index;
  u_char                            lowcase_header[NGX_HTTP_LC_HEADER_LEN];

  u_char                           *header_name_start;
  u_char                           *header_name_end;
  u_char                           *header_start;
  u_char                           *header_end;

  /*
   * a memory that can be reused after parsing a request line
   * via ngx_http_ephemeral_t
   */

  u_char                           *uri_start;
  u_char                           *uri_end;
  u_char                           *uri_ext;
  u_char                           *args_start;
  u_char                           *request_start;
  u_char                           *request_end;
  u_char                           *method_end;
  u_char                           *schema_start;
  u_char                           *schema_end;
  u_char                           *host_start;
  u_char                           *host_end;
  u_char                           *port_start;
  u_char                           *port_end;

  unsigned                          http_minor:16;
  unsigned                          http_major:16;

}