comparison src/http/ngx_http.c @ 2027:f321b59ae0e9

locations tree
author Igor Sysoev <igor@sysoev.ru>
date Sat, 24 May 2008 14:14:13 +0000
parents 638bbe2464f3
children c036922f6f07
comparison
equal deleted inserted replaced
2026:72db8932f782 2027:f321b59ae0e9
25 ngx_http_listen_t *listen); 25 ngx_http_listen_t *listen);
26 static ngx_int_t ngx_http_add_names(ngx_conf_t *cf, 26 static ngx_int_t ngx_http_add_names(ngx_conf_t *cf,
27 ngx_http_core_srv_conf_t *cscf, ngx_http_conf_in_addr_t *in_addr); 27 ngx_http_core_srv_conf_t *cscf, ngx_http_conf_in_addr_t *in_addr);
28 28
29 static char *ngx_http_merge_locations(ngx_conf_t *cf, 29 static char *ngx_http_merge_locations(ngx_conf_t *cf,
30 ngx_array_t *locations, void **loc_conf, ngx_http_module_t *module, 30 ngx_queue_t *locations, void **loc_conf, ngx_http_module_t *module,
31 ngx_uint_t ctx_index); 31 ngx_uint_t ctx_index);
32 static ngx_int_t ngx_http_init_locations(ngx_conf_t *cf,
33 ngx_http_core_srv_conf_t *cscf, ngx_http_core_loc_conf_t *pclcf);
34 static ngx_int_t ngx_http_init_static_location_trees(ngx_conf_t *cf,
35 ngx_http_core_loc_conf_t *pclcf);
36 static ngx_int_t ngx_http_cmp_locations(const ngx_queue_t *one,
37 const ngx_queue_t *two);
38 static ngx_int_t ngx_http_join_exact_locations(ngx_conf_t *cf,
39 ngx_queue_t *locations);
40 static void ngx_http_create_locations_list(ngx_queue_t *locations,
41 ngx_queue_t *q);
42 static ngx_http_location_tree_node_t *
43 ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations,
44 size_t prefix);
32 45
33 static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf, 46 static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf,
34 ngx_http_core_main_conf_t *cmcf, ngx_array_t *in_ports); 47 ngx_http_core_main_conf_t *cmcf, ngx_array_t *in_ports);
35 static ngx_int_t ngx_http_cmp_conf_in_addrs(const void *one, const void *two); 48 static ngx_int_t ngx_http_cmp_conf_in_addrs(const void *one, const void *two);
36 static int ngx_libc_cdecl ngx_http_cmp_dns_wildcards(const void *one, 49 static int ngx_libc_cdecl ngx_http_cmp_dns_wildcards(const void *one,
89 ngx_uint_t mi, m, s; 102 ngx_uint_t mi, m, s;
90 ngx_conf_t pcf; 103 ngx_conf_t pcf;
91 ngx_array_t in_ports; 104 ngx_array_t in_ports;
92 ngx_http_module_t *module; 105 ngx_http_module_t *module;
93 ngx_http_conf_ctx_t *ctx; 106 ngx_http_conf_ctx_t *ctx;
107 ngx_http_core_loc_conf_t *clcf;
94 ngx_http_core_srv_conf_t **cscfp; 108 ngx_http_core_srv_conf_t **cscfp;
95 ngx_http_core_main_conf_t *cmcf; 109 ngx_http_core_main_conf_t *cmcf;
96 110
97 /* the main http context */ 111 /* the main http context */
98 112
204 cf->module_type = NGX_HTTP_MODULE; 218 cf->module_type = NGX_HTTP_MODULE;
205 cf->cmd_type = NGX_HTTP_MAIN_CONF; 219 cf->cmd_type = NGX_HTTP_MAIN_CONF;
206 rv = ngx_conf_parse(cf, NULL); 220 rv = ngx_conf_parse(cf, NULL);
207 221
208 if (rv != NGX_CONF_OK) { 222 if (rv != NGX_CONF_OK) {
209 *cf = pcf; 223 goto failed;
210 return rv;
211 } 224 }
212 225
213 /* 226 /*
214 * init http{} main_conf's, merge the server{}s' srv_conf's 227 * init http{} main_conf's, merge the server{}s' srv_conf's
215 * and its location{}s' loc_conf's 228 * and its location{}s' loc_conf's
229 /* init http{} main_conf's */ 242 /* init http{} main_conf's */
230 243
231 if (module->init_main_conf) { 244 if (module->init_main_conf) {
232 rv = module->init_main_conf(cf, ctx->main_conf[mi]); 245 rv = module->init_main_conf(cf, ctx->main_conf[mi]);
233 if (rv != NGX_CONF_OK) { 246 if (rv != NGX_CONF_OK) {
234 *cf = pcf; 247 goto failed;
235 return rv;
236 } 248 }
237 } 249 }
238 250
239 for (s = 0; s < cmcf->servers.nelts; s++) { 251 for (s = 0; s < cmcf->servers.nelts; s++) {
240 252
241 /* merge the server{}s' srv_conf's */ 253 /* merge the server{}s' srv_conf's */
242 254
243 if (module->merge_srv_conf) { 255 if (module->merge_srv_conf) {
244 rv = module->merge_srv_conf(cf, 256 rv = module->merge_srv_conf(cf, ctx->srv_conf[mi],
245 ctx->srv_conf[mi],
246 cscfp[s]->ctx->srv_conf[mi]); 257 cscfp[s]->ctx->srv_conf[mi]);
247 if (rv != NGX_CONF_OK) { 258 if (rv != NGX_CONF_OK) {
248 *cf = pcf; 259 goto failed;
249 return rv;
250 } 260 }
251 } 261 }
252 262
253 if (module->merge_loc_conf) { 263 if (module->merge_loc_conf) {
254 264
255 /* merge the server{}'s loc_conf */ 265 /* merge the server{}'s loc_conf */
256 266
257 rv = module->merge_loc_conf(cf, 267 rv = module->merge_loc_conf(cf, ctx->loc_conf[mi],
258 ctx->loc_conf[mi],
259 cscfp[s]->ctx->loc_conf[mi]); 268 cscfp[s]->ctx->loc_conf[mi]);
260 if (rv != NGX_CONF_OK) { 269 if (rv != NGX_CONF_OK) {
261 *cf = pcf; 270 goto failed;
262 return rv;
263 } 271 }
264 272
265 /* merge the locations{}' loc_conf's */ 273 /* merge the locations{}' loc_conf's */
266 274
267 rv = ngx_http_merge_locations(cf, &cscfp[s]->locations, 275 clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
276
277 rv = ngx_http_merge_locations(cf, clcf->locations,
268 cscfp[s]->ctx->loc_conf, 278 cscfp[s]->ctx->loc_conf,
269 module, mi); 279 module, mi);
270 if (rv != NGX_CONF_OK) { 280 if (rv != NGX_CONF_OK) {
271 *cf = pcf; 281 goto failed;
272 return rv;
273 } 282 }
274 } 283 }
284 }
285 }
286
287
288 /* create location trees */
289
290 for (s = 0; s < cmcf->servers.nelts; s++) {
291
292 clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
293
294 if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
295 return NGX_CONF_ERROR;
296 }
297
298 if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
299 return NGX_CONF_ERROR;
275 } 300 }
276 } 301 }
277 302
278 303
279 if (ngx_http_init_phases(cf, cmcf) != NGX_OK) { 304 if (ngx_http_init_phases(cf, cmcf) != NGX_OK) {
335 if (ngx_http_optimize_servers(cf, cmcf, &in_ports) != NGX_OK) { 360 if (ngx_http_optimize_servers(cf, cmcf, &in_ports) != NGX_OK) {
336 return NGX_CONF_ERROR; 361 return NGX_CONF_ERROR;
337 } 362 }
338 363
339 return NGX_CONF_OK; 364 return NGX_CONF_OK;
365
366 failed:
367
368 *cf = pcf;
369
370 return rv;
340 } 371 }
341 372
342 373
343 static ngx_int_t 374 static ngx_int_t
344 ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) 375 ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
539 ph++; 570 ph++;
540 } 571 }
541 } 572 }
542 573
543 return NGX_OK; 574 return NGX_OK;
575 }
576
577
578 static char *
579 ngx_http_merge_locations(ngx_conf_t *cf, ngx_queue_t *locations,
580 void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index)
581 {
582 char *rv;
583 ngx_queue_t *q;
584 ngx_http_core_loc_conf_t *clcf;
585 ngx_http_location_queue_t *lq;
586
587 if (locations == NULL) {
588 return NGX_CONF_OK;
589 }
590
591 for (q = ngx_queue_head(locations);
592 q != ngx_queue_sentinel(locations);
593 q = ngx_queue_next(q))
594 {
595 lq = (ngx_http_location_queue_t *) q;
596
597 clcf = lq->exact ? lq->exact : lq->inclusive;
598
599 rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
600 clcf->loc_conf[ctx_index]);
601 if (rv != NGX_CONF_OK) {
602 return rv;
603 }
604
605 rv = ngx_http_merge_locations(cf, clcf->locations, clcf->loc_conf,
606 module, ctx_index);
607 if (rv != NGX_CONF_OK) {
608 return rv;
609 }
610 }
611
612 return NGX_CONF_OK;
613 }
614
615
616 static ngx_int_t
617 ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
618 ngx_http_core_loc_conf_t *pclcf)
619 {
620 ngx_uint_t n;
621 ngx_queue_t *q, *locations, *named, tail;
622 ngx_http_core_loc_conf_t *clcf;
623 ngx_http_location_queue_t *lq;
624 ngx_http_core_loc_conf_t **clcfp;
625 #if (NGX_PCRE)
626 ngx_uint_t r;
627 ngx_queue_t *regex;
628 #endif
629
630 locations = pclcf->locations;
631
632 if (locations == NULL) {
633 return NGX_OK;
634 }
635
636 ngx_queue_sort(locations, ngx_http_cmp_locations);
637
638 named = NULL;
639 n = 0;
640 #if (NGX_PCRE)
641 regex = NULL;
642 r = 0;
643 #endif
644
645 for (q = ngx_queue_head(locations);
646 q != ngx_queue_sentinel(locations);
647 q = ngx_queue_next(q))
648 {
649 lq = (ngx_http_location_queue_t *) q;
650
651 clcf = lq->exact ? lq->exact : lq->inclusive;
652
653 if (ngx_http_init_locations(cf, NULL, clcf) != NGX_OK) {
654 return NGX_ERROR;
655 }
656
657 #if (NGX_PCRE)
658
659 if (clcf->regex) {
660 r++;
661
662 if (regex == NULL) {
663 regex = q;
664 }
665
666 continue;
667 }
668
669 #endif
670
671 if (clcf->named) {
672 n++;
673
674 if (named == NULL) {
675 named = q;
676 }
677
678 continue;
679 }
680
681 if (clcf->noname) {
682 break;
683 }
684 }
685
686 if (q != ngx_queue_sentinel(locations)) {
687 ngx_queue_split(locations, q, &tail);
688 }
689
690 if (named) {
691 clcfp = ngx_palloc(cf->pool,
692 (n + 1) * sizeof(ngx_http_core_loc_conf_t **));
693 if (clcfp == NULL) {
694 return NGX_ERROR;
695 }
696
697 cscf->named_locations = clcfp;
698
699 for (q = named;
700 q != ngx_queue_sentinel(locations);
701 q = ngx_queue_next(q))
702 {
703 lq = (ngx_http_location_queue_t *) q;
704
705 *(clcfp++) = lq->exact;
706 }
707
708 *clcfp = NULL;
709
710 ngx_queue_split(locations, named, &tail);
711 }
712
713 #if (NGX_PCRE)
714
715 if (regex) {
716
717 clcfp = ngx_palloc(cf->pool,
718 (r + 1) * sizeof(ngx_http_core_loc_conf_t **));
719 if (clcfp == NULL) {
720 return NGX_ERROR;
721 }
722
723 pclcf->regex_locations = clcfp;
724
725 for (q = regex;
726 q != ngx_queue_sentinel(locations);
727 q = ngx_queue_next(q))
728 {
729 lq = (ngx_http_location_queue_t *) q;
730
731 *(clcfp++) = lq->exact;
732 }
733
734 *clcfp = NULL;
735
736 ngx_queue_split(locations, regex, &tail);
737 }
738
739 #endif
740
741 return NGX_OK;
742 }
743
744
745 static ngx_int_t
746 ngx_http_init_static_location_trees(ngx_conf_t *cf,
747 ngx_http_core_loc_conf_t *pclcf)
748 {
749 ngx_queue_t *q, *locations;
750 ngx_http_core_loc_conf_t *clcf;
751 ngx_http_location_queue_t *lq;
752
753 locations = pclcf->locations;
754
755 if (locations == NULL) {
756 return NGX_OK;
757 }
758
759 if (ngx_queue_empty(locations)) {
760 return NGX_OK;
761 }
762
763 for (q = ngx_queue_head(locations);
764 q != ngx_queue_sentinel(locations);
765 q = ngx_queue_next(q))
766 {
767 lq = (ngx_http_location_queue_t *) q;
768
769 clcf = lq->exact ? lq->exact : lq->inclusive;
770
771 if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
772 return NGX_ERROR;
773 }
774 }
775
776 if (ngx_http_join_exact_locations(cf, locations) != NGX_OK) {
777 return NGX_ERROR;
778 }
779
780 ngx_http_create_locations_list(locations, ngx_queue_head(locations));
781
782 pclcf->static_locations = ngx_http_create_locations_tree(cf, locations, 0);
783 if (pclcf->static_locations == NULL) {
784 return NGX_ERROR;
785 }
786
787 return NGX_OK;
788 }
789
790
791 ngx_int_t
792 ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
793 ngx_http_core_loc_conf_t *clcf)
794 {
795 ngx_http_location_queue_t *lq;
796
797 if (*locations == NULL) {
798 *locations = ngx_palloc(cf->temp_pool,
799 sizeof(ngx_http_location_queue_t));
800 if (*locations == NULL) {
801 return NGX_ERROR;
802 }
803
804 ngx_queue_init(*locations);
805 }
806
807 lq = ngx_palloc(cf->temp_pool, sizeof(ngx_http_location_queue_t));
808 if (lq == NULL) {
809 return NGX_ERROR;
810 }
811
812 if (clcf->exact_match
813 #if (NGX_PCRE)
814 || clcf->regex
815 #endif
816 || clcf->named || clcf->noname)
817 {
818 lq->exact = clcf;
819 lq->inclusive = NULL;
820
821 } else {
822 lq->exact = NULL;
823 lq->inclusive = clcf;
824 }
825
826 lq->name = &clcf->name;
827 lq->file_name = cf->conf_file->file.name.data;
828 lq->line = cf->conf_file->line;
829
830 ngx_queue_init(&lq->list);
831
832 ngx_queue_insert_tail(*locations, &lq->queue);
833
834 return NGX_OK;
835 }
836
837
838 static ngx_int_t
839 ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two)
840 {
841 ngx_int_t rc;
842 ngx_http_core_loc_conf_t *first, *second;
843 ngx_http_location_queue_t *lq1, *lq2;
844
845 lq1 = (ngx_http_location_queue_t *) one;
846 lq2 = (ngx_http_location_queue_t *) two;
847
848 first = lq1->exact ? lq1->exact : lq1->inclusive;
849 second = lq2->exact ? lq2->exact : lq2->inclusive;
850
851 if (first->noname && !second->noname) {
852 /* shift no named locations to the end */
853 return 1;
854 }
855
856 if (!first->noname && second->noname) {
857 /* shift no named locations to the end */
858 return -1;
859 }
860
861 if (first->noname || second->noname) {
862 /* do not sort no named locations */
863 return 0;
864 }
865
866 if (first->named && !second->named) {
867 /* shift named locations to the end */
868 return 1;
869 }
870
871 if (!first->named && second->named) {
872 /* shift named locations to the end */
873 return -1;
874 }
875
876 if (first->named && second->named) {
877 return ngx_strcmp(first->name.data, second->name.data);
878 }
879
880 #if (NGX_PCRE)
881
882 if (first->regex && !second->regex) {
883 /* shift the regex matches to the end */
884 return 1;
885 }
886
887 if (!first->regex && second->regex) {
888 /* shift the regex matches to the end */
889 return -1;
890 }
891
892 if (first->regex || second->regex) {
893 /* do not sort the regex matches */
894 return 0;
895 }
896
897 #endif
898
899 rc = ngx_strcmp(first->name.data, second->name.data);
900
901 if (rc == 0 && !first->exact_match && second->exact_match) {
902 /* an exact match must be before the same inclusive one */
903 return 1;
904 }
905
906 return rc;
907 }
908
909
910 static ngx_int_t
911 ngx_http_join_exact_locations(ngx_conf_t *cf, ngx_queue_t *locations)
912 {
913 ngx_queue_t *q, *x;
914 ngx_http_location_queue_t *lq, *lx;
915
916 q = ngx_queue_head(locations);
917
918 while (q != ngx_queue_last(locations)) {
919
920 x = ngx_queue_next(q);
921
922 lq = (ngx_http_location_queue_t *) q;
923 lx = (ngx_http_location_queue_t *) x;
924
925 if (ngx_strcmp(lq->name->data, lx->name->data) == 0) {
926
927 if ((lq->exact && lx->exact) || (lq->inclusive && lx->inclusive)) {
928 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
929 "duplicate location \"%V\" in %s:%ui",
930 lx->name, lx->file_name, lx->line);
931
932 return NGX_ERROR;
933 }
934
935 lq->inclusive = lx->inclusive;
936
937 ngx_queue_remove(x);
938
939 continue;
940 }
941
942 q = ngx_queue_next(q);
943 }
944
945 return NGX_OK;
946 }
947
948
949 static void
950 ngx_http_create_locations_list(ngx_queue_t *locations, ngx_queue_t *q)
951 {
952 u_char *name;
953 size_t len;
954 ngx_queue_t *x, tail;
955 ngx_http_location_queue_t *lq, *lx;
956
957 if (q == ngx_queue_last(locations)) {
958 return;
959 }
960
961 lq = (ngx_http_location_queue_t *) q;
962
963 if (lq->inclusive == NULL) {
964 ngx_http_create_locations_list(locations, ngx_queue_next(q));
965 return;
966 }
967
968 len = lq->name->len;
969 name = lq->name->data;
970
971 for (x = ngx_queue_next(q);
972 x != ngx_queue_sentinel(locations);
973 x = ngx_queue_next(x))
974 {
975 lx = (ngx_http_location_queue_t *) x;
976
977 if (len > lx->name->len
978 || (ngx_strncmp(name, lx->name->data, len) != 0))
979 {
980 break;
981 }
982 }
983
984 q = ngx_queue_next(q);
985
986 if (q == x) {
987 ngx_http_create_locations_list(locations, x);
988 return;
989 }
990
991 ngx_queue_split(locations, q, &tail);
992 ngx_queue_add(&lq->list, &tail);
993
994 if (x == ngx_queue_sentinel(locations)) {
995 ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list));
996 return;
997 }
998
999 ngx_queue_split(&lq->list, x, &tail);
1000 ngx_queue_add(locations, &tail);
1001
1002 ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list));
1003
1004 ngx_http_create_locations_list(locations, x);
1005 }
1006
1007
1008 /*
1009 * to keep cache locality for left leaf nodes, allocate nodes in following
1010 * order: node, left subtree, right subtree, inclusive subtree
1011 */
1012
1013 static ngx_http_location_tree_node_t *
1014 ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations,
1015 size_t prefix)
1016 {
1017 size_t len;
1018 ngx_queue_t *q, tail;
1019 ngx_http_location_queue_t *lq;
1020 ngx_http_location_tree_node_t *node;
1021
1022 q = ngx_queue_middle(locations);
1023
1024 lq = (ngx_http_location_queue_t *) q;
1025 len = lq->name->len - prefix;
1026
1027 node = ngx_pcalloc(cf->pool,
1028 offsetof(ngx_http_location_tree_node_t, name) + len);
1029 if (node == NULL) {
1030 return NULL;
1031 }
1032
1033 node->exact = lq->exact;
1034 node->inclusive = lq->inclusive;
1035
1036 node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect)
1037 || (lq->inclusive && lq->inclusive->auto_redirect));
1038
1039 node->len = (u_char) len;
1040 ngx_memcpy(node->name, &lq->name->data[prefix], len);
1041
1042 ngx_queue_split(locations, q, &tail);
1043
1044 if (ngx_queue_empty(locations)) {
1045 /*
1046 * ngx_queue_split() insures that if left part is empty,
1047 * then right one is empty too
1048 */
1049 goto inclusive;
1050 }
1051
1052 node->left = ngx_http_create_locations_tree(cf, locations, prefix);
1053 if (node->left == NULL) {
1054 return NULL;
1055 }
1056
1057 ngx_queue_remove(q);
1058
1059 if (ngx_queue_empty(&tail)) {
1060 goto inclusive;
1061 }
1062
1063 node->right = ngx_http_create_locations_tree(cf, &tail, prefix);
1064 if (node->right == NULL) {
1065 return NULL;
1066 }
1067
1068 inclusive:
1069
1070 if (ngx_queue_empty(&lq->list)) {
1071 return node;
1072 }
1073
1074 node->tree = ngx_http_create_locations_tree(cf, &lq->list, prefix + len);
1075 if (node->tree == NULL) {
1076 return NULL;
1077 }
1078
1079 return node;
544 } 1080 }
545 1081
546 1082
547 static ngx_int_t 1083 static ngx_int_t
548 ngx_http_init_server_lists(ngx_conf_t *cf, ngx_array_t *servers, 1084 ngx_http_init_server_lists(ngx_conf_t *cf, ngx_array_t *servers,
754 1290
755 return NGX_OK; 1291 return NGX_OK;
756 } 1292 }
757 1293
758 1294
759 static char *
760 ngx_http_merge_locations(ngx_conf_t *cf, ngx_array_t *locations,
761 void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index)
762 {
763 char *rv;
764 ngx_uint_t i;
765 ngx_http_core_loc_conf_t **clcfp;
766
767 clcfp = locations->elts;
768
769 for (i = 0; i < locations->nelts; i++) {
770 rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
771 clcfp[i]->loc_conf[ctx_index]);
772 if (rv != NGX_CONF_OK) {
773 return rv;
774 }
775
776 if (clcfp[i]->locations == NULL) {
777 continue;
778 }
779
780 rv = ngx_http_merge_locations(cf, clcfp[i]->locations,
781 clcfp[i]->loc_conf, module, ctx_index);
782 if (rv != NGX_CONF_OK) {
783 return rv;
784 }
785 }
786
787 return NGX_CONF_OK;
788 }
789
790
791 static ngx_int_t 1295 static ngx_int_t
792 ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, 1296 ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
793 ngx_array_t *in_ports) 1297 ngx_array_t *in_ports)
794 { 1298 {
795 ngx_int_t rc; 1299 ngx_int_t rc;