全面了解Nginx中的HTTP协议相关模块配置

时间:2021-12-23 18:04:16

要理解 HTTP 模块配置解析的过程,首先需要对 nginx 的配置文件结构做一个了解

nginx 的配置文件是用树状结构组织的,每个 NGX_CORE_MODULE 作为根统领着其下的所有配置项

而如下图所示,HTTP 模块的配置被分成了 main、server、location 三层

全面了解Nginx中的HTTP协议相关模块配置

整个 nginx 配置解析的过程其实就是这棵树的深度遍历过程

而遍历 HTTP 子树的函数就是下面要介绍的 ngx_http_block

 

配置文件解析 -- http 配置块
当我们需要使用 http 模块的时候,我们需要在配置文件中加入 http 配置块:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
http { // http 配置块 {{{
  include    mime.types;
  default_type application/octet-stream;
  #log_format main '$remote_addr - $remote_user [$time_local] "$request"
'
  #         '$status $body_bytes_sent "$http_referer" '
  #         '"$http_user_agent" "$http_x_forwarded_for"';
  #access_log logs/access.log main;
  sendfile    on;
  #tcp_nopush   on;
  #keepalive_timeout 0;
  keepalive_timeout 65;
  #gzip on;
  server {
    listen    8001;
    server_name localhost;
    #autoindex  on;
    #charset koi8-r;
    #access_log logs/host.access.log main;
    location / {
      root  /var/www/;
      index index.html index.htm index.php;

在 http 配置块中,我们配置了 http 连接相关的信息,HTTP 框架也正是从这里启动的.

在 nginx 初始化的过程中,执行了 ngx_init_cycle 函数,其中进行了配置文件解析,调用了 ngx_conf_parse 函数

 

配置文件解析

函数 ngx_conf_handler 根据配置项的 command 调用了对应的 set 回调函数

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
// 配置项解析 {{{
static ngx_int_t
ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{
  char      *rv;
  void      *conf, **confp;
  ngx_uint_t   i, found;
  ngx_str_t   *name;
  ngx_command_t *cmd;
  name = cf->args->elts;
  found = 0;
  for (i = 0; ngx_modules[i]; i++) {
    cmd = ngx_modules[i]->commands;
    if (cmd == NULL) {
      continue;
    }
    for ( /* void */ ; cmd->name.len; cmd++) {
      if (name->len != cmd->name.len) {
        continue;
      }
      if (ngx_strcmp(name->data, cmd->name.data) != 0) {
        continue;
      }

阅读各模块的 ngx_command_t 命令配置结构,可以找到:

?
1
2
3
4
5
6
7
8
9
10
11
// static ngx_command_t ngx_http_commands
// http 模块命令结构 {{{
static ngx_command_t ngx_http_commands[] = {
  { ngx_string("http"),
   NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
   ngx_http_block,
   0,
   0,
   NULL },
   ngx_null_command
}; // }}}

 

http 配置块解析 -- ngx_http_block

全面了解Nginx中的HTTP协议相关模块配置

在解析到 http 配置块时,执行了对应的 set 回调函数 ngx_http_block

?
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
321
322
323
324
325
static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
  char            *rv;
  ngx_uint_t          mi, m, s;
  ngx_conf_t          pcf;
  ngx_http_module_t      *module;
  ngx_http_conf_ctx_t     *ctx;
  ngx_http_core_loc_conf_t  *clcf;
  ngx_http_core_srv_conf_t  **cscfp;
  ngx_http_core_main_conf_t  *cmcf;
 
  /* the main http context */
 
  ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
  if (ctx == NULL) {
    return NGX_CONF_ERROR;
  }
 
 // 创建 http 配置结构,保存所有 http 模块的配置信息
  *(ngx_http_conf_ctx_t **) conf = ctx;
 
 
  /* count the number of the http modules and set up their indices */
 
  ngx_http_max_module = 0;
  for (m = 0; ngx_modules[m]; m++) {
    if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
      continue;
    }
 
 // 重新设定 HTTP 模块序号
    ngx_modules[m]->ctx_index = ngx_http_max_module++;
  }
 
 
  /* the http main_conf context, it is the same in the all http contexts */
 
  ctx->main_conf = ngx_pcalloc(cf->pool,
                 sizeof(void *) * ngx_http_max_module);
  if (ctx->main_conf == NULL) {
    return NGX_CONF_ERROR;
  }
 
 
  /*
   * the http null srv_conf context, it is used to merge
   * the server{}s' srv_conf's
   */
 
  ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  if (ctx->srv_conf == NULL) {
    return NGX_CONF_ERROR;
  }
 
 
  /*
   * the http null loc_conf context, it is used to merge
   * the server{}s' loc_conf's
   */
 
  ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  if (ctx->loc_conf == NULL) {
    return NGX_CONF_ERROR;
  }
 
 
  /*
   * create the main_conf's, the null srv_conf's, and the null loc_conf's
   * of the all http modules
   */
 
  for (m = 0; ngx_modules[m]; m++) {
    if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
      continue;
    }
 
    module = ngx_modules[m]->ctx;
    mi = ngx_modules[m]->ctx_index;
 
    if (module->create_main_conf) {
  // 调用每个模块的 create_main_conf 回调函数
  // 创建自己的 main_conf
  //
  // ngx_http_core_module  ngx_http_core_create_main_conf
  // ngx_http_log_module  ngx_http_log_create_main_conf
  // ngx_http_upstream_module  ngx_http_upstream_create_main_conf
  // ngx_http_map_module  ngx_http_map_create_conf
  // ngx_http_ssi_filter_module ngx_http_ssi_create_main_conf
  // ngx_http_charset_filter_module ngx_http_charset_create_main_conf
      ctx->main_conf[mi] = module->create_main_conf(cf);
      if (ctx->main_conf[mi] == NULL) {
        return NGX_CONF_ERROR;
      }
    }
 
    if (module->create_srv_conf) {
  // 调用每个模块的 create_srv_conf 回调函数
  // 创建自己的 srv_conf
  //
  // ngx_http_core_module   ngx_http_core_create_srv_conf
  // ngx_http_ssl_module   ngx_http_ssl_create_srv_conf
  // ngx_http_upstream_hash_module ngx_http_upstream_hash_create_conf
  // ngx_http_upstream_least_conn_module ngx_http_upstream_least_conn_create_conf
  // ngx_http_upstream_keepalive_module ngx_http_upstream_keepalive_create_conf
      ctx->srv_conf[mi] = module->create_srv_conf(cf);
      if (ctx->srv_conf[mi] == NULL) {
        return NGX_CONF_ERROR;
      }
    }
 
    if (module->create_loc_conf) {
  // 调用每个模块的 create_loc_conf 回调函数
  // 创建自己的 loc_conf
  //
  // ngx_http_core_module  ngx_http_core_create_loc_conf
  // ngx_http_log_module  ngx_http_log_create_loc_conf
  // ngx_http_gzip_static_module ngx_http_gzip_static_create_conf
  // ngx_http_autoindex_module ngx_http_autoindex_create_loc_conf
  // ngx_http_index_module  ngx_http_index_create_loc_conf
  // ngx_http_auth_basic_module ngx_http_auth_basic_create_loc_conf
  // ngx_http_access_module  ngx_http_access_create_loc_conf
  // ngx_http_limit_conn_module ngx_http_limit_conn_create_conf
  // ngx_http_limit_req_module ngx_http_limit_req_create_conf
  // ngx_http_referer_module  ngx_http_referer_create_conf
  // ngx_http_rewrite_module  ngx_http_rewrite_create_loc_conf
  // ngx_http_proxy_module  ngx_http_proxy_create_loc_conf
  // ngx_http_fastcgi_module  ngx_http_fastcgi_create_loc_conf
  // ngx_http_uwsgi_module  ngx_http_uwsgi_create_loc_conf
  // ngx_http_scgi_module  ngx_http_scgi_create_loc_conf
  // ngx_http_memcached_module ngx_http_memcached_create_loc_conf
  // ngx_http_browser_module  ngx_http_browser_create_conf
  // ngx_http_gzip_filter_module ngx_http_gzip_create_conf
  // ngx_http_ssi_filter_module ngx_http_ssi_create_loc_conf
  // ngx_http_charset_filter_module ngx_http_charset_create_loc_conf
  // ngx_http_userid_filter_module ngx_http_userid_create_conf
  // ngx_http_headers_filter_module ngx_http_headers_create_conf
  // ngx_http_copy_filter_module ngx_http_copy_filter_create_conf
      ctx->loc_conf[mi] = module->create_loc_conf(cf);
      if (ctx->loc_conf[mi] == NULL) {
        return NGX_CONF_ERROR;
      }
    }
  }
 
  pcf = *cf;
  cf->ctx = ctx;
 
  for (m = 0; ngx_modules[m]; m++) {
    if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
      continue;
    }
 
    module = ngx_modules[m]->ctx;
 
    if (module->preconfiguration) {
  // 调用每个模块的 preconfiguration 回调函数
  //
  // ngx_http_core_module  ngx_http_core_preconfiguration
  // ngx_http_upstream_module  ngx_http_upstream_add_variables
  // ngx_http_ssl_module  ngx_http_ssl_add_variables
  // ngx_http_proxy_module  ngx_http_proxy_add_variables
  // ngx_http_fastcgi_module  ngx_http_fastcgi_add_variables
  // ngx_http_browser_module  ngx_http_browser_add_variable
  // ngx_http_stub_status_module ngx_http_stub_status_add_variables
  // ngx_http_gzip_filter_module ngx_http_gzip_add_variables
  // ngx_http_ssi_filter_module ngx_http_ssi_preconfiguration
  // ngx_http_userid_filter_module ngx_http_userid_add_variables
      if (module->preconfiguration(cf) != NGX_OK) {
        return NGX_CONF_ERROR;
      }
    }
  }
 
  /* parse inside the http{} block */
 
  cf->module_type = NGX_HTTP_MODULE;
  cf->cmd_type = NGX_HTTP_MAIN_CONF;
  rv = ngx_conf_parse(cf, NULL);
 
  if (rv != NGX_CONF_OK) {
    goto failed;
  }
 
  /*
   * init http{} main_conf's, merge the server{}s' srv_conf's
   * and its location{}s' loc_conf's
   */
 
  cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
  cscfp = cmcf->servers.elts;
 
  for (m = 0; ngx_modules[m]; m++) {
    if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
      continue;
    }
 
    module = ngx_modules[m]->ctx;
    mi = ngx_modules[m]->ctx_index;
 
    /* init http{} main_conf's */
 
    if (module->init_main_conf) {
  // 调用每个模块的 init_main_conf 回调函数
  // 初始化自己的 main_conf
  //
  // ngx_http_core_module  ngx_http_core_init_main_conf
  // ngx_http_upstream_module ngx_http_upstream_init_main_conf
  // ngx_http_ssi_filter_module ngx_http_ssi_init_main_conf
      rv = module->init_main_conf(cf, ctx->main_conf[mi]);
      if (rv != NGX_CONF_OK) {
        goto failed;
      }
    }
 
 // 合并同名配置项
    rv = ngx_http_merge_servers(cf, cmcf, module, mi);
    if (rv != NGX_CONF_OK) {
      goto failed;
    }
  }
 
 
  /* create location trees */
 
  for (s = 0; s < cmcf->servers.nelts; s++) {
 
    clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
 
    if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
      return NGX_CONF_ERROR;
    }
 
    if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
      return NGX_CONF_ERROR;
    }
  }
 
 
  if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {
    return NGX_CONF_ERROR;
  }
 
  if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) {
    return NGX_CONF_ERROR;
  }
 
 
  for (m = 0; ngx_modules[m]; m++) {
    if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
      continue;
    }
 
    module = ngx_modules[m]->ctx;
 
    if (module->postconfiguration) {
  // 调用每个 HTTP 模块的 postconfiguration 回调函数
  //
  // ngx_http_log_module   ngx_http_log_init
  // ngx_http_static_module  ngx_http_static_init
  // ngx_http_gzip_static_module  ngx_http_gzip_static_init
  // ngx_http_autoindex_module  ngx_http_autoindex_init
  // ngx_http_index_module  ngx_http_index_init
  // ngx_http_auth_basic_module  ngx_http_auth_basic_init
  // ngx_http_access_module  ngx_http_access_init
  // ngx_http_limit_conn_module  ngx_http_limit_conn_init
  // ngx_http_limit_req_module  ngx_http_limit_req_init
  // ngx_http_rewrite_module  ngx_http_rewrite_init
  // ngx_http_ssl_module   ngx_http_ssl_init
  // ngx_http_write_filter_module  ngx_http_write_filter_init
  // ngx_http_header_filter_module ngx_http_header_filter_init
  // ngx_http_chunked_filter_module ngx_http_chunked_filter_init
  // ngx_http_range_body_filter_module ngx_http_range_body_filter_init
  // ngx_http_gzip_filter_module  ngx_http_gzip_filter_init
  // ngx_http_postpone_filter_module ngx_http_postpone_filter_init
  // ngx_http_ssi_filter_module  ngx_http_ssi_filter_init
  // ngx_http_charset_filter_module ngx_http_charset_postconfiguration
  // ngx_http_userid_filter_module ngx_http_userid_init
  // ngx_http_headers_filter_module ngx_http_headers_filter_init
  // ngx_http_copy_filter_module  ngx_http_copy_filter_init
  // ngx_http_range_body_filter_module ngx_http_range_body_filter_init
  // ngx_http_not_modified_filter_module ngx_http_not_modified_filter_init
      if (module->postconfiguration(cf) != NGX_OK) {
        return NGX_CONF_ERROR;
      }
    }
  }
 
 // 初始化所有的变量
 // 不仅包括HTTP core模块的变量
 // 也包括其他的HTTP模块导出的变量,以及配置文件中使用 set 命令设置的变量
 // 这里的初始化包括初始化hash表,以及初始化数组索引
  if (ngx_http_variables_init_vars(cf) != NGX_OK) {
    return NGX_CONF_ERROR;
  }
 
  /*
   * http{}'s cf->ctx was needed while the configuration merging
   * and in postconfiguration process
   */
 
  *cf = pcf;
 
 
 // 初始化 phase_engine 结构
  if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
    return NGX_CONF_ERROR;
  }
 
 
  /* optimize the lists of ports, addresses and server names */
 
 // 创建 http 连接,并设置为监听状态
  if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
    return NGX_CONF_ERROR;
  }
 
  return NGX_CONF_OK;
 
failed:
 
  *cf = pcf;
 
  return rv;
} // }}}

这个函数中,为所有的 http 模块都分配并创建了配置结构,同时,调用了每个模块相应的初始化回调。

最后,调用 ngx_http_optimize_servers 创建了 http 连接,加入 cycle 的监听数组,并设为监听状态。

nginx 配置文件对 http 模块的配置分为三层:main、sever、location,因此,http 模块上下文 ngx_http_module_t 中定义了以下六个回调函数,用来创建和保存配置信息:

  • create_main_conf
  • init_main_conf
  • create_srv_conf
  • merge_srv_conf
  • create_loc_conf
  • merge_loc_conf

在 ngx_http_block 中,循环调用了所有 NGX_HTTP_MODULE 的这六个回调函数,创建相关的配置结构。

 

server、location 配置解析 -- ngx_http_core_server、ngx_http_core_location
在调用所有 HTTP 模块的 create_main_conf、create_srv_conf、create_loc_conf 后,所有需要配置结构的模块都完成了配置结构的创建,于是在调用所有模块的 preconfiguration 回调函数后,配置解析工作正式展开

通过调用 ngx_conf_parse 函数,开始了 http 配置块的解析,并通过解析到的命令调用相应的函数

在首个 NGX_HTTP_MODULE ngx_http_core_module 的 ngx_command_t 域中包含了大量的配置指令,它们都是在http{}块中出现的,其中包括两个重要的指令:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{ ngx_string("listen"),
 NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
 ngx_http_core_listen,
 NGX_HTTP_SRV_CONF_OFFSET,
 0,
 NULL },
 
{ ngx_string("server"),
 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
 ngx_http_core_server,
 0,
 0,
 NULL },
 
{ ngx_string("location"),
 NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,
 ngx_http_core_location,
 NGX_HTTP_SRV_CONF_OFFSET,
 0,
 NULL },

这里配置了 listen、server 与 location 块的解析函数 ngx_http_core_listen、ngx_http_core_server 和 ngx_http_core_location.


server 块解析 -- ngx_http_core_server

?
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
// static char *
// ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
// http server 块解析 {{{
static char *
ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
  char            *rv;
  void            *mconf;
  ngx_uint_t          i;
  ngx_conf_t          pcf;
  ngx_http_module_t      *module;
  struct sockaddr_in     *sin;
  ngx_http_conf_ctx_t     *ctx, *http_ctx;
  ngx_http_listen_opt_t    lsopt;
  ngx_http_core_srv_conf_t  *cscf, **cscfp;
  ngx_http_core_main_conf_t  *cmcf;
 
  ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
  if (ctx == NULL) {
    return NGX_CONF_ERROR;
  }
 
  http_ctx = cf->ctx;
  ctx->main_conf = http_ctx->main_conf;
 
  /* the server{}'s srv_conf */
 
 // 为所有 HTTP 模块分配空间存储 srv_conf
  ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  if (ctx->srv_conf == NULL) {
    return NGX_CONF_ERROR;
  }
 
  /* the server{}'s loc_conf */
 
 // 为所有 HTTP 模块分配空间存储 loc_conf
  ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  if (ctx->loc_conf == NULL) {
    return NGX_CONF_ERROR;
  }
 
 // 循环调用每个模块的 create_srv_conf 与 create_loc_conf 回调,创建配置结构
  for (i = 0; ngx_modules[i]; i++) {
    if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
      continue;
    }
 
    module = ngx_modules[i]->ctx;
 
    if (module->create_srv_conf) {
      mconf = module->create_srv_conf(cf);
      if (mconf == NULL) {
        return NGX_CONF_ERROR;
      }
 
      ctx->srv_conf[ngx_modules[i]->ctx_index] = mconf;
    }
 
    if (module->create_loc_conf) {
      mconf = module->create_loc_conf(cf);
      if (mconf == NULL) {
        return NGX_CONF_ERROR;
      }
 
      ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
    }
  }
 
 
  /* the server configuration context */
 
  cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];
  cscf->ctx = ctx;
 
 
  cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
 
  cscfp = ngx_array_push(&cmcf->servers);
  if (cscfp == NULL) {
    return NGX_CONF_ERROR;
  }
 
  *cscfp = cscf;
 
 
  /* parse inside server{} */
 
  pcf = *cf;
  cf->ctx = ctx;
  cf->cmd_type = NGX_HTTP_SRV_CONF;
 
 // 解析 server 块配置
  rv = ngx_conf_parse(cf, NULL);
 
  *cf = pcf;
 
 // 如果没有监听任何端口,则监听默认的 80 或 8000端口
  if (rv == NGX_CONF_OK && !cscf->listen) {
    ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));
 
    sin = &lsopt.u.sockaddr_in;
 
    sin->sin_family = AF_INET;
#if (NGX_WIN32)
    sin->sin_port = htons(80);
#else
    sin->sin_port = htons((getuid() == 0) ? 80 : 8000);
#endif
    sin->sin_addr.s_addr = INADDR_ANY;
 
    lsopt.socklen = sizeof(struct sockaddr_in);
 
    lsopt.backlog = NGX_LISTEN_BACKLOG;
    lsopt.rcvbuf = -1;
    lsopt.sndbuf = -1;
#if (NGX_HAVE_SETFIB)
    lsopt.setfib = -1;
#endif
#if (NGX_HAVE_TCP_FASTOPEN)
    lsopt.fastopen = -1;
#endif
    lsopt.wildcard = 1;
 
    (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.socklen, lsopt.addr,
               NGX_SOCKADDR_STRLEN, 1);
 
    if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) {
      return NGX_CONF_ERROR;
    }
  }
 
  return rv;
} // }}}

 

location 块解析 -- ngx_http_core_location

?
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
// static char *
// ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
// location 块配置解析 {{{
static char *
ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
  char           *rv;
  u_char          *mod;
  size_t           len;
  ngx_str_t         *value, *name;
  ngx_uint_t         i;
  ngx_conf_t         save;
  ngx_http_module_t     *module;
  ngx_http_conf_ctx_t    *ctx, *pctx;
  ngx_http_core_loc_conf_t *clcf, *pclcf;
 
  ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
  if (ctx == NULL) {
    return NGX_CONF_ERROR;
  }
 
  pctx = cf->ctx;
  ctx->main_conf = pctx->main_conf;
  ctx->srv_conf = pctx->srv_conf;
 
  ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
  if (ctx->loc_conf == NULL) {
    return NGX_CONF_ERROR;
  }
 
  for (i = 0; ngx_modules[i]; i++) {
    if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
      continue;
    }
 
    module = ngx_modules[i]->ctx;
 
    if (module->create_loc_conf) {
      ctx->loc_conf[ngx_modules[i]->ctx_index] =
                          module->create_loc_conf(cf);
      if (ctx->loc_conf[ngx_modules[i]->ctx_index] == NULL) {
         return NGX_CONF_ERROR;
      }
    }
  }
 
  clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
  clcf->loc_conf = ctx->loc_conf;
 
  value = cf->args->elts;
 
  if (cf->args->nelts == 3) {
 
    len = value[1].len;
    mod = value[1].data;
    name = &value[2];
 
    if (len == 1 && mod[0] == '=') {
 
      clcf->name = *name;
      clcf->exact_match = 1;
 
    } else if (len == 2 && mod[0] == '^' && mod[1] == '~') {
 
      clcf->name = *name;
      clcf->noregex = 1;
 
    } else if (len == 1 && mod[0] == '~') {
 
      if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {
        return NGX_CONF_ERROR;
      }
 
    } else if (len == 2 && mod[0] == '~' && mod[1] == '*') {
 
      if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {
        return NGX_CONF_ERROR;
      }
 
    } else {
      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "invalid location modifier "%V"", &value[1]);
      return NGX_CONF_ERROR;
    }
 
  } else {
 
    name = &value[1];
 
    if (name->data[0] == '=') {
 
      clcf->name.len = name->len - 1;
      clcf->name.data = name->data + 1;
      clcf->exact_match = 1;
 
    } else if (name->data[0] == '^' && name->data[1] == '~') {
 
      clcf->name.len = name->len - 2;
      clcf->name.data = name->data + 2;
      clcf->noregex = 1;
 
    } else if (name->data[0] == '~') {
 
      name->len--;
      name->data++;
 
      if (name->data[0] == '*') {
 
        name->len--;
        name->data++;
 
        if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {
          return NGX_CONF_ERROR;
        }
 
      } else {
        if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {
          return NGX_CONF_ERROR;
        }
      }
 
    } else {
 
      clcf->name = *name;
 
      if (name->data[0] == '@') {
        clcf->named = 1;
      }
    }
  }
 
  pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
 
  if (pclcf->name.len) {
 
    /* nested location */
 
#if 0
    clcf->prev_location = pclcf;
#endif
 
    if (pclcf->exact_match) {
      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "location "%V" cannot be inside "
                "the exact location "%V"",
                &clcf->name, &pclcf->name);
      return NGX_CONF_ERROR;
    }
 
    if (pclcf->named) {
      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "location "%V" cannot be inside "
                "the named location "%V"",
                &clcf->name, &pclcf->name);
      return NGX_CONF_ERROR;
    }
 
    if (clcf->named) {
      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "named location "%V" can be "
                "on the server level only",
                &clcf->name);
      return NGX_CONF_ERROR;
    }
 
    len = pclcf->name.len;
 
#if (NGX_PCRE)
    if (clcf->regex == NULL
      && ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
#else
    if (ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
#endif
    {
      ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                "location "%V" is outside location "%V"",
                &clcf->name, &pclcf->name);
      return NGX_CONF_ERROR;
    }
  }
 
 // 将 location 配置加入到 locations 配置链表中
  if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
    return NGX_CONF_ERROR;
  }
 
  save = *cf;
  cf->ctx = ctx;
  cf->cmd_type = NGX_HTTP_LOC_CONF;
 
  rv = ngx_conf_parse(cf, NULL);
 
  *cf = save;
 
  return rv;
} // }}}

与 server 块解析函数 ngx_http_core_server 类似,他创建了所有模块的 loc_conf,为了防止内外层具有相同指令,在配置赋值完成后,会通过 merge 函数合并到一起。

然而,与 server 块不同,location 块在 location 后面会通过路径或正则表达式指定 location 配置的应用 uri,因此,在 ngx_http_core_location 函数中调用 PCRE 进行了 location 命令的解析。

解析完成后调用 ngx_http_add_location 将解析结果加入到 locations 链表中。

?
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
// ngx_int_t ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
//   ngx_http_core_loc_conf_t *clcf)
// 将 location 配置加入到 locations 配置链表中 {{{
ngx_int_t
ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
  ngx_http_core_loc_conf_t *clcf)
{
  ngx_http_location_queue_t *lq;
 
  if (*locations == NULL) {
    *locations = ngx_palloc(cf->temp_pool,
                sizeof(ngx_http_location_queue_t));
    if (*locations == NULL) {
      return NGX_ERROR;
    }
 
    ngx_queue_init(*locations);
  }
 
  lq = ngx_palloc(cf->temp_pool, sizeof(ngx_http_location_queue_t));
  if (lq == NULL) {
    return NGX_ERROR;
  }
 
  if (clcf->exact_match
#if (NGX_PCRE)
    || clcf->regex
#endif
    || clcf->named || clcf->noname)
  {
    lq->exact = clcf;
    lq->inclusive = NULL;
 
  } else {
    lq->exact = NULL;
    lq->inclusive = clcf;
  }
 
  lq->name = &clcf->name;
  lq->file_name = cf->conf_file->file.name.data;
  lq->line = cf->conf_file->line;
 
  ngx_queue_init(&lq->list);
 
  ngx_queue_insert_tail(*locations, &lq->queue);
 
  return NGX_OK;
} // }}}

配置解析全部完成后的配置结构。