/src/nginx/src/http/ngx_http.c
Line | Count | Source |
1 | | |
2 | | /* |
3 | | * Copyright (C) Igor Sysoev |
4 | | * Copyright (C) Nginx, Inc. |
5 | | */ |
6 | | |
7 | | |
8 | | #include <ngx_config.h> |
9 | | #include <ngx_core.h> |
10 | | #include <ngx_http.h> |
11 | | |
12 | | |
13 | | static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); |
14 | | static ngx_int_t ngx_http_init_phases(ngx_conf_t *cf, |
15 | | ngx_http_core_main_conf_t *cmcf); |
16 | | static ngx_int_t ngx_http_init_headers_in_hash(ngx_conf_t *cf, |
17 | | ngx_http_core_main_conf_t *cmcf); |
18 | | static ngx_int_t ngx_http_init_phase_handlers(ngx_conf_t *cf, |
19 | | ngx_http_core_main_conf_t *cmcf); |
20 | | |
21 | | static ngx_int_t ngx_http_add_addresses(ngx_conf_t *cf, |
22 | | ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port, |
23 | | ngx_http_listen_opt_t *lsopt); |
24 | | static ngx_int_t ngx_http_add_address(ngx_conf_t *cf, |
25 | | ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port, |
26 | | ngx_http_listen_opt_t *lsopt); |
27 | | static ngx_int_t ngx_http_add_server(ngx_conf_t *cf, |
28 | | ngx_http_core_srv_conf_t *cscf, ngx_http_conf_addr_t *addr); |
29 | | |
30 | | static char *ngx_http_merge_servers(ngx_conf_t *cf, |
31 | | ngx_http_core_main_conf_t *cmcf, ngx_http_module_t *module, |
32 | | ngx_uint_t ctx_index); |
33 | | static char *ngx_http_merge_locations(ngx_conf_t *cf, |
34 | | ngx_queue_t *locations, void **loc_conf, ngx_http_module_t *module, |
35 | | ngx_uint_t ctx_index); |
36 | | static ngx_int_t ngx_http_init_locations(ngx_conf_t *cf, |
37 | | ngx_http_core_srv_conf_t *cscf, ngx_http_core_loc_conf_t *pclcf); |
38 | | static ngx_int_t ngx_http_init_static_location_trees(ngx_conf_t *cf, |
39 | | ngx_http_core_loc_conf_t *pclcf); |
40 | | static ngx_int_t ngx_http_escape_location_name(ngx_conf_t *cf, |
41 | | ngx_http_core_loc_conf_t *clcf); |
42 | | static ngx_int_t ngx_http_cmp_locations(const ngx_queue_t *one, |
43 | | const ngx_queue_t *two); |
44 | | static ngx_int_t ngx_http_join_exact_locations(ngx_conf_t *cf, |
45 | | ngx_queue_t *locations); |
46 | | static void ngx_http_create_locations_list(ngx_queue_t *locations, |
47 | | ngx_queue_t *q); |
48 | | static ngx_http_location_tree_node_t * |
49 | | ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations, |
50 | | size_t prefix); |
51 | | |
52 | | static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf, |
53 | | ngx_http_core_main_conf_t *cmcf, ngx_array_t *ports); |
54 | | static ngx_int_t ngx_http_server_names(ngx_conf_t *cf, |
55 | | ngx_http_core_main_conf_t *cmcf, ngx_http_conf_addr_t *addr); |
56 | | static ngx_int_t ngx_http_cmp_conf_addrs(const void *one, const void *two); |
57 | | static int ngx_libc_cdecl ngx_http_cmp_dns_wildcards(const void *one, |
58 | | const void *two); |
59 | | |
60 | | static ngx_int_t ngx_http_init_listening(ngx_conf_t *cf, |
61 | | ngx_http_conf_port_t *port); |
62 | | static ngx_listening_t *ngx_http_add_listening(ngx_conf_t *cf, |
63 | | ngx_http_conf_addr_t *addr); |
64 | | static ngx_int_t ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport, |
65 | | ngx_http_conf_addr_t *addr); |
66 | | #if (NGX_HAVE_INET6) |
67 | | static ngx_int_t ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport, |
68 | | ngx_http_conf_addr_t *addr); |
69 | | #endif |
70 | | |
71 | | ngx_uint_t ngx_http_max_module; |
72 | | |
73 | | |
74 | | ngx_http_output_header_filter_pt ngx_http_top_header_filter; |
75 | | ngx_http_output_header_filter_pt ngx_http_top_early_hints_filter; |
76 | | ngx_http_output_body_filter_pt ngx_http_top_body_filter; |
77 | | ngx_http_request_body_filter_pt ngx_http_top_request_body_filter; |
78 | | |
79 | | |
80 | | ngx_str_t ngx_http_html_default_types[] = { |
81 | | ngx_string("text/html"), |
82 | | ngx_null_string |
83 | | }; |
84 | | |
85 | | |
86 | | static ngx_command_t ngx_http_commands[] = { |
87 | | |
88 | | { ngx_string("http"), |
89 | | NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, |
90 | | ngx_http_block, |
91 | | 0, |
92 | | 0, |
93 | | NULL }, |
94 | | |
95 | | ngx_null_command |
96 | | }; |
97 | | |
98 | | |
99 | | static ngx_core_module_t ngx_http_module_ctx = { |
100 | | ngx_string("http"), |
101 | | NULL, |
102 | | NULL |
103 | | }; |
104 | | |
105 | | |
106 | | ngx_module_t ngx_http_module = { |
107 | | NGX_MODULE_V1, |
108 | | &ngx_http_module_ctx, /* module context */ |
109 | | ngx_http_commands, /* module directives */ |
110 | | NGX_CORE_MODULE, /* module type */ |
111 | | NULL, /* init master */ |
112 | | NULL, /* init module */ |
113 | | NULL, /* init process */ |
114 | | NULL, /* init thread */ |
115 | | NULL, /* exit thread */ |
116 | | NULL, /* exit process */ |
117 | | NULL, /* exit master */ |
118 | | NGX_MODULE_V1_PADDING |
119 | | }; |
120 | | |
121 | | |
122 | | static char * |
123 | | ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
124 | 1 | { |
125 | 1 | char *rv; |
126 | 1 | ngx_uint_t mi, m, s; |
127 | 1 | ngx_conf_t pcf; |
128 | 1 | ngx_http_module_t *module; |
129 | 1 | ngx_http_conf_ctx_t *ctx; |
130 | 1 | ngx_http_core_loc_conf_t *clcf; |
131 | 1 | ngx_http_core_srv_conf_t **cscfp; |
132 | 1 | ngx_http_core_main_conf_t *cmcf; |
133 | | |
134 | 1 | if (*(ngx_http_conf_ctx_t **) conf) { |
135 | 0 | return "is duplicate"; |
136 | 0 | } |
137 | | |
138 | | /* the main http context */ |
139 | | |
140 | 1 | ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); |
141 | 1 | if (ctx == NULL) { |
142 | 0 | return NGX_CONF_ERROR; |
143 | 0 | } |
144 | | |
145 | 1 | *(ngx_http_conf_ctx_t **) conf = ctx; |
146 | | |
147 | | |
148 | | /* count the number of the http modules and set up their indices */ |
149 | | |
150 | 1 | ngx_http_max_module = ngx_count_modules(cf->cycle, NGX_HTTP_MODULE); |
151 | | |
152 | | |
153 | | /* the http main_conf context, it is the same in the all http contexts */ |
154 | | |
155 | 1 | ctx->main_conf = ngx_pcalloc(cf->pool, |
156 | 1 | sizeof(void *) * ngx_http_max_module); |
157 | 1 | if (ctx->main_conf == NULL) { |
158 | 0 | return NGX_CONF_ERROR; |
159 | 0 | } |
160 | | |
161 | | |
162 | | /* |
163 | | * the http null srv_conf context, it is used to merge |
164 | | * the server{}s' srv_conf's |
165 | | */ |
166 | | |
167 | 1 | ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); |
168 | 1 | if (ctx->srv_conf == NULL) { |
169 | 0 | return NGX_CONF_ERROR; |
170 | 0 | } |
171 | | |
172 | | |
173 | | /* |
174 | | * the http null loc_conf context, it is used to merge |
175 | | * the server{}s' loc_conf's |
176 | | */ |
177 | | |
178 | 1 | ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); |
179 | 1 | if (ctx->loc_conf == NULL) { |
180 | 0 | return NGX_CONF_ERROR; |
181 | 0 | } |
182 | | |
183 | | |
184 | | /* |
185 | | * create the main_conf's, the null srv_conf's, and the null loc_conf's |
186 | | * of the all http modules |
187 | | */ |
188 | | |
189 | 59 | for (m = 0; cf->cycle->modules[m]; m++) { |
190 | 58 | if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { |
191 | 8 | continue; |
192 | 8 | } |
193 | | |
194 | 50 | module = cf->cycle->modules[m]->ctx; |
195 | 50 | mi = cf->cycle->modules[m]->ctx_index; |
196 | | |
197 | 50 | if (module->create_main_conf) { |
198 | 11 | ctx->main_conf[mi] = module->create_main_conf(cf); |
199 | 11 | if (ctx->main_conf[mi] == NULL) { |
200 | 0 | return NGX_CONF_ERROR; |
201 | 0 | } |
202 | 11 | } |
203 | | |
204 | 50 | if (module->create_srv_conf) { |
205 | 7 | ctx->srv_conf[mi] = module->create_srv_conf(cf); |
206 | 7 | if (ctx->srv_conf[mi] == NULL) { |
207 | 0 | return NGX_CONF_ERROR; |
208 | 0 | } |
209 | 7 | } |
210 | | |
211 | 50 | if (module->create_loc_conf) { |
212 | 27 | ctx->loc_conf[mi] = module->create_loc_conf(cf); |
213 | 27 | if (ctx->loc_conf[mi] == NULL) { |
214 | 0 | return NGX_CONF_ERROR; |
215 | 0 | } |
216 | 27 | } |
217 | 50 | } |
218 | | |
219 | 1 | pcf = *cf; |
220 | 1 | cf->ctx = ctx; |
221 | | |
222 | 59 | for (m = 0; cf->cycle->modules[m]; m++) { |
223 | 58 | if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { |
224 | 8 | continue; |
225 | 8 | } |
226 | | |
227 | 50 | module = cf->cycle->modules[m]->ctx; |
228 | | |
229 | 50 | if (module->preconfiguration) { |
230 | 13 | if (module->preconfiguration(cf) != NGX_OK) { |
231 | 0 | return NGX_CONF_ERROR; |
232 | 0 | } |
233 | 13 | } |
234 | 50 | } |
235 | | |
236 | | /* parse inside the http{} block */ |
237 | | |
238 | 1 | cf->module_type = NGX_HTTP_MODULE; |
239 | 1 | cf->cmd_type = NGX_HTTP_MAIN_CONF; |
240 | 1 | rv = ngx_conf_parse(cf, NULL); |
241 | | |
242 | 1 | if (rv != NGX_CONF_OK) { |
243 | 0 | goto failed; |
244 | 0 | } |
245 | | |
246 | | /* |
247 | | * init http{} main_conf's, merge the server{}s' srv_conf's |
248 | | * and its location{}s' loc_conf's |
249 | | */ |
250 | | |
251 | 1 | cmcf = ctx->main_conf[ngx_http_core_module.ctx_index]; |
252 | 1 | cscfp = cmcf->servers.elts; |
253 | | |
254 | 59 | for (m = 0; cf->cycle->modules[m]; m++) { |
255 | 58 | if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { |
256 | 8 | continue; |
257 | 8 | } |
258 | | |
259 | 50 | module = cf->cycle->modules[m]->ctx; |
260 | 50 | mi = cf->cycle->modules[m]->ctx_index; |
261 | | |
262 | | /* init http{} main_conf's */ |
263 | | |
264 | 50 | if (module->init_main_conf) { |
265 | 5 | rv = module->init_main_conf(cf, ctx->main_conf[mi]); |
266 | 5 | if (rv != NGX_CONF_OK) { |
267 | 0 | goto failed; |
268 | 0 | } |
269 | 5 | } |
270 | | |
271 | 50 | rv = ngx_http_merge_servers(cf, cmcf, module, mi); |
272 | 50 | if (rv != NGX_CONF_OK) { |
273 | 0 | goto failed; |
274 | 0 | } |
275 | 50 | } |
276 | | |
277 | | |
278 | | /* create location trees */ |
279 | | |
280 | 2 | for (s = 0; s < cmcf->servers.nelts; s++) { |
281 | | |
282 | 1 | clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index]; |
283 | | |
284 | 1 | if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) { |
285 | 0 | return NGX_CONF_ERROR; |
286 | 0 | } |
287 | | |
288 | 1 | if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) { |
289 | 0 | return NGX_CONF_ERROR; |
290 | 0 | } |
291 | 1 | } |
292 | | |
293 | | |
294 | 1 | if (ngx_http_init_phases(cf, cmcf) != NGX_OK) { |
295 | 0 | return NGX_CONF_ERROR; |
296 | 0 | } |
297 | | |
298 | 1 | if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) { |
299 | 0 | return NGX_CONF_ERROR; |
300 | 0 | } |
301 | | |
302 | | |
303 | 59 | for (m = 0; cf->cycle->modules[m]; m++) { |
304 | 58 | if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { |
305 | 8 | continue; |
306 | 8 | } |
307 | | |
308 | 50 | module = cf->cycle->modules[m]->ctx; |
309 | | |
310 | 50 | if (module->postconfiguration) { |
311 | 26 | if (module->postconfiguration(cf) != NGX_OK) { |
312 | 0 | return NGX_CONF_ERROR; |
313 | 0 | } |
314 | 26 | } |
315 | 50 | } |
316 | | |
317 | 1 | if (ngx_http_variables_init_vars(cf) != NGX_OK) { |
318 | 0 | return NGX_CONF_ERROR; |
319 | 0 | } |
320 | | |
321 | | /* |
322 | | * http{}'s cf->ctx was needed while the configuration merging |
323 | | * and in postconfiguration process |
324 | | */ |
325 | | |
326 | 1 | *cf = pcf; |
327 | | |
328 | | |
329 | 1 | if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) { |
330 | 0 | return NGX_CONF_ERROR; |
331 | 0 | } |
332 | | |
333 | | |
334 | | /* optimize the lists of ports, addresses and server names */ |
335 | | |
336 | 1 | if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) { |
337 | 0 | return NGX_CONF_ERROR; |
338 | 0 | } |
339 | | |
340 | 1 | return NGX_CONF_OK; |
341 | | |
342 | 0 | failed: |
343 | |
|
344 | 0 | *cf = pcf; |
345 | |
|
346 | 0 | return rv; |
347 | 1 | } |
348 | | |
349 | | |
350 | | static ngx_int_t |
351 | | ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) |
352 | 1 | { |
353 | 1 | if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers, |
354 | 1 | cf->pool, 1, sizeof(ngx_http_handler_pt)) |
355 | 1 | != NGX_OK) |
356 | 0 | { |
357 | 0 | return NGX_ERROR; |
358 | 0 | } |
359 | | |
360 | 1 | if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers, |
361 | 1 | cf->pool, 1, sizeof(ngx_http_handler_pt)) |
362 | 1 | != NGX_OK) |
363 | 0 | { |
364 | 0 | return NGX_ERROR; |
365 | 0 | } |
366 | | |
367 | 1 | if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers, |
368 | 1 | cf->pool, 1, sizeof(ngx_http_handler_pt)) |
369 | 1 | != NGX_OK) |
370 | 0 | { |
371 | 0 | return NGX_ERROR; |
372 | 0 | } |
373 | | |
374 | 1 | if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers, |
375 | 1 | cf->pool, 1, sizeof(ngx_http_handler_pt)) |
376 | 1 | != NGX_OK) |
377 | 0 | { |
378 | 0 | return NGX_ERROR; |
379 | 0 | } |
380 | | |
381 | 1 | if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers, |
382 | 1 | cf->pool, 2, sizeof(ngx_http_handler_pt)) |
383 | 1 | != NGX_OK) |
384 | 0 | { |
385 | 0 | return NGX_ERROR; |
386 | 0 | } |
387 | | |
388 | 1 | if (ngx_array_init(&cmcf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers, |
389 | 1 | cf->pool, 2, sizeof(ngx_http_handler_pt)) |
390 | 1 | != NGX_OK) |
391 | 0 | { |
392 | 0 | return NGX_ERROR; |
393 | 0 | } |
394 | | |
395 | 1 | if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers, |
396 | 1 | cf->pool, 4, sizeof(ngx_http_handler_pt)) |
397 | 1 | != NGX_OK) |
398 | 0 | { |
399 | 0 | return NGX_ERROR; |
400 | 0 | } |
401 | | |
402 | 1 | if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers, |
403 | 1 | cf->pool, 1, sizeof(ngx_http_handler_pt)) |
404 | 1 | != NGX_OK) |
405 | 0 | { |
406 | 0 | return NGX_ERROR; |
407 | 0 | } |
408 | | |
409 | 1 | return NGX_OK; |
410 | 1 | } |
411 | | |
412 | | |
413 | | static ngx_int_t |
414 | | ngx_http_init_headers_in_hash(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) |
415 | 1 | { |
416 | 1 | ngx_array_t headers_in; |
417 | 1 | ngx_hash_key_t *hk; |
418 | 1 | ngx_hash_init_t hash; |
419 | 1 | ngx_http_header_t *header; |
420 | | |
421 | 1 | if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t)) |
422 | 1 | != NGX_OK) |
423 | 0 | { |
424 | 0 | return NGX_ERROR; |
425 | 0 | } |
426 | | |
427 | 26 | for (header = ngx_http_headers_in; header->name.len; header++) { |
428 | 25 | hk = ngx_array_push(&headers_in); |
429 | 25 | if (hk == NULL) { |
430 | 0 | return NGX_ERROR; |
431 | 0 | } |
432 | | |
433 | 25 | hk->key = header->name; |
434 | 25 | hk->key_hash = ngx_hash_key_lc(header->name.data, header->name.len); |
435 | 25 | hk->value = header; |
436 | 25 | } |
437 | | |
438 | 1 | hash.hash = &cmcf->headers_in_hash; |
439 | 1 | hash.key = ngx_hash_key_lc; |
440 | 1 | hash.max_size = 512; |
441 | 1 | hash.bucket_size = ngx_align(64, ngx_cacheline_size); |
442 | 1 | hash.name = "headers_in_hash"; |
443 | 1 | hash.pool = cf->pool; |
444 | 1 | hash.temp_pool = NULL; |
445 | | |
446 | 1 | if (ngx_hash_init(&hash, headers_in.elts, headers_in.nelts) != NGX_OK) { |
447 | 0 | return NGX_ERROR; |
448 | 0 | } |
449 | | |
450 | 1 | return NGX_OK; |
451 | 1 | } |
452 | | |
453 | | |
454 | | static ngx_int_t |
455 | | ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) |
456 | 1 | { |
457 | 1 | ngx_int_t j; |
458 | 1 | ngx_uint_t i, n; |
459 | 1 | ngx_uint_t find_config_index, use_rewrite, use_access; |
460 | 1 | ngx_http_handler_pt *h; |
461 | 1 | ngx_http_phase_handler_t *ph; |
462 | 1 | ngx_http_phase_handler_pt checker; |
463 | | |
464 | 1 | cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1; |
465 | 1 | cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1; |
466 | 1 | find_config_index = 0; |
467 | 1 | use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0; |
468 | 1 | use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0; |
469 | | |
470 | 1 | n = 1 /* find config phase */ |
471 | 1 | + use_rewrite /* post rewrite phase */ |
472 | 1 | + use_access; /* post access phase */ |
473 | | |
474 | 11 | for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) { |
475 | 10 | n += cmcf->phases[i].handlers.nelts; |
476 | 10 | } |
477 | | |
478 | 1 | ph = ngx_pcalloc(cf->pool, |
479 | 1 | n * sizeof(ngx_http_phase_handler_t) + sizeof(void *)); |
480 | 1 | if (ph == NULL) { |
481 | 0 | return NGX_ERROR; |
482 | 0 | } |
483 | | |
484 | 1 | cmcf->phase_engine.handlers = ph; |
485 | 1 | n = 0; |
486 | | |
487 | 11 | for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) { |
488 | 10 | h = cmcf->phases[i].handlers.elts; |
489 | | |
490 | 10 | switch (i) { |
491 | | |
492 | 1 | case NGX_HTTP_SERVER_REWRITE_PHASE: |
493 | 1 | if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) { |
494 | 1 | cmcf->phase_engine.server_rewrite_index = n; |
495 | 1 | } |
496 | 1 | checker = ngx_http_core_rewrite_phase; |
497 | | |
498 | 1 | break; |
499 | | |
500 | 1 | case NGX_HTTP_FIND_CONFIG_PHASE: |
501 | 1 | find_config_index = n; |
502 | | |
503 | 1 | ph->checker = ngx_http_core_find_config_phase; |
504 | 1 | n++; |
505 | 1 | ph++; |
506 | | |
507 | 1 | continue; |
508 | | |
509 | 1 | case NGX_HTTP_REWRITE_PHASE: |
510 | 1 | if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) { |
511 | 1 | cmcf->phase_engine.location_rewrite_index = n; |
512 | 1 | } |
513 | 1 | checker = ngx_http_core_rewrite_phase; |
514 | | |
515 | 1 | break; |
516 | | |
517 | 1 | case NGX_HTTP_POST_REWRITE_PHASE: |
518 | 1 | if (use_rewrite) { |
519 | 1 | ph->checker = ngx_http_core_post_rewrite_phase; |
520 | 1 | ph->next = find_config_index; |
521 | 1 | n++; |
522 | 1 | ph++; |
523 | 1 | } |
524 | | |
525 | 1 | continue; |
526 | | |
527 | 1 | case NGX_HTTP_ACCESS_PHASE: |
528 | 1 | checker = ngx_http_core_access_phase; |
529 | 1 | n++; |
530 | 1 | break; |
531 | | |
532 | 1 | case NGX_HTTP_POST_ACCESS_PHASE: |
533 | 1 | if (use_access) { |
534 | 1 | ph->checker = ngx_http_core_post_access_phase; |
535 | 1 | ph->next = n; |
536 | 1 | ph++; |
537 | 1 | } |
538 | | |
539 | 1 | continue; |
540 | | |
541 | 1 | case NGX_HTTP_CONTENT_PHASE: |
542 | 1 | checker = ngx_http_core_content_phase; |
543 | 1 | break; |
544 | | |
545 | 3 | default: |
546 | 3 | checker = ngx_http_core_generic_phase; |
547 | 10 | } |
548 | | |
549 | 7 | n += cmcf->phases[i].handlers.nelts; |
550 | | |
551 | 18 | for (j = cmcf->phases[i].handlers.nelts - 1; j >= 0; j--) { |
552 | 11 | ph->checker = checker; |
553 | 11 | ph->handler = h[j]; |
554 | 11 | ph->next = n; |
555 | 11 | ph++; |
556 | 11 | } |
557 | 7 | } |
558 | | |
559 | 1 | return NGX_OK; |
560 | 1 | } |
561 | | |
562 | | |
563 | | static char * |
564 | | ngx_http_merge_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, |
565 | | ngx_http_module_t *module, ngx_uint_t ctx_index) |
566 | 50 | { |
567 | 50 | char *rv; |
568 | 50 | ngx_uint_t s; |
569 | 50 | ngx_http_conf_ctx_t *ctx, saved; |
570 | 50 | ngx_http_core_loc_conf_t *clcf; |
571 | 50 | ngx_http_core_srv_conf_t **cscfp; |
572 | | |
573 | 50 | cscfp = cmcf->servers.elts; |
574 | 50 | ctx = (ngx_http_conf_ctx_t *) cf->ctx; |
575 | 50 | saved = *ctx; |
576 | 50 | rv = NGX_CONF_OK; |
577 | | |
578 | 100 | for (s = 0; s < cmcf->servers.nelts; s++) { |
579 | | |
580 | | /* merge the server{}s' srv_conf's */ |
581 | | |
582 | 50 | ctx->srv_conf = cscfp[s]->ctx->srv_conf; |
583 | | |
584 | 50 | if (module->merge_srv_conf) { |
585 | 2 | rv = module->merge_srv_conf(cf, saved.srv_conf[ctx_index], |
586 | 2 | cscfp[s]->ctx->srv_conf[ctx_index]); |
587 | 2 | if (rv != NGX_CONF_OK) { |
588 | 0 | goto failed; |
589 | 0 | } |
590 | 2 | } |
591 | | |
592 | 50 | if (module->merge_loc_conf) { |
593 | | |
594 | | /* merge the server{}'s loc_conf */ |
595 | | |
596 | 26 | ctx->loc_conf = cscfp[s]->ctx->loc_conf; |
597 | | |
598 | 26 | rv = module->merge_loc_conf(cf, saved.loc_conf[ctx_index], |
599 | 26 | cscfp[s]->ctx->loc_conf[ctx_index]); |
600 | 26 | if (rv != NGX_CONF_OK) { |
601 | 0 | goto failed; |
602 | 0 | } |
603 | | |
604 | | /* merge the locations{}' loc_conf's */ |
605 | | |
606 | 26 | clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index]; |
607 | | |
608 | 26 | rv = ngx_http_merge_locations(cf, clcf->locations, |
609 | 26 | cscfp[s]->ctx->loc_conf, |
610 | 26 | module, ctx_index); |
611 | 26 | if (rv != NGX_CONF_OK) { |
612 | 0 | goto failed; |
613 | 0 | } |
614 | 26 | } |
615 | 50 | } |
616 | | |
617 | 50 | failed: |
618 | | |
619 | 50 | *ctx = saved; |
620 | | |
621 | 50 | return rv; |
622 | 50 | } |
623 | | |
624 | | |
625 | | static char * |
626 | | ngx_http_merge_locations(ngx_conf_t *cf, ngx_queue_t *locations, |
627 | | void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index) |
628 | 52 | { |
629 | 52 | char *rv; |
630 | 52 | ngx_queue_t *q; |
631 | 52 | ngx_http_conf_ctx_t *ctx, saved; |
632 | 52 | ngx_http_core_loc_conf_t *clcf; |
633 | 52 | ngx_http_location_queue_t *lq; |
634 | | |
635 | 52 | if (locations == NULL) { |
636 | 26 | return NGX_CONF_OK; |
637 | 26 | } |
638 | | |
639 | 26 | ctx = (ngx_http_conf_ctx_t *) cf->ctx; |
640 | 26 | saved = *ctx; |
641 | | |
642 | 26 | for (q = ngx_queue_head(locations); |
643 | 52 | q != ngx_queue_sentinel(locations); |
644 | 26 | q = ngx_queue_next(q)) |
645 | 26 | { |
646 | 26 | lq = (ngx_http_location_queue_t *) q; |
647 | | |
648 | 26 | clcf = lq->exact ? lq->exact : lq->inclusive; |
649 | 26 | ctx->loc_conf = clcf->loc_conf; |
650 | | |
651 | 26 | rv = module->merge_loc_conf(cf, loc_conf[ctx_index], |
652 | 26 | clcf->loc_conf[ctx_index]); |
653 | 26 | if (rv != NGX_CONF_OK) { |
654 | 0 | return rv; |
655 | 0 | } |
656 | | |
657 | 26 | rv = ngx_http_merge_locations(cf, clcf->locations, clcf->loc_conf, |
658 | 26 | module, ctx_index); |
659 | 26 | if (rv != NGX_CONF_OK) { |
660 | 0 | return rv; |
661 | 0 | } |
662 | 26 | } |
663 | | |
664 | 26 | *ctx = saved; |
665 | | |
666 | 26 | return NGX_CONF_OK; |
667 | 26 | } |
668 | | |
669 | | |
670 | | static ngx_int_t |
671 | | ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, |
672 | | ngx_http_core_loc_conf_t *pclcf) |
673 | 2 | { |
674 | 2 | ngx_uint_t n; |
675 | 2 | ngx_queue_t *q, *locations, *named, tail; |
676 | 2 | ngx_http_core_loc_conf_t *clcf; |
677 | 2 | ngx_http_location_queue_t *lq; |
678 | 2 | ngx_http_core_loc_conf_t **clcfp; |
679 | 2 | #if (NGX_PCRE) |
680 | 2 | ngx_uint_t r; |
681 | 2 | ngx_queue_t *regex; |
682 | 2 | #endif |
683 | | |
684 | 2 | locations = pclcf->locations; |
685 | | |
686 | 2 | if (locations == NULL) { |
687 | 1 | return NGX_OK; |
688 | 1 | } |
689 | | |
690 | 1 | ngx_queue_sort(locations, ngx_http_cmp_locations); |
691 | | |
692 | 1 | named = NULL; |
693 | 1 | n = 0; |
694 | 1 | #if (NGX_PCRE) |
695 | 1 | regex = NULL; |
696 | 1 | r = 0; |
697 | 1 | #endif |
698 | | |
699 | 1 | for (q = ngx_queue_head(locations); |
700 | 2 | q != ngx_queue_sentinel(locations); |
701 | 1 | q = ngx_queue_next(q)) |
702 | 1 | { |
703 | 1 | lq = (ngx_http_location_queue_t *) q; |
704 | | |
705 | 1 | clcf = lq->exact ? lq->exact : lq->inclusive; |
706 | | |
707 | 1 | if (ngx_http_init_locations(cf, NULL, clcf) != NGX_OK) { |
708 | 0 | return NGX_ERROR; |
709 | 0 | } |
710 | | |
711 | 1 | #if (NGX_PCRE) |
712 | | |
713 | 1 | if (clcf->regex) { |
714 | 0 | r++; |
715 | |
|
716 | 0 | if (regex == NULL) { |
717 | 0 | regex = q; |
718 | 0 | } |
719 | |
|
720 | 0 | continue; |
721 | 0 | } |
722 | | |
723 | 1 | #endif |
724 | | |
725 | 1 | if (clcf->named) { |
726 | 0 | n++; |
727 | |
|
728 | 0 | if (named == NULL) { |
729 | 0 | named = q; |
730 | 0 | } |
731 | |
|
732 | 0 | continue; |
733 | 0 | } |
734 | | |
735 | 1 | if (clcf->noname) { |
736 | 0 | break; |
737 | 0 | } |
738 | 1 | } |
739 | | |
740 | 1 | if (q != ngx_queue_sentinel(locations)) { |
741 | 0 | ngx_queue_split(locations, q, &tail); |
742 | 0 | } |
743 | | |
744 | 1 | if (named) { |
745 | 0 | clcfp = ngx_palloc(cf->pool, |
746 | 0 | (n + 1) * sizeof(ngx_http_core_loc_conf_t *)); |
747 | 0 | if (clcfp == NULL) { |
748 | 0 | return NGX_ERROR; |
749 | 0 | } |
750 | | |
751 | 0 | cscf->named_locations = clcfp; |
752 | |
|
753 | 0 | for (q = named; |
754 | 0 | q != ngx_queue_sentinel(locations); |
755 | 0 | q = ngx_queue_next(q)) |
756 | 0 | { |
757 | 0 | lq = (ngx_http_location_queue_t *) q; |
758 | |
|
759 | 0 | *(clcfp++) = lq->exact; |
760 | 0 | } |
761 | |
|
762 | 0 | *clcfp = NULL; |
763 | |
|
764 | 0 | ngx_queue_split(locations, named, &tail); |
765 | 0 | } |
766 | | |
767 | 1 | #if (NGX_PCRE) |
768 | | |
769 | 1 | if (regex) { |
770 | |
|
771 | 0 | clcfp = ngx_palloc(cf->pool, |
772 | 0 | (r + 1) * sizeof(ngx_http_core_loc_conf_t *)); |
773 | 0 | if (clcfp == NULL) { |
774 | 0 | return NGX_ERROR; |
775 | 0 | } |
776 | | |
777 | 0 | pclcf->regex_locations = clcfp; |
778 | |
|
779 | 0 | for (q = regex; |
780 | 0 | q != ngx_queue_sentinel(locations); |
781 | 0 | q = ngx_queue_next(q)) |
782 | 0 | { |
783 | 0 | lq = (ngx_http_location_queue_t *) q; |
784 | |
|
785 | 0 | *(clcfp++) = lq->exact; |
786 | 0 | } |
787 | |
|
788 | 0 | *clcfp = NULL; |
789 | |
|
790 | 0 | ngx_queue_split(locations, regex, &tail); |
791 | 0 | } |
792 | | |
793 | 1 | #endif |
794 | | |
795 | 1 | return NGX_OK; |
796 | 1 | } |
797 | | |
798 | | |
799 | | static ngx_int_t |
800 | | ngx_http_init_static_location_trees(ngx_conf_t *cf, |
801 | | ngx_http_core_loc_conf_t *pclcf) |
802 | 2 | { |
803 | 2 | ngx_queue_t *q, *locations; |
804 | 2 | ngx_http_core_loc_conf_t *clcf; |
805 | 2 | ngx_http_location_queue_t *lq; |
806 | | |
807 | 2 | locations = pclcf->locations; |
808 | | |
809 | 2 | if (locations == NULL) { |
810 | 1 | return NGX_OK; |
811 | 1 | } |
812 | | |
813 | 1 | if (ngx_queue_empty(locations)) { |
814 | 0 | return NGX_OK; |
815 | 0 | } |
816 | | |
817 | 1 | for (q = ngx_queue_head(locations); |
818 | 2 | q != ngx_queue_sentinel(locations); |
819 | 1 | q = ngx_queue_next(q)) |
820 | 1 | { |
821 | 1 | lq = (ngx_http_location_queue_t *) q; |
822 | | |
823 | 1 | clcf = lq->exact ? lq->exact : lq->inclusive; |
824 | | |
825 | 1 | if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) { |
826 | 0 | return NGX_ERROR; |
827 | 0 | } |
828 | 1 | } |
829 | | |
830 | 1 | if (ngx_http_join_exact_locations(cf, locations) != NGX_OK) { |
831 | 0 | return NGX_ERROR; |
832 | 0 | } |
833 | | |
834 | 1 | ngx_http_create_locations_list(locations, ngx_queue_head(locations)); |
835 | | |
836 | 1 | pclcf->static_locations = ngx_http_create_locations_tree(cf, locations, 0); |
837 | 1 | if (pclcf->static_locations == NULL) { |
838 | 0 | return NGX_ERROR; |
839 | 0 | } |
840 | | |
841 | 1 | return NGX_OK; |
842 | 1 | } |
843 | | |
844 | | |
845 | | ngx_int_t |
846 | | ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations, |
847 | | ngx_http_core_loc_conf_t *clcf) |
848 | 1 | { |
849 | 1 | ngx_http_location_queue_t *lq; |
850 | | |
851 | 1 | if (*locations == NULL) { |
852 | 1 | *locations = ngx_palloc(cf->temp_pool, |
853 | 1 | sizeof(ngx_http_location_queue_t)); |
854 | 1 | if (*locations == NULL) { |
855 | 0 | return NGX_ERROR; |
856 | 0 | } |
857 | | |
858 | 1 | ngx_queue_init(*locations); |
859 | 1 | } |
860 | | |
861 | 1 | lq = ngx_palloc(cf->temp_pool, sizeof(ngx_http_location_queue_t)); |
862 | 1 | if (lq == NULL) { |
863 | 0 | return NGX_ERROR; |
864 | 0 | } |
865 | | |
866 | 1 | if (clcf->exact_match |
867 | 1 | #if (NGX_PCRE) |
868 | 1 | || clcf->regex |
869 | 1 | #endif |
870 | 1 | || clcf->named || clcf->noname) |
871 | 0 | { |
872 | 0 | lq->exact = clcf; |
873 | 0 | lq->inclusive = NULL; |
874 | |
|
875 | 1 | } else { |
876 | 1 | lq->exact = NULL; |
877 | 1 | lq->inclusive = clcf; |
878 | 1 | } |
879 | | |
880 | 1 | lq->name = &clcf->name; |
881 | 1 | lq->file_name = cf->conf_file->file.name.data; |
882 | 1 | lq->line = cf->conf_file->line; |
883 | | |
884 | 1 | ngx_queue_init(&lq->list); |
885 | | |
886 | 1 | ngx_queue_insert_tail(*locations, &lq->queue); |
887 | | |
888 | 1 | if (ngx_http_escape_location_name(cf, clcf) != NGX_OK) { |
889 | 0 | return NGX_ERROR; |
890 | 0 | } |
891 | | |
892 | 1 | return NGX_OK; |
893 | 1 | } |
894 | | |
895 | | |
896 | | static ngx_int_t |
897 | | ngx_http_escape_location_name(ngx_conf_t *cf, ngx_http_core_loc_conf_t *clcf) |
898 | 1 | { |
899 | 1 | u_char *p; |
900 | 1 | size_t len; |
901 | 1 | uintptr_t escape; |
902 | | |
903 | 1 | escape = 2 * ngx_escape_uri(NULL, clcf->name.data, clcf->name.len, |
904 | 1 | NGX_ESCAPE_URI); |
905 | | |
906 | 1 | if (escape) { |
907 | 0 | len = clcf->name.len + escape; |
908 | |
|
909 | 0 | p = ngx_pnalloc(cf->pool, len); |
910 | 0 | if (p == NULL) { |
911 | 0 | return NGX_ERROR; |
912 | 0 | } |
913 | | |
914 | 0 | clcf->escaped_name.len = len; |
915 | 0 | clcf->escaped_name.data = p; |
916 | |
|
917 | 0 | ngx_escape_uri(p, clcf->name.data, clcf->name.len, NGX_ESCAPE_URI); |
918 | |
|
919 | 1 | } else { |
920 | 1 | clcf->escaped_name = clcf->name; |
921 | 1 | } |
922 | | |
923 | 1 | return NGX_OK; |
924 | 1 | } |
925 | | |
926 | | |
927 | | static ngx_int_t |
928 | | ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two) |
929 | 0 | { |
930 | 0 | ngx_int_t rc; |
931 | 0 | ngx_http_core_loc_conf_t *first, *second; |
932 | 0 | ngx_http_location_queue_t *lq1, *lq2; |
933 | |
|
934 | 0 | lq1 = (ngx_http_location_queue_t *) one; |
935 | 0 | lq2 = (ngx_http_location_queue_t *) two; |
936 | |
|
937 | 0 | first = lq1->exact ? lq1->exact : lq1->inclusive; |
938 | 0 | second = lq2->exact ? lq2->exact : lq2->inclusive; |
939 | |
|
940 | 0 | if (first->noname && !second->noname) { |
941 | | /* shift no named locations to the end */ |
942 | 0 | return 1; |
943 | 0 | } |
944 | | |
945 | 0 | if (!first->noname && second->noname) { |
946 | | /* shift no named locations to the end */ |
947 | 0 | return -1; |
948 | 0 | } |
949 | | |
950 | 0 | if (first->noname || second->noname) { |
951 | | /* do not sort no named locations */ |
952 | 0 | return 0; |
953 | 0 | } |
954 | | |
955 | 0 | if (first->named && !second->named) { |
956 | | /* shift named locations to the end */ |
957 | 0 | return 1; |
958 | 0 | } |
959 | | |
960 | 0 | if (!first->named && second->named) { |
961 | | /* shift named locations to the end */ |
962 | 0 | return -1; |
963 | 0 | } |
964 | | |
965 | 0 | if (first->named && second->named) { |
966 | 0 | return ngx_strcmp(first->name.data, second->name.data); |
967 | 0 | } |
968 | | |
969 | 0 | #if (NGX_PCRE) |
970 | | |
971 | 0 | if (first->regex && !second->regex) { |
972 | | /* shift the regex matches to the end */ |
973 | 0 | return 1; |
974 | 0 | } |
975 | | |
976 | 0 | if (!first->regex && second->regex) { |
977 | | /* shift the regex matches to the end */ |
978 | 0 | return -1; |
979 | 0 | } |
980 | | |
981 | 0 | if (first->regex || second->regex) { |
982 | | /* do not sort the regex matches */ |
983 | 0 | return 0; |
984 | 0 | } |
985 | | |
986 | 0 | #endif |
987 | | |
988 | 0 | rc = ngx_filename_cmp(first->name.data, second->name.data, |
989 | 0 | ngx_min(first->name.len, second->name.len) + 1); |
990 | |
|
991 | 0 | if (rc == 0 && !first->exact_match && second->exact_match) { |
992 | | /* an exact match must be before the same inclusive one */ |
993 | 0 | return 1; |
994 | 0 | } |
995 | | |
996 | 0 | return rc; |
997 | 0 | } |
998 | | |
999 | | |
1000 | | static ngx_int_t |
1001 | | ngx_http_join_exact_locations(ngx_conf_t *cf, ngx_queue_t *locations) |
1002 | 1 | { |
1003 | 1 | ngx_queue_t *q, *x; |
1004 | 1 | ngx_http_location_queue_t *lq, *lx; |
1005 | | |
1006 | 1 | q = ngx_queue_head(locations); |
1007 | | |
1008 | 1 | while (q != ngx_queue_last(locations)) { |
1009 | |
|
1010 | 0 | x = ngx_queue_next(q); |
1011 | |
|
1012 | 0 | lq = (ngx_http_location_queue_t *) q; |
1013 | 0 | lx = (ngx_http_location_queue_t *) x; |
1014 | |
|
1015 | 0 | if (lq->name->len == lx->name->len |
1016 | 0 | && ngx_filename_cmp(lq->name->data, lx->name->data, lx->name->len) |
1017 | 0 | == 0) |
1018 | 0 | { |
1019 | 0 | if ((lq->exact && lx->exact) || (lq->inclusive && lx->inclusive)) { |
1020 | 0 | ngx_log_error(NGX_LOG_EMERG, cf->log, 0, |
1021 | 0 | "duplicate location \"%V\" in %s:%ui", |
1022 | 0 | lx->name, lx->file_name, lx->line); |
1023 | |
|
1024 | 0 | return NGX_ERROR; |
1025 | 0 | } |
1026 | | |
1027 | 0 | lq->inclusive = lx->inclusive; |
1028 | |
|
1029 | 0 | ngx_queue_remove(x); |
1030 | |
|
1031 | 0 | continue; |
1032 | 0 | } |
1033 | | |
1034 | 0 | q = ngx_queue_next(q); |
1035 | 0 | } |
1036 | | |
1037 | 1 | return NGX_OK; |
1038 | 1 | } |
1039 | | |
1040 | | |
1041 | | static void |
1042 | | ngx_http_create_locations_list(ngx_queue_t *locations, ngx_queue_t *q) |
1043 | 1 | { |
1044 | 1 | u_char *name; |
1045 | 1 | size_t len; |
1046 | 1 | ngx_queue_t *x, tail; |
1047 | 1 | ngx_http_location_queue_t *lq, *lx; |
1048 | | |
1049 | 1 | if (q == ngx_queue_last(locations)) { |
1050 | 1 | return; |
1051 | 1 | } |
1052 | | |
1053 | 0 | lq = (ngx_http_location_queue_t *) q; |
1054 | |
|
1055 | 0 | if (lq->inclusive == NULL) { |
1056 | 0 | ngx_http_create_locations_list(locations, ngx_queue_next(q)); |
1057 | 0 | return; |
1058 | 0 | } |
1059 | | |
1060 | 0 | len = lq->name->len; |
1061 | 0 | name = lq->name->data; |
1062 | |
|
1063 | 0 | for (x = ngx_queue_next(q); |
1064 | 0 | x != ngx_queue_sentinel(locations); |
1065 | 0 | x = ngx_queue_next(x)) |
1066 | 0 | { |
1067 | 0 | lx = (ngx_http_location_queue_t *) x; |
1068 | |
|
1069 | 0 | if (len > lx->name->len |
1070 | 0 | || ngx_filename_cmp(name, lx->name->data, len) != 0) |
1071 | 0 | { |
1072 | 0 | break; |
1073 | 0 | } |
1074 | 0 | } |
1075 | |
|
1076 | 0 | q = ngx_queue_next(q); |
1077 | |
|
1078 | 0 | if (q == x) { |
1079 | 0 | ngx_http_create_locations_list(locations, x); |
1080 | 0 | return; |
1081 | 0 | } |
1082 | | |
1083 | 0 | ngx_queue_split(locations, q, &tail); |
1084 | 0 | ngx_queue_add(&lq->list, &tail); |
1085 | |
|
1086 | 0 | if (x == ngx_queue_sentinel(locations)) { |
1087 | 0 | ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list)); |
1088 | 0 | return; |
1089 | 0 | } |
1090 | | |
1091 | 0 | ngx_queue_split(&lq->list, x, &tail); |
1092 | 0 | ngx_queue_add(locations, &tail); |
1093 | |
|
1094 | 0 | ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list)); |
1095 | |
|
1096 | 0 | ngx_http_create_locations_list(locations, x); |
1097 | 0 | } |
1098 | | |
1099 | | |
1100 | | /* |
1101 | | * to keep cache locality for left leaf nodes, allocate nodes in following |
1102 | | * order: node, left subtree, right subtree, inclusive subtree |
1103 | | */ |
1104 | | |
1105 | | static ngx_http_location_tree_node_t * |
1106 | | ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations, |
1107 | | size_t prefix) |
1108 | 1 | { |
1109 | 1 | size_t len; |
1110 | 1 | ngx_queue_t *q, tail; |
1111 | 1 | ngx_http_location_queue_t *lq; |
1112 | 1 | ngx_http_location_tree_node_t *node; |
1113 | | |
1114 | 1 | q = ngx_queue_middle(locations); |
1115 | | |
1116 | 1 | lq = (ngx_http_location_queue_t *) q; |
1117 | 1 | len = lq->name->len - prefix; |
1118 | | |
1119 | 1 | node = ngx_palloc(cf->pool, |
1120 | 1 | offsetof(ngx_http_location_tree_node_t, name) + len); |
1121 | 1 | if (node == NULL) { |
1122 | 0 | return NULL; |
1123 | 0 | } |
1124 | | |
1125 | 1 | node->left = NULL; |
1126 | 1 | node->right = NULL; |
1127 | 1 | node->tree = NULL; |
1128 | 1 | node->exact = lq->exact; |
1129 | 1 | node->inclusive = lq->inclusive; |
1130 | | |
1131 | 1 | node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect) |
1132 | 1 | || (lq->inclusive && lq->inclusive->auto_redirect)); |
1133 | | |
1134 | 1 | node->len = (u_short) len; |
1135 | 1 | ngx_memcpy(node->name, &lq->name->data[prefix], len); |
1136 | | |
1137 | 1 | ngx_queue_split(locations, q, &tail); |
1138 | | |
1139 | 1 | if (ngx_queue_empty(locations)) { |
1140 | | /* |
1141 | | * ngx_queue_split() insures that if left part is empty, |
1142 | | * then right one is empty too |
1143 | | */ |
1144 | 1 | goto inclusive; |
1145 | 1 | } |
1146 | | |
1147 | 0 | node->left = ngx_http_create_locations_tree(cf, locations, prefix); |
1148 | 0 | if (node->left == NULL) { |
1149 | 0 | return NULL; |
1150 | 0 | } |
1151 | | |
1152 | 0 | ngx_queue_remove(q); |
1153 | |
|
1154 | 0 | if (ngx_queue_empty(&tail)) { |
1155 | 0 | goto inclusive; |
1156 | 0 | } |
1157 | | |
1158 | 0 | node->right = ngx_http_create_locations_tree(cf, &tail, prefix); |
1159 | 0 | if (node->right == NULL) { |
1160 | 0 | return NULL; |
1161 | 0 | } |
1162 | | |
1163 | 1 | inclusive: |
1164 | | |
1165 | 1 | if (ngx_queue_empty(&lq->list)) { |
1166 | 1 | return node; |
1167 | 1 | } |
1168 | | |
1169 | 0 | node->tree = ngx_http_create_locations_tree(cf, &lq->list, prefix + len); |
1170 | 0 | if (node->tree == NULL) { |
1171 | 0 | return NULL; |
1172 | 0 | } |
1173 | | |
1174 | 0 | return node; |
1175 | 0 | } |
1176 | | |
1177 | | |
1178 | | ngx_int_t |
1179 | | ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, |
1180 | | ngx_http_listen_opt_t *lsopt) |
1181 | 1 | { |
1182 | 1 | in_port_t p; |
1183 | 1 | ngx_uint_t i; |
1184 | 1 | struct sockaddr *sa; |
1185 | 1 | ngx_http_conf_port_t *port; |
1186 | 1 | ngx_http_core_main_conf_t *cmcf; |
1187 | | |
1188 | 1 | cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); |
1189 | | |
1190 | 1 | if (cmcf->ports == NULL) { |
1191 | 1 | cmcf->ports = ngx_array_create(cf->temp_pool, 2, |
1192 | 1 | sizeof(ngx_http_conf_port_t)); |
1193 | 1 | if (cmcf->ports == NULL) { |
1194 | 0 | return NGX_ERROR; |
1195 | 0 | } |
1196 | 1 | } |
1197 | | |
1198 | 1 | sa = lsopt->sockaddr; |
1199 | 1 | p = ngx_inet_get_port(sa); |
1200 | | |
1201 | 1 | port = cmcf->ports->elts; |
1202 | 1 | for (i = 0; i < cmcf->ports->nelts; i++) { |
1203 | |
|
1204 | 0 | if (p != port[i].port |
1205 | 0 | || lsopt->type != port[i].type |
1206 | 0 | || sa->sa_family != port[i].family) |
1207 | 0 | { |
1208 | 0 | continue; |
1209 | 0 | } |
1210 | | |
1211 | | /* a port is already in the port list */ |
1212 | | |
1213 | 0 | return ngx_http_add_addresses(cf, cscf, &port[i], lsopt); |
1214 | 0 | } |
1215 | | |
1216 | | /* add a port to the port list */ |
1217 | | |
1218 | 1 | port = ngx_array_push(cmcf->ports); |
1219 | 1 | if (port == NULL) { |
1220 | 0 | return NGX_ERROR; |
1221 | 0 | } |
1222 | | |
1223 | 1 | port->family = sa->sa_family; |
1224 | 1 | port->type = lsopt->type; |
1225 | 1 | port->port = p; |
1226 | 1 | port->addrs.elts = NULL; |
1227 | | |
1228 | 1 | return ngx_http_add_address(cf, cscf, port, lsopt); |
1229 | 1 | } |
1230 | | |
1231 | | |
1232 | | static ngx_int_t |
1233 | | ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, |
1234 | | ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt) |
1235 | 0 | { |
1236 | 0 | ngx_uint_t i, default_server, proxy_protocol, |
1237 | 0 | protocols, protocols_prev; |
1238 | 0 | ngx_http_conf_addr_t *addr; |
1239 | | #if (NGX_HTTP_SSL) |
1240 | | ngx_uint_t ssl; |
1241 | | #endif |
1242 | 0 | #if (NGX_HTTP_V2) |
1243 | 0 | ngx_uint_t http2; |
1244 | 0 | #endif |
1245 | | #if (NGX_HTTP_V3) |
1246 | | ngx_uint_t quic; |
1247 | | #endif |
1248 | | |
1249 | | /* |
1250 | | * we cannot compare whole sockaddr struct's as kernel |
1251 | | * may fill some fields in inherited sockaddr struct's |
1252 | | */ |
1253 | |
|
1254 | 0 | addr = port->addrs.elts; |
1255 | |
|
1256 | 0 | for (i = 0; i < port->addrs.nelts; i++) { |
1257 | |
|
1258 | 0 | if (ngx_cmp_sockaddr(lsopt->sockaddr, lsopt->socklen, |
1259 | 0 | addr[i].opt.sockaddr, |
1260 | 0 | addr[i].opt.socklen, 0) |
1261 | 0 | != NGX_OK) |
1262 | 0 | { |
1263 | 0 | continue; |
1264 | 0 | } |
1265 | | |
1266 | | /* the address is already in the address list */ |
1267 | | |
1268 | 0 | if (ngx_http_add_server(cf, cscf, &addr[i]) != NGX_OK) { |
1269 | 0 | return NGX_ERROR; |
1270 | 0 | } |
1271 | | |
1272 | | /* preserve default_server bit during listen options overwriting */ |
1273 | 0 | default_server = addr[i].opt.default_server; |
1274 | |
|
1275 | 0 | proxy_protocol = lsopt->proxy_protocol || addr[i].opt.proxy_protocol; |
1276 | 0 | protocols = lsopt->proxy_protocol; |
1277 | 0 | protocols_prev = addr[i].opt.proxy_protocol; |
1278 | |
|
1279 | | #if (NGX_HTTP_SSL) |
1280 | | ssl = lsopt->ssl || addr[i].opt.ssl; |
1281 | | protocols |= lsopt->ssl << 1; |
1282 | | protocols_prev |= addr[i].opt.ssl << 1; |
1283 | | #endif |
1284 | 0 | #if (NGX_HTTP_V2) |
1285 | 0 | http2 = lsopt->http2 || addr[i].opt.http2; |
1286 | 0 | protocols |= lsopt->http2 << 2; |
1287 | 0 | protocols_prev |= addr[i].opt.http2 << 2; |
1288 | 0 | #endif |
1289 | | #if (NGX_HTTP_V3) |
1290 | | quic = lsopt->quic || addr[i].opt.quic; |
1291 | | #endif |
1292 | |
|
1293 | 0 | if (lsopt->set) { |
1294 | |
|
1295 | 0 | if (addr[i].opt.set) { |
1296 | 0 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
1297 | 0 | "duplicate listen options for %V", |
1298 | 0 | &addr[i].opt.addr_text); |
1299 | 0 | return NGX_ERROR; |
1300 | 0 | } |
1301 | | |
1302 | 0 | addr[i].opt = *lsopt; |
1303 | 0 | } |
1304 | | |
1305 | | /* check the duplicate "default" server for this address:port */ |
1306 | | |
1307 | 0 | if (lsopt->default_server) { |
1308 | |
|
1309 | 0 | if (default_server) { |
1310 | 0 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
1311 | 0 | "a duplicate default server for %V", |
1312 | 0 | &addr[i].opt.addr_text); |
1313 | 0 | return NGX_ERROR; |
1314 | 0 | } |
1315 | | |
1316 | 0 | default_server = 1; |
1317 | 0 | addr[i].default_server = cscf; |
1318 | 0 | } |
1319 | | |
1320 | | /* check for conflicting protocol options */ |
1321 | | |
1322 | 0 | if ((protocols | protocols_prev) != protocols_prev) { |
1323 | | |
1324 | | /* options added */ |
1325 | |
|
1326 | 0 | if ((addr[i].opt.set && !lsopt->set) |
1327 | 0 | || addr[i].protocols_changed |
1328 | 0 | || (protocols | protocols_prev) != protocols) |
1329 | 0 | { |
1330 | 0 | ngx_conf_log_error(NGX_LOG_WARN, cf, 0, |
1331 | 0 | "protocol options redefined for %V", |
1332 | 0 | &addr[i].opt.addr_text); |
1333 | 0 | } |
1334 | |
|
1335 | 0 | addr[i].protocols = protocols_prev; |
1336 | 0 | addr[i].protocols_set = 1; |
1337 | 0 | addr[i].protocols_changed = 1; |
1338 | |
|
1339 | 0 | } else if ((protocols_prev | protocols) != protocols) { |
1340 | | |
1341 | | /* options removed */ |
1342 | |
|
1343 | 0 | if (lsopt->set |
1344 | 0 | || (addr[i].protocols_set && protocols != addr[i].protocols)) |
1345 | 0 | { |
1346 | 0 | ngx_conf_log_error(NGX_LOG_WARN, cf, 0, |
1347 | 0 | "protocol options redefined for %V", |
1348 | 0 | &addr[i].opt.addr_text); |
1349 | 0 | } |
1350 | |
|
1351 | 0 | addr[i].protocols = protocols; |
1352 | 0 | addr[i].protocols_set = 1; |
1353 | 0 | addr[i].protocols_changed = 1; |
1354 | |
|
1355 | 0 | } else { |
1356 | | |
1357 | | /* the same options */ |
1358 | |
|
1359 | 0 | if ((lsopt->set && addr[i].protocols_changed) |
1360 | 0 | || (addr[i].protocols_set && protocols != addr[i].protocols)) |
1361 | 0 | { |
1362 | 0 | ngx_conf_log_error(NGX_LOG_WARN, cf, 0, |
1363 | 0 | "protocol options redefined for %V", |
1364 | 0 | &addr[i].opt.addr_text); |
1365 | 0 | } |
1366 | |
|
1367 | 0 | addr[i].protocols = protocols; |
1368 | 0 | addr[i].protocols_set = 1; |
1369 | 0 | } |
1370 | |
|
1371 | 0 | addr[i].opt.default_server = default_server; |
1372 | 0 | addr[i].opt.proxy_protocol = proxy_protocol; |
1373 | | #if (NGX_HTTP_SSL) |
1374 | | addr[i].opt.ssl = ssl; |
1375 | | #endif |
1376 | 0 | #if (NGX_HTTP_V2) |
1377 | 0 | addr[i].opt.http2 = http2; |
1378 | 0 | #endif |
1379 | | #if (NGX_HTTP_V3) |
1380 | | addr[i].opt.quic = quic; |
1381 | | #endif |
1382 | |
|
1383 | 0 | return NGX_OK; |
1384 | 0 | } |
1385 | | |
1386 | | /* add the address to the addresses list that bound to this port */ |
1387 | | |
1388 | 0 | return ngx_http_add_address(cf, cscf, port, lsopt); |
1389 | 0 | } |
1390 | | |
1391 | | |
1392 | | /* |
1393 | | * add the server address, the server names and the server core module |
1394 | | * configurations to the port list |
1395 | | */ |
1396 | | |
1397 | | static ngx_int_t |
1398 | | ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, |
1399 | | ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt) |
1400 | 1 | { |
1401 | 1 | ngx_http_conf_addr_t *addr; |
1402 | | |
1403 | 1 | if (port->addrs.elts == NULL) { |
1404 | 1 | if (ngx_array_init(&port->addrs, cf->temp_pool, 4, |
1405 | 1 | sizeof(ngx_http_conf_addr_t)) |
1406 | 1 | != NGX_OK) |
1407 | 0 | { |
1408 | 0 | return NGX_ERROR; |
1409 | 0 | } |
1410 | 1 | } |
1411 | | |
1412 | | #if (NGX_HTTP_V2 && NGX_HTTP_SSL \ |
1413 | | && !defined TLSEXT_TYPE_application_layer_protocol_negotiation) |
1414 | | |
1415 | | if (lsopt->http2 && lsopt->ssl) { |
1416 | | ngx_conf_log_error(NGX_LOG_WARN, cf, 0, |
1417 | | "nginx was built with OpenSSL that lacks ALPN " |
1418 | | "support, HTTP/2 is not enabled for %V", |
1419 | | &lsopt->addr_text); |
1420 | | } |
1421 | | |
1422 | | #endif |
1423 | | |
1424 | 1 | addr = ngx_array_push(&port->addrs); |
1425 | 1 | if (addr == NULL) { |
1426 | 0 | return NGX_ERROR; |
1427 | 0 | } |
1428 | | |
1429 | 1 | addr->opt = *lsopt; |
1430 | 1 | addr->protocols = 0; |
1431 | 1 | addr->protocols_set = 0; |
1432 | 1 | addr->protocols_changed = 0; |
1433 | 1 | addr->hash.buckets = NULL; |
1434 | 1 | addr->hash.size = 0; |
1435 | 1 | addr->wc_head = NULL; |
1436 | 1 | addr->wc_tail = NULL; |
1437 | 1 | #if (NGX_PCRE) |
1438 | 1 | addr->nregex = 0; |
1439 | 1 | addr->regex = NULL; |
1440 | 1 | #endif |
1441 | 1 | addr->default_server = cscf; |
1442 | 1 | addr->servers.elts = NULL; |
1443 | | |
1444 | 1 | return ngx_http_add_server(cf, cscf, addr); |
1445 | 1 | } |
1446 | | |
1447 | | |
1448 | | /* add the server core module configuration to the address:port */ |
1449 | | |
1450 | | static ngx_int_t |
1451 | | ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, |
1452 | | ngx_http_conf_addr_t *addr) |
1453 | 1 | { |
1454 | 1 | ngx_uint_t i; |
1455 | 1 | ngx_http_core_srv_conf_t **server; |
1456 | | |
1457 | 1 | if (addr->servers.elts == NULL) { |
1458 | 1 | if (ngx_array_init(&addr->servers, cf->temp_pool, 4, |
1459 | 1 | sizeof(ngx_http_core_srv_conf_t *)) |
1460 | 1 | != NGX_OK) |
1461 | 0 | { |
1462 | 0 | return NGX_ERROR; |
1463 | 0 | } |
1464 | | |
1465 | 1 | } else { |
1466 | 0 | server = addr->servers.elts; |
1467 | 0 | for (i = 0; i < addr->servers.nelts; i++) { |
1468 | 0 | if (server[i] == cscf) { |
1469 | 0 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
1470 | 0 | "a duplicate listen %V", |
1471 | 0 | &addr->opt.addr_text); |
1472 | 0 | return NGX_ERROR; |
1473 | 0 | } |
1474 | 0 | } |
1475 | 0 | } |
1476 | | |
1477 | 1 | server = ngx_array_push(&addr->servers); |
1478 | 1 | if (server == NULL) { |
1479 | 0 | return NGX_ERROR; |
1480 | 0 | } |
1481 | | |
1482 | 1 | *server = cscf; |
1483 | | |
1484 | 1 | return NGX_OK; |
1485 | 1 | } |
1486 | | |
1487 | | |
1488 | | static ngx_int_t |
1489 | | ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, |
1490 | | ngx_array_t *ports) |
1491 | 1 | { |
1492 | 1 | ngx_uint_t p, a; |
1493 | 1 | ngx_http_conf_port_t *port; |
1494 | 1 | ngx_http_conf_addr_t *addr; |
1495 | | |
1496 | 1 | if (ports == NULL) { |
1497 | 0 | return NGX_OK; |
1498 | 0 | } |
1499 | | |
1500 | 1 | port = ports->elts; |
1501 | 2 | for (p = 0; p < ports->nelts; p++) { |
1502 | | |
1503 | 1 | ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts, |
1504 | 1 | sizeof(ngx_http_conf_addr_t), ngx_http_cmp_conf_addrs); |
1505 | | |
1506 | | /* |
1507 | | * check whether all name-based servers have the same |
1508 | | * configuration as a default server for given address:port |
1509 | | */ |
1510 | | |
1511 | 1 | addr = port[p].addrs.elts; |
1512 | 2 | for (a = 0; a < port[p].addrs.nelts; a++) { |
1513 | | |
1514 | 1 | if (addr[a].servers.nelts > 1 |
1515 | 1 | #if (NGX_PCRE) |
1516 | 1 | || addr[a].default_server->captures |
1517 | 1 | #endif |
1518 | 1 | ) |
1519 | 1 | { |
1520 | 1 | if (ngx_http_server_names(cf, cmcf, &addr[a]) != NGX_OK) { |
1521 | 0 | return NGX_ERROR; |
1522 | 0 | } |
1523 | 1 | } |
1524 | 1 | } |
1525 | | |
1526 | 1 | if (ngx_http_init_listening(cf, &port[p]) != NGX_OK) { |
1527 | 0 | return NGX_ERROR; |
1528 | 0 | } |
1529 | 1 | } |
1530 | | |
1531 | 1 | return NGX_OK; |
1532 | 1 | } |
1533 | | |
1534 | | |
1535 | | static ngx_int_t |
1536 | | ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, |
1537 | | ngx_http_conf_addr_t *addr) |
1538 | 1 | { |
1539 | 1 | ngx_int_t rc; |
1540 | 1 | ngx_uint_t n, s; |
1541 | 1 | ngx_hash_init_t hash; |
1542 | 1 | ngx_hash_keys_arrays_t ha; |
1543 | 1 | ngx_http_server_name_t *name; |
1544 | 1 | ngx_http_core_srv_conf_t **cscfp; |
1545 | 1 | #if (NGX_PCRE) |
1546 | 1 | ngx_uint_t regex, i; |
1547 | | |
1548 | 1 | regex = 0; |
1549 | 1 | #endif |
1550 | | |
1551 | 1 | ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t)); |
1552 | | |
1553 | 1 | ha.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log); |
1554 | 1 | if (ha.temp_pool == NULL) { |
1555 | 0 | return NGX_ERROR; |
1556 | 0 | } |
1557 | | |
1558 | 1 | ha.pool = cf->pool; |
1559 | | |
1560 | 1 | if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) { |
1561 | 0 | goto failed; |
1562 | 0 | } |
1563 | | |
1564 | 1 | cscfp = addr->servers.elts; |
1565 | | |
1566 | 2 | for (s = 0; s < addr->servers.nelts; s++) { |
1567 | | |
1568 | 1 | name = cscfp[s]->server_names.elts; |
1569 | | |
1570 | 2 | for (n = 0; n < cscfp[s]->server_names.nelts; n++) { |
1571 | | |
1572 | 1 | #if (NGX_PCRE) |
1573 | 1 | if (name[n].regex) { |
1574 | 1 | regex++; |
1575 | 1 | continue; |
1576 | 1 | } |
1577 | 0 | #endif |
1578 | | |
1579 | 0 | rc = ngx_hash_add_key(&ha, &name[n].name, name[n].server, |
1580 | 0 | NGX_HASH_WILDCARD_KEY); |
1581 | |
|
1582 | 0 | if (rc == NGX_ERROR) { |
1583 | 0 | goto failed; |
1584 | 0 | } |
1585 | | |
1586 | 0 | if (rc == NGX_DECLINED) { |
1587 | 0 | ngx_log_error(NGX_LOG_EMERG, cf->log, 0, |
1588 | 0 | "invalid server name or wildcard \"%V\" on %V", |
1589 | 0 | &name[n].name, &addr->opt.addr_text); |
1590 | 0 | goto failed; |
1591 | 0 | } |
1592 | | |
1593 | 0 | if (rc == NGX_BUSY) { |
1594 | 0 | ngx_log_error(NGX_LOG_WARN, cf->log, 0, |
1595 | 0 | "conflicting server name \"%V\" on %V, ignored", |
1596 | 0 | &name[n].name, &addr->opt.addr_text); |
1597 | 0 | } |
1598 | 0 | } |
1599 | 1 | } |
1600 | | |
1601 | 1 | hash.key = ngx_hash_key_lc; |
1602 | 1 | hash.max_size = cmcf->server_names_hash_max_size; |
1603 | 1 | hash.bucket_size = cmcf->server_names_hash_bucket_size; |
1604 | 1 | hash.name = "server_names_hash"; |
1605 | 1 | hash.pool = cf->pool; |
1606 | | |
1607 | 1 | if (ha.keys.nelts) { |
1608 | 0 | hash.hash = &addr->hash; |
1609 | 0 | hash.temp_pool = NULL; |
1610 | |
|
1611 | 0 | if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) { |
1612 | 0 | goto failed; |
1613 | 0 | } |
1614 | 0 | } |
1615 | | |
1616 | 1 | if (ha.dns_wc_head.nelts) { |
1617 | |
|
1618 | 0 | ngx_qsort(ha.dns_wc_head.elts, (size_t) ha.dns_wc_head.nelts, |
1619 | 0 | sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards); |
1620 | |
|
1621 | 0 | hash.hash = NULL; |
1622 | 0 | hash.temp_pool = ha.temp_pool; |
1623 | |
|
1624 | 0 | if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts, |
1625 | 0 | ha.dns_wc_head.nelts) |
1626 | 0 | != NGX_OK) |
1627 | 0 | { |
1628 | 0 | goto failed; |
1629 | 0 | } |
1630 | | |
1631 | 0 | addr->wc_head = (ngx_hash_wildcard_t *) hash.hash; |
1632 | 0 | } |
1633 | | |
1634 | 1 | if (ha.dns_wc_tail.nelts) { |
1635 | |
|
1636 | 0 | ngx_qsort(ha.dns_wc_tail.elts, (size_t) ha.dns_wc_tail.nelts, |
1637 | 0 | sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards); |
1638 | |
|
1639 | 0 | hash.hash = NULL; |
1640 | 0 | hash.temp_pool = ha.temp_pool; |
1641 | |
|
1642 | 0 | if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts, |
1643 | 0 | ha.dns_wc_tail.nelts) |
1644 | 0 | != NGX_OK) |
1645 | 0 | { |
1646 | 0 | goto failed; |
1647 | 0 | } |
1648 | | |
1649 | 0 | addr->wc_tail = (ngx_hash_wildcard_t *) hash.hash; |
1650 | 0 | } |
1651 | | |
1652 | 1 | ngx_destroy_pool(ha.temp_pool); |
1653 | | |
1654 | 1 | #if (NGX_PCRE) |
1655 | | |
1656 | 1 | if (regex == 0) { |
1657 | 0 | return NGX_OK; |
1658 | 0 | } |
1659 | | |
1660 | 1 | addr->nregex = regex; |
1661 | 1 | addr->regex = ngx_palloc(cf->pool, regex * sizeof(ngx_http_server_name_t)); |
1662 | 1 | if (addr->regex == NULL) { |
1663 | 0 | return NGX_ERROR; |
1664 | 0 | } |
1665 | | |
1666 | 1 | i = 0; |
1667 | | |
1668 | 2 | for (s = 0; s < addr->servers.nelts; s++) { |
1669 | | |
1670 | 1 | name = cscfp[s]->server_names.elts; |
1671 | | |
1672 | 2 | for (n = 0; n < cscfp[s]->server_names.nelts; n++) { |
1673 | 1 | if (name[n].regex) { |
1674 | 1 | addr->regex[i++] = name[n]; |
1675 | 1 | } |
1676 | 1 | } |
1677 | 1 | } |
1678 | | |
1679 | 1 | #endif |
1680 | | |
1681 | 1 | return NGX_OK; |
1682 | | |
1683 | 0 | failed: |
1684 | |
|
1685 | 0 | ngx_destroy_pool(ha.temp_pool); |
1686 | |
|
1687 | 0 | return NGX_ERROR; |
1688 | 1 | } |
1689 | | |
1690 | | |
1691 | | static ngx_int_t |
1692 | | ngx_http_cmp_conf_addrs(const void *one, const void *two) |
1693 | 0 | { |
1694 | 0 | ngx_http_conf_addr_t *first, *second; |
1695 | |
|
1696 | 0 | first = (ngx_http_conf_addr_t *) one; |
1697 | 0 | second = (ngx_http_conf_addr_t *) two; |
1698 | |
|
1699 | 0 | if (first->opt.wildcard) { |
1700 | | /* a wildcard address must be the last resort, shift it to the end */ |
1701 | 0 | return 1; |
1702 | 0 | } |
1703 | | |
1704 | 0 | if (second->opt.wildcard) { |
1705 | | /* a wildcard address must be the last resort, shift it to the end */ |
1706 | 0 | return -1; |
1707 | 0 | } |
1708 | | |
1709 | 0 | if (first->opt.bind && !second->opt.bind) { |
1710 | | /* shift explicit bind()ed addresses to the start */ |
1711 | 0 | return -1; |
1712 | 0 | } |
1713 | | |
1714 | 0 | if (!first->opt.bind && second->opt.bind) { |
1715 | | /* shift explicit bind()ed addresses to the start */ |
1716 | 0 | return 1; |
1717 | 0 | } |
1718 | | |
1719 | | /* do not sort by default */ |
1720 | | |
1721 | 0 | return 0; |
1722 | 0 | } |
1723 | | |
1724 | | |
1725 | | static int ngx_libc_cdecl |
1726 | | ngx_http_cmp_dns_wildcards(const void *one, const void *two) |
1727 | 0 | { |
1728 | 0 | ngx_hash_key_t *first, *second; |
1729 | |
|
1730 | 0 | first = (ngx_hash_key_t *) one; |
1731 | 0 | second = (ngx_hash_key_t *) two; |
1732 | |
|
1733 | 0 | return ngx_dns_strcmp(first->key.data, second->key.data); |
1734 | 0 | } |
1735 | | |
1736 | | |
1737 | | static ngx_int_t |
1738 | | ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port) |
1739 | 1 | { |
1740 | 1 | ngx_uint_t i, last, bind_wildcard; |
1741 | 1 | ngx_listening_t *ls; |
1742 | 1 | ngx_http_port_t *hport; |
1743 | 1 | ngx_http_conf_addr_t *addr; |
1744 | | |
1745 | 1 | addr = port->addrs.elts; |
1746 | 1 | last = port->addrs.nelts; |
1747 | | |
1748 | | /* |
1749 | | * If there is a binding to an "*:port" then we need to bind() to |
1750 | | * the "*:port" only and ignore other implicit bindings. The bindings |
1751 | | * have been already sorted: explicit bindings are on the start, then |
1752 | | * implicit bindings go, and wildcard binding is in the end. |
1753 | | */ |
1754 | | |
1755 | 1 | if (addr[last - 1].opt.wildcard) { |
1756 | 0 | addr[last - 1].opt.bind = 1; |
1757 | 0 | bind_wildcard = 1; |
1758 | |
|
1759 | 1 | } else { |
1760 | 1 | bind_wildcard = 0; |
1761 | 1 | } |
1762 | | |
1763 | 1 | i = 0; |
1764 | | |
1765 | 2 | while (i < last) { |
1766 | | |
1767 | 1 | if (bind_wildcard && !addr[i].opt.bind) { |
1768 | 0 | i++; |
1769 | 0 | continue; |
1770 | 0 | } |
1771 | | |
1772 | 1 | ls = ngx_http_add_listening(cf, &addr[i]); |
1773 | 1 | if (ls == NULL) { |
1774 | 0 | return NGX_ERROR; |
1775 | 0 | } |
1776 | | |
1777 | 1 | hport = ngx_pcalloc(cf->pool, sizeof(ngx_http_port_t)); |
1778 | 1 | if (hport == NULL) { |
1779 | 0 | return NGX_ERROR; |
1780 | 0 | } |
1781 | | |
1782 | 1 | ls->servers = hport; |
1783 | | |
1784 | 1 | hport->naddrs = i + 1; |
1785 | | |
1786 | 1 | switch (ls->sockaddr->sa_family) { |
1787 | | |
1788 | 0 | #if (NGX_HAVE_INET6) |
1789 | 0 | case AF_INET6: |
1790 | 0 | if (ngx_http_add_addrs6(cf, hport, addr) != NGX_OK) { |
1791 | 0 | return NGX_ERROR; |
1792 | 0 | } |
1793 | 0 | break; |
1794 | 0 | #endif |
1795 | 1 | default: /* AF_INET */ |
1796 | 1 | if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) { |
1797 | 0 | return NGX_ERROR; |
1798 | 0 | } |
1799 | 1 | break; |
1800 | 1 | } |
1801 | | |
1802 | 1 | addr++; |
1803 | 1 | last--; |
1804 | 1 | } |
1805 | | |
1806 | 1 | return NGX_OK; |
1807 | 1 | } |
1808 | | |
1809 | | |
1810 | | static ngx_listening_t * |
1811 | | ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) |
1812 | 1 | { |
1813 | 1 | ngx_listening_t *ls; |
1814 | 1 | ngx_http_core_loc_conf_t *clcf; |
1815 | 1 | ngx_http_core_srv_conf_t *cscf; |
1816 | | |
1817 | 1 | ls = ngx_create_listening(cf, addr->opt.sockaddr, addr->opt.socklen); |
1818 | 1 | if (ls == NULL) { |
1819 | 0 | return NULL; |
1820 | 0 | } |
1821 | | |
1822 | 1 | ls->addr_ntop = 1; |
1823 | | |
1824 | 1 | ls->handler = ngx_http_init_connection; |
1825 | | |
1826 | 1 | cscf = addr->default_server; |
1827 | 1 | ls->pool_size = cscf->connection_pool_size; |
1828 | | |
1829 | 1 | clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; |
1830 | | |
1831 | 1 | ls->logp = clcf->error_log; |
1832 | 1 | ls->log.data = &ls->addr_text; |
1833 | 1 | ls->log.handler = ngx_accept_log_error; |
1834 | | |
1835 | | #if (NGX_WIN32) |
1836 | | { |
1837 | | ngx_iocp_conf_t *iocpcf = NULL; |
1838 | | |
1839 | | if (ngx_get_conf(cf->cycle->conf_ctx, ngx_events_module)) { |
1840 | | iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module); |
1841 | | } |
1842 | | if (iocpcf && iocpcf->acceptex_read) { |
1843 | | ls->post_accept_buffer_size = cscf->client_header_buffer_size; |
1844 | | } |
1845 | | } |
1846 | | #endif |
1847 | | |
1848 | 1 | ls->type = addr->opt.type; |
1849 | 1 | ls->protocol = addr->opt.protocol; |
1850 | 1 | ls->backlog = addr->opt.backlog; |
1851 | 1 | ls->rcvbuf = addr->opt.rcvbuf; |
1852 | 1 | ls->sndbuf = addr->opt.sndbuf; |
1853 | | |
1854 | 1 | ls->keepalive = addr->opt.so_keepalive; |
1855 | | #if (NGX_HAVE_KEEPALIVE_TUNABLE) |
1856 | | ls->keepidle = addr->opt.tcp_keepidle; |
1857 | | ls->keepintvl = addr->opt.tcp_keepintvl; |
1858 | | ls->keepcnt = addr->opt.tcp_keepcnt; |
1859 | | #endif |
1860 | | |
1861 | | #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) |
1862 | | ls->accept_filter = addr->opt.accept_filter; |
1863 | | #endif |
1864 | | |
1865 | | #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) |
1866 | | ls->deferred_accept = addr->opt.deferred_accept; |
1867 | | #endif |
1868 | | |
1869 | 1 | #if (NGX_HAVE_INET6) |
1870 | 1 | ls->ipv6only = addr->opt.ipv6only; |
1871 | 1 | #endif |
1872 | | |
1873 | | #if (NGX_HAVE_SETFIB) |
1874 | | ls->setfib = addr->opt.setfib; |
1875 | | #endif |
1876 | | |
1877 | | #if (NGX_HAVE_TCP_FASTOPEN) |
1878 | | ls->fastopen = addr->opt.fastopen; |
1879 | | #endif |
1880 | | |
1881 | | #if (NGX_HAVE_REUSEPORT) |
1882 | | ls->reuseport = addr->opt.reuseport; |
1883 | | #endif |
1884 | | |
1885 | 1 | ls->wildcard = addr->opt.wildcard; |
1886 | | |
1887 | | #if (NGX_HTTP_V3) |
1888 | | ls->quic = addr->opt.quic; |
1889 | | #endif |
1890 | | |
1891 | 1 | return ls; |
1892 | 1 | } |
1893 | | |
1894 | | |
1895 | | static ngx_int_t |
1896 | | ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport, |
1897 | | ngx_http_conf_addr_t *addr) |
1898 | 1 | { |
1899 | 1 | ngx_uint_t i; |
1900 | 1 | ngx_http_in_addr_t *addrs; |
1901 | 1 | struct sockaddr_in *sin; |
1902 | 1 | ngx_http_virtual_names_t *vn; |
1903 | | |
1904 | 1 | hport->addrs = ngx_pcalloc(cf->pool, |
1905 | 1 | hport->naddrs * sizeof(ngx_http_in_addr_t)); |
1906 | 1 | if (hport->addrs == NULL) { |
1907 | 0 | return NGX_ERROR; |
1908 | 0 | } |
1909 | | |
1910 | 1 | addrs = hport->addrs; |
1911 | | |
1912 | 2 | for (i = 0; i < hport->naddrs; i++) { |
1913 | | |
1914 | 1 | sin = (struct sockaddr_in *) addr[i].opt.sockaddr; |
1915 | 1 | addrs[i].addr = sin->sin_addr.s_addr; |
1916 | 1 | addrs[i].conf.default_server = addr[i].default_server; |
1917 | | #if (NGX_HTTP_SSL) |
1918 | | addrs[i].conf.ssl = addr[i].opt.ssl; |
1919 | | #endif |
1920 | 1 | #if (NGX_HTTP_V2) |
1921 | 1 | addrs[i].conf.http2 = addr[i].opt.http2; |
1922 | 1 | #endif |
1923 | | #if (NGX_HTTP_V3) |
1924 | | addrs[i].conf.quic = addr[i].opt.quic; |
1925 | | #endif |
1926 | 1 | addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; |
1927 | | |
1928 | 1 | if (addr[i].hash.buckets == NULL |
1929 | 1 | && (addr[i].wc_head == NULL |
1930 | 0 | || addr[i].wc_head->hash.buckets == NULL) |
1931 | 1 | && (addr[i].wc_tail == NULL |
1932 | 0 | || addr[i].wc_tail->hash.buckets == NULL) |
1933 | 1 | #if (NGX_PCRE) |
1934 | 1 | && addr[i].nregex == 0 |
1935 | 1 | #endif |
1936 | 1 | ) |
1937 | 0 | { |
1938 | 0 | continue; |
1939 | 0 | } |
1940 | | |
1941 | 1 | vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t)); |
1942 | 1 | if (vn == NULL) { |
1943 | 0 | return NGX_ERROR; |
1944 | 0 | } |
1945 | | |
1946 | 1 | addrs[i].conf.virtual_names = vn; |
1947 | | |
1948 | 1 | vn->names.hash = addr[i].hash; |
1949 | 1 | vn->names.wc_head = addr[i].wc_head; |
1950 | 1 | vn->names.wc_tail = addr[i].wc_tail; |
1951 | 1 | #if (NGX_PCRE) |
1952 | 1 | vn->nregex = addr[i].nregex; |
1953 | 1 | vn->regex = addr[i].regex; |
1954 | 1 | #endif |
1955 | 1 | } |
1956 | | |
1957 | 1 | return NGX_OK; |
1958 | 1 | } |
1959 | | |
1960 | | |
1961 | | #if (NGX_HAVE_INET6) |
1962 | | |
1963 | | static ngx_int_t |
1964 | | ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport, |
1965 | | ngx_http_conf_addr_t *addr) |
1966 | 0 | { |
1967 | 0 | ngx_uint_t i; |
1968 | 0 | ngx_http_in6_addr_t *addrs6; |
1969 | 0 | struct sockaddr_in6 *sin6; |
1970 | 0 | ngx_http_virtual_names_t *vn; |
1971 | |
|
1972 | 0 | hport->addrs = ngx_pcalloc(cf->pool, |
1973 | 0 | hport->naddrs * sizeof(ngx_http_in6_addr_t)); |
1974 | 0 | if (hport->addrs == NULL) { |
1975 | 0 | return NGX_ERROR; |
1976 | 0 | } |
1977 | | |
1978 | 0 | addrs6 = hport->addrs; |
1979 | |
|
1980 | 0 | for (i = 0; i < hport->naddrs; i++) { |
1981 | |
|
1982 | 0 | sin6 = (struct sockaddr_in6 *) addr[i].opt.sockaddr; |
1983 | 0 | addrs6[i].addr6 = sin6->sin6_addr; |
1984 | 0 | addrs6[i].conf.default_server = addr[i].default_server; |
1985 | | #if (NGX_HTTP_SSL) |
1986 | | addrs6[i].conf.ssl = addr[i].opt.ssl; |
1987 | | #endif |
1988 | 0 | #if (NGX_HTTP_V2) |
1989 | 0 | addrs6[i].conf.http2 = addr[i].opt.http2; |
1990 | 0 | #endif |
1991 | | #if (NGX_HTTP_V3) |
1992 | | addrs6[i].conf.quic = addr[i].opt.quic; |
1993 | | #endif |
1994 | 0 | addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol; |
1995 | |
|
1996 | 0 | if (addr[i].hash.buckets == NULL |
1997 | 0 | && (addr[i].wc_head == NULL |
1998 | 0 | || addr[i].wc_head->hash.buckets == NULL) |
1999 | 0 | && (addr[i].wc_tail == NULL |
2000 | 0 | || addr[i].wc_tail->hash.buckets == NULL) |
2001 | 0 | #if (NGX_PCRE) |
2002 | 0 | && addr[i].nregex == 0 |
2003 | 0 | #endif |
2004 | 0 | ) |
2005 | 0 | { |
2006 | 0 | continue; |
2007 | 0 | } |
2008 | | |
2009 | 0 | vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t)); |
2010 | 0 | if (vn == NULL) { |
2011 | 0 | return NGX_ERROR; |
2012 | 0 | } |
2013 | | |
2014 | 0 | addrs6[i].conf.virtual_names = vn; |
2015 | |
|
2016 | 0 | vn->names.hash = addr[i].hash; |
2017 | 0 | vn->names.wc_head = addr[i].wc_head; |
2018 | 0 | vn->names.wc_tail = addr[i].wc_tail; |
2019 | 0 | #if (NGX_PCRE) |
2020 | 0 | vn->nregex = addr[i].nregex; |
2021 | 0 | vn->regex = addr[i].regex; |
2022 | 0 | #endif |
2023 | 0 | } |
2024 | | |
2025 | 0 | return NGX_OK; |
2026 | 0 | } |
2027 | | |
2028 | | #endif |
2029 | | |
2030 | | |
2031 | | char * |
2032 | | ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
2033 | 0 | { |
2034 | 0 | char *p = conf; |
2035 | |
|
2036 | 0 | ngx_array_t **types; |
2037 | 0 | ngx_str_t *value, *default_type; |
2038 | 0 | ngx_uint_t i, n, hash; |
2039 | 0 | ngx_hash_key_t *type; |
2040 | |
|
2041 | 0 | types = (ngx_array_t **) (p + cmd->offset); |
2042 | |
|
2043 | 0 | if (*types == (void *) -1) { |
2044 | 0 | return NGX_CONF_OK; |
2045 | 0 | } |
2046 | | |
2047 | 0 | default_type = cmd->post; |
2048 | |
|
2049 | 0 | if (*types == NULL) { |
2050 | 0 | *types = ngx_array_create(cf->temp_pool, 1, sizeof(ngx_hash_key_t)); |
2051 | 0 | if (*types == NULL) { |
2052 | 0 | return NGX_CONF_ERROR; |
2053 | 0 | } |
2054 | | |
2055 | 0 | if (default_type) { |
2056 | 0 | type = ngx_array_push(*types); |
2057 | 0 | if (type == NULL) { |
2058 | 0 | return NGX_CONF_ERROR; |
2059 | 0 | } |
2060 | | |
2061 | 0 | type->key = *default_type; |
2062 | 0 | type->key_hash = ngx_hash_key(default_type->data, |
2063 | 0 | default_type->len); |
2064 | 0 | type->value = (void *) 4; |
2065 | 0 | } |
2066 | 0 | } |
2067 | | |
2068 | 0 | value = cf->args->elts; |
2069 | |
|
2070 | 0 | for (i = 1; i < cf->args->nelts; i++) { |
2071 | |
|
2072 | 0 | if (value[i].len == 1 && value[i].data[0] == '*') { |
2073 | 0 | *types = (void *) -1; |
2074 | 0 | return NGX_CONF_OK; |
2075 | 0 | } |
2076 | | |
2077 | 0 | hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len); |
2078 | 0 | value[i].data[value[i].len] = '\0'; |
2079 | |
|
2080 | 0 | type = (*types)->elts; |
2081 | 0 | for (n = 0; n < (*types)->nelts; n++) { |
2082 | |
|
2083 | 0 | if (ngx_strcmp(value[i].data, type[n].key.data) == 0) { |
2084 | 0 | ngx_conf_log_error(NGX_LOG_WARN, cf, 0, |
2085 | 0 | "duplicate MIME type \"%V\"", &value[i]); |
2086 | 0 | goto next; |
2087 | 0 | } |
2088 | 0 | } |
2089 | | |
2090 | 0 | type = ngx_array_push(*types); |
2091 | 0 | if (type == NULL) { |
2092 | 0 | return NGX_CONF_ERROR; |
2093 | 0 | } |
2094 | | |
2095 | 0 | type->key = value[i]; |
2096 | 0 | type->key_hash = hash; |
2097 | 0 | type->value = (void *) 4; |
2098 | |
|
2099 | 0 | next: |
2100 | |
|
2101 | 0 | continue; |
2102 | 0 | } |
2103 | | |
2104 | 0 | return NGX_CONF_OK; |
2105 | 0 | } |
2106 | | |
2107 | | |
2108 | | char * |
2109 | | ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t **keys, ngx_hash_t *types_hash, |
2110 | | ngx_array_t **prev_keys, ngx_hash_t *prev_types_hash, |
2111 | | ngx_str_t *default_types) |
2112 | 6 | { |
2113 | 6 | ngx_hash_init_t hash; |
2114 | | |
2115 | 6 | if (*keys) { |
2116 | |
|
2117 | 0 | if (*keys == (void *) -1) { |
2118 | 0 | return NGX_CONF_OK; |
2119 | 0 | } |
2120 | | |
2121 | 0 | hash.hash = types_hash; |
2122 | 0 | hash.key = NULL; |
2123 | 0 | hash.max_size = 2048; |
2124 | 0 | hash.bucket_size = 64; |
2125 | 0 | hash.name = "test_types_hash"; |
2126 | 0 | hash.pool = cf->pool; |
2127 | 0 | hash.temp_pool = NULL; |
2128 | |
|
2129 | 0 | if (ngx_hash_init(&hash, (*keys)->elts, (*keys)->nelts) != NGX_OK) { |
2130 | 0 | return NGX_CONF_ERROR; |
2131 | 0 | } |
2132 | | |
2133 | 0 | return NGX_CONF_OK; |
2134 | 0 | } |
2135 | | |
2136 | 6 | if (prev_types_hash->buckets == NULL) { |
2137 | | |
2138 | 3 | if (*prev_keys == NULL) { |
2139 | | |
2140 | 3 | if (ngx_http_set_default_types(cf, prev_keys, default_types) |
2141 | 3 | != NGX_OK) |
2142 | 0 | { |
2143 | 0 | return NGX_CONF_ERROR; |
2144 | 0 | } |
2145 | | |
2146 | 3 | } else if (*prev_keys == (void *) -1) { |
2147 | 0 | *keys = *prev_keys; |
2148 | 0 | return NGX_CONF_OK; |
2149 | 0 | } |
2150 | | |
2151 | 3 | hash.hash = prev_types_hash; |
2152 | 3 | hash.key = NULL; |
2153 | 3 | hash.max_size = 2048; |
2154 | 3 | hash.bucket_size = 64; |
2155 | 3 | hash.name = "test_types_hash"; |
2156 | 3 | hash.pool = cf->pool; |
2157 | 3 | hash.temp_pool = NULL; |
2158 | | |
2159 | 3 | if (ngx_hash_init(&hash, (*prev_keys)->elts, (*prev_keys)->nelts) |
2160 | 3 | != NGX_OK) |
2161 | 0 | { |
2162 | 0 | return NGX_CONF_ERROR; |
2163 | 0 | } |
2164 | 3 | } |
2165 | | |
2166 | 6 | *types_hash = *prev_types_hash; |
2167 | | |
2168 | 6 | return NGX_CONF_OK; |
2169 | | |
2170 | 6 | } |
2171 | | |
2172 | | |
2173 | | ngx_int_t |
2174 | | ngx_http_set_default_types(ngx_conf_t *cf, ngx_array_t **types, |
2175 | | ngx_str_t *default_type) |
2176 | 3 | { |
2177 | 3 | ngx_hash_key_t *type; |
2178 | | |
2179 | 3 | *types = ngx_array_create(cf->temp_pool, 1, sizeof(ngx_hash_key_t)); |
2180 | 3 | if (*types == NULL) { |
2181 | 0 | return NGX_ERROR; |
2182 | 0 | } |
2183 | | |
2184 | 11 | while (default_type->len) { |
2185 | | |
2186 | 8 | type = ngx_array_push(*types); |
2187 | 8 | if (type == NULL) { |
2188 | 0 | return NGX_ERROR; |
2189 | 0 | } |
2190 | | |
2191 | 8 | type->key = *default_type; |
2192 | 8 | type->key_hash = ngx_hash_key(default_type->data, |
2193 | 8 | default_type->len); |
2194 | 8 | type->value = (void *) 4; |
2195 | | |
2196 | 8 | default_type++; |
2197 | 8 | } |
2198 | | |
2199 | 3 | return NGX_OK; |
2200 | 3 | } |