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