locations tree
Igor Sysoev
14 years ago
523 | 523 | ngx_conf_t save; |
524 | 524 | ngx_http_module_t *module; |
525 | 525 | ngx_http_conf_ctx_t *ctx, *pctx; |
526 | ngx_http_core_loc_conf_t *clcf, *pclcf, **clcfp; | |
526 | ngx_http_core_loc_conf_t *clcf, *pclcf; | |
527 | 527 | ngx_http_script_if_code_t *if_code; |
528 | 528 | ngx_http_rewrite_loc_conf_t *nlcf; |
529 | 529 | |
566 | 566 | clcf->name = pclcf->name; |
567 | 567 | clcf->noname = 1; |
568 | 568 | |
569 | if (pclcf->locations == NULL) { | |
570 | pclcf->locations = ngx_array_create(cf->pool, 2, sizeof(void *)); | |
571 | if (pclcf->locations == NULL) { | |
572 | return NGX_CONF_ERROR; | |
573 | } | |
574 | } | |
575 | ||
576 | clcfp = ngx_array_push(pclcf->locations); | |
577 | if (clcfp == NULL) { | |
578 | return NGX_CONF_ERROR; | |
579 | } | |
580 | ||
581 | *clcfp = clcf; | |
582 | ||
569 | if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) { | |
570 | return NGX_CONF_ERROR; | |
571 | } | |
583 | 572 | |
584 | 573 | if (ngx_http_rewrite_if_condition(cf, lcf) != NGX_CONF_OK) { |
585 | 574 | return NGX_CONF_ERROR; |
26 | 26 | ngx_http_core_srv_conf_t *cscf, ngx_http_conf_in_addr_t *in_addr); |
27 | 27 | |
28 | 28 | static char *ngx_http_merge_locations(ngx_conf_t *cf, |
29 | ngx_array_t *locations, void **loc_conf, ngx_http_module_t *module, | |
29 | ngx_queue_t *locations, void **loc_conf, ngx_http_module_t *module, | |
30 | 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); | |
31 | 44 | |
32 | 45 | static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf, |
33 | 46 | ngx_http_core_main_conf_t *cmcf, ngx_array_t *in_ports); |
90 | 103 | ngx_array_t in_ports; |
91 | 104 | ngx_http_module_t *module; |
92 | 105 | ngx_http_conf_ctx_t *ctx; |
106 | ngx_http_core_loc_conf_t *clcf; | |
93 | 107 | ngx_http_core_srv_conf_t **cscfp; |
94 | 108 | ngx_http_core_main_conf_t *cmcf; |
95 | 109 | |
205 | 219 | rv = ngx_conf_parse(cf, NULL); |
206 | 220 | |
207 | 221 | if (rv != NGX_CONF_OK) { |
208 | *cf = pcf; | |
209 | return rv; | |
222 | goto failed; | |
210 | 223 | } |
211 | 224 | |
212 | 225 | /* |
230 | 243 | if (module->init_main_conf) { |
231 | 244 | rv = module->init_main_conf(cf, ctx->main_conf[mi]); |
232 | 245 | if (rv != NGX_CONF_OK) { |
233 | *cf = pcf; | |
234 | return rv; | |
246 | goto failed; | |
235 | 247 | } |
236 | 248 | } |
237 | 249 | |
240 | 252 | /* merge the server{}s' srv_conf's */ |
241 | 253 | |
242 | 254 | if (module->merge_srv_conf) { |
243 | rv = module->merge_srv_conf(cf, | |
244 | ctx->srv_conf[mi], | |
255 | rv = module->merge_srv_conf(cf, ctx->srv_conf[mi], | |
245 | 256 | cscfp[s]->ctx->srv_conf[mi]); |
246 | 257 | if (rv != NGX_CONF_OK) { |
247 | *cf = pcf; | |
248 | return rv; | |
258 | goto failed; | |
249 | 259 | } |
250 | 260 | } |
251 | 261 | |
253 | 263 | |
254 | 264 | /* merge the server{}'s loc_conf */ |
255 | 265 | |
256 | rv = module->merge_loc_conf(cf, | |
257 | ctx->loc_conf[mi], | |
266 | rv = module->merge_loc_conf(cf, ctx->loc_conf[mi], | |
258 | 267 | cscfp[s]->ctx->loc_conf[mi]); |
259 | 268 | if (rv != NGX_CONF_OK) { |
260 | *cf = pcf; | |
261 | return rv; | |
269 | goto failed; | |
262 | 270 | } |
263 | 271 | |
264 | 272 | /* merge the locations{}' loc_conf's */ |
265 | 273 | |
266 | rv = ngx_http_merge_locations(cf, &cscfp[s]->locations, | |
274 | clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index]; | |
275 | ||
276 | rv = ngx_http_merge_locations(cf, clcf->locations, | |
267 | 277 | cscfp[s]->ctx->loc_conf, |
268 | 278 | module, mi); |
269 | 279 | if (rv != NGX_CONF_OK) { |
270 | *cf = pcf; | |
271 | return rv; | |
280 | goto failed; | |
272 | 281 | } |
273 | 282 | } |
283 | } | |
284 | } | |
285 | ||
286 | ||
287 | /* create location trees */ | |
288 | ||
289 | for (s = 0; s < cmcf->servers.nelts; s++) { | |
290 | ||
291 | clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index]; | |
292 | ||
293 | if (ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) { | |
294 | return NGX_CONF_ERROR; | |
295 | } | |
296 | ||
297 | if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) { | |
298 | return NGX_CONF_ERROR; | |
274 | 299 | } |
275 | 300 | } |
276 | 301 | |
336 | 361 | } |
337 | 362 | |
338 | 363 | return NGX_CONF_OK; |
364 | ||
365 | failed: | |
366 | ||
367 | *cf = pcf; | |
368 | ||
369 | return rv; | |
339 | 370 | } |
340 | 371 | |
341 | 372 | |
540 | 571 | } |
541 | 572 | |
542 | 573 | return NGX_OK; |
574 | } | |
575 | ||
576 | ||
577 | static char * | |
578 | ngx_http_merge_locations(ngx_conf_t *cf, ngx_queue_t *locations, | |
579 | void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index) | |
580 | { | |
581 | char *rv; | |
582 | ngx_queue_t *q; | |
583 | ngx_http_core_loc_conf_t *clcf; | |
584 | ngx_http_location_queue_t *lq; | |
585 | ||
586 | if (locations == NULL) { | |
587 | return NGX_CONF_OK; | |
588 | } | |
589 | ||
590 | for (q = ngx_queue_head(locations); | |
591 | q != ngx_queue_sentinel(locations); | |
592 | q = ngx_queue_next(q)) | |
593 | { | |
594 | lq = (ngx_http_location_queue_t *) q; | |
595 | ||
596 | clcf = lq->exact ? lq->exact : lq->inclusive; | |
597 | ||
598 | rv = module->merge_loc_conf(cf, loc_conf[ctx_index], | |
599 | clcf->loc_conf[ctx_index]); | |
600 | if (rv != NGX_CONF_OK) { | |
601 | return rv; | |
602 | } | |
603 | ||
604 | rv = ngx_http_merge_locations(cf, clcf->locations, clcf->loc_conf, | |
605 | module, ctx_index); | |
606 | if (rv != NGX_CONF_OK) { | |
607 | return rv; | |
608 | } | |
609 | } | |
610 | ||
611 | return NGX_CONF_OK; | |
612 | } | |
613 | ||
614 | ||
615 | static ngx_int_t | |
616 | ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, | |
617 | ngx_http_core_loc_conf_t *pclcf) | |
618 | { | |
619 | ngx_uint_t n; | |
620 | ngx_queue_t *q, *locations, *named, tail; | |
621 | ngx_http_core_loc_conf_t *clcf; | |
622 | ngx_http_location_queue_t *lq; | |
623 | ngx_http_core_loc_conf_t **clcfp; | |
624 | #if (NGX_PCRE) | |
625 | ngx_uint_t r; | |
626 | ngx_queue_t *regex; | |
627 | #endif | |
628 | ||
629 | locations = pclcf->locations; | |
630 | ||
631 | if (locations == NULL) { | |
632 | return NGX_OK; | |
633 | } | |
634 | ||
635 | ngx_queue_sort(locations, ngx_http_cmp_locations); | |
636 | ||
637 | named = NULL; | |
638 | n = 0; | |
639 | #if (NGX_PCRE) | |
640 | regex = NULL; | |
641 | r = 0; | |
642 | #endif | |
643 | ||
644 | for (q = ngx_queue_head(locations); | |
645 | q != ngx_queue_sentinel(locations); | |
646 | q = ngx_queue_next(q)) | |
647 | { | |
648 | lq = (ngx_http_location_queue_t *) q; | |
649 | ||
650 | clcf = lq->exact ? lq->exact : lq->inclusive; | |
651 | ||
652 | if (ngx_http_init_locations(cf, NULL, clcf) != NGX_OK) { | |
653 | return NGX_ERROR; | |
654 | } | |
655 | ||
656 | #if (NGX_PCRE) | |
657 | ||
658 | if (clcf->regex) { | |
659 | r++; | |
660 | ||
661 | if (regex == NULL) { | |
662 | regex = q; | |
663 | } | |
664 | ||
665 | continue; | |
666 | } | |
667 | ||
668 | #endif | |
669 | ||
670 | if (clcf->named) { | |
671 | n++; | |
672 | ||
673 | if (named == NULL) { | |
674 | named = q; | |
675 | } | |
676 | ||
677 | continue; | |
678 | } | |
679 | ||
680 | if (clcf->noname) { | |
681 | break; | |
682 | } | |
683 | } | |
684 | ||
685 | if (q != ngx_queue_sentinel(locations)) { | |
686 | ngx_queue_split(locations, q, &tail); | |
687 | } | |
688 | ||
689 | if (named) { | |
690 | clcfp = ngx_palloc(cf->pool, | |
691 | (n + 1) * sizeof(ngx_http_core_loc_conf_t **)); | |
692 | if (clcfp == NULL) { | |
693 | return NGX_ERROR; | |
694 | } | |
695 | ||
696 | cscf->named_locations = clcfp; | |
697 | ||
698 | for (q = named; | |
699 | q != ngx_queue_sentinel(locations); | |
700 | q = ngx_queue_next(q)) | |
701 | { | |
702 | lq = (ngx_http_location_queue_t *) q; | |
703 | ||
704 | *(clcfp++) = lq->exact; | |
705 | } | |
706 | ||
707 | *clcfp = NULL; | |
708 | ||
709 | ngx_queue_split(locations, named, &tail); | |
710 | } | |
711 | ||
712 | #if (NGX_PCRE) | |
713 | ||
714 | if (regex) { | |
715 | ||
716 | clcfp = ngx_palloc(cf->pool, | |
717 | (r + 1) * sizeof(ngx_http_core_loc_conf_t **)); | |
718 | if (clcfp == NULL) { | |
719 | return NGX_ERROR; | |
720 | } | |
721 | ||
722 | pclcf->regex_locations = clcfp; | |
723 | ||
724 | for (q = regex; | |
725 | q != ngx_queue_sentinel(locations); | |
726 | q = ngx_queue_next(q)) | |
727 | { | |
728 | lq = (ngx_http_location_queue_t *) q; | |
729 | ||
730 | *(clcfp++) = lq->exact; | |
731 | } | |
732 | ||
733 | *clcfp = NULL; | |
734 | ||
735 | ngx_queue_split(locations, regex, &tail); | |
736 | } | |
737 | ||
738 | #endif | |
739 | ||
740 | return NGX_OK; | |
741 | } | |
742 | ||
743 | ||
744 | static ngx_int_t | |
745 | ngx_http_init_static_location_trees(ngx_conf_t *cf, | |
746 | ngx_http_core_loc_conf_t *pclcf) | |
747 | { | |
748 | ngx_queue_t *q, *locations; | |
749 | ngx_http_core_loc_conf_t *clcf; | |
750 | ngx_http_location_queue_t *lq; | |
751 | ||
752 | locations = pclcf->locations; | |
753 | ||
754 | if (locations == NULL) { | |
755 | return NGX_OK; | |
756 | } | |
757 | ||
758 | if (ngx_queue_empty(locations)) { | |
759 | return NGX_OK; | |
760 | } | |
761 | ||
762 | for (q = ngx_queue_head(locations); | |
763 | q != ngx_queue_sentinel(locations); | |
764 | q = ngx_queue_next(q)) | |
765 | { | |
766 | lq = (ngx_http_location_queue_t *) q; | |
767 | ||
768 | clcf = lq->exact ? lq->exact : lq->inclusive; | |
769 | ||
770 | if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) { | |
771 | return NGX_ERROR; | |
772 | } | |
773 | } | |
774 | ||
775 | if (ngx_http_join_exact_locations(cf, locations) != NGX_OK) { | |
776 | return NGX_ERROR; | |
777 | } | |
778 | ||
779 | ngx_http_create_locations_list(locations, ngx_queue_head(locations)); | |
780 | ||
781 | pclcf->static_locations = ngx_http_create_locations_tree(cf, locations, 0); | |
782 | if (pclcf->static_locations == NULL) { | |
783 | return NGX_ERROR; | |
784 | } | |
785 | ||
786 | return NGX_OK; | |
787 | } | |
788 | ||
789 | ||
790 | ngx_int_t | |
791 | ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations, | |
792 | ngx_http_core_loc_conf_t *clcf) | |
793 | { | |
794 | ngx_http_location_queue_t *lq; | |
795 | ||
796 | if (*locations == NULL) { | |
797 | *locations = ngx_palloc(cf->temp_pool, | |
798 | sizeof(ngx_http_location_queue_t)); | |
799 | if (*locations == NULL) { | |
800 | return NGX_ERROR; | |
801 | } | |
802 | ||
803 | ngx_queue_init(*locations); | |
804 | } | |
805 | ||
806 | lq = ngx_palloc(cf->temp_pool, sizeof(ngx_http_location_queue_t)); | |
807 | if (lq == NULL) { | |
808 | return NGX_ERROR; | |
809 | } | |
810 | ||
811 | if (clcf->exact_match | |
812 | #if (NGX_PCRE) | |
813 | || clcf->regex | |
814 | #endif | |
815 | || clcf->named || clcf->noname) | |
816 | { | |
817 | lq->exact = clcf; | |
818 | lq->inclusive = NULL; | |
819 | ||
820 | } else { | |
821 | lq->exact = NULL; | |
822 | lq->inclusive = clcf; | |
823 | } | |
824 | ||
825 | lq->name = &clcf->name; | |
826 | lq->file_name = cf->conf_file->file.name.data; | |
827 | lq->line = cf->conf_file->line; | |
828 | ||
829 | ngx_queue_init(&lq->list); | |
830 | ||
831 | ngx_queue_insert_tail(*locations, &lq->queue); | |
832 | ||
833 | return NGX_OK; | |
834 | } | |
835 | ||
836 | ||
837 | static ngx_int_t | |
838 | ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two) | |
839 | { | |
840 | ngx_int_t rc; | |
841 | ngx_http_core_loc_conf_t *first, *second; | |
842 | ngx_http_location_queue_t *lq1, *lq2; | |
843 | ||
844 | lq1 = (ngx_http_location_queue_t *) one; | |
845 | lq2 = (ngx_http_location_queue_t *) two; | |
846 | ||
847 | first = lq1->exact ? lq1->exact : lq1->inclusive; | |
848 | second = lq2->exact ? lq2->exact : lq2->inclusive; | |
849 | ||
850 | if (first->noname && !second->noname) { | |
851 | /* shift no named locations to the end */ | |
852 | return 1; | |
853 | } | |
854 | ||
855 | if (!first->noname && second->noname) { | |
856 | /* shift no named locations to the end */ | |
857 | return -1; | |
858 | } | |
859 | ||
860 | if (first->noname || second->noname) { | |
861 | /* do not sort no named locations */ | |
862 | return 0; | |
863 | } | |
864 | ||
865 | if (first->named && !second->named) { | |
866 | /* shift named locations to the end */ | |
867 | return 1; | |
868 | } | |
869 | ||
870 | if (!first->named && second->named) { | |
871 | /* shift named locations to the end */ | |
872 | return -1; | |
873 | } | |
874 | ||
875 | if (first->named && second->named) { | |
876 | return ngx_strcmp(first->name.data, second->name.data); | |
877 | } | |
878 | ||
879 | #if (NGX_PCRE) | |
880 | ||
881 | if (first->regex && !second->regex) { | |
882 | /* shift the regex matches to the end */ | |
883 | return 1; | |
884 | } | |
885 | ||
886 | if (!first->regex && second->regex) { | |
887 | /* shift the regex matches to the end */ | |
888 | return -1; | |
889 | } | |
890 | ||
891 | if (first->regex || second->regex) { | |
892 | /* do not sort the regex matches */ | |
893 | return 0; | |
894 | } | |
895 | ||
896 | #endif | |
897 | ||
898 | rc = ngx_strcmp(first->name.data, second->name.data); | |
899 | ||
900 | if (rc == 0 && !first->exact_match && second->exact_match) { | |
901 | /* an exact match must be before the same inclusive one */ | |
902 | return 1; | |
903 | } | |
904 | ||
905 | return rc; | |
906 | } | |
907 | ||
908 | ||
909 | static ngx_int_t | |
910 | ngx_http_join_exact_locations(ngx_conf_t *cf, ngx_queue_t *locations) | |
911 | { | |
912 | ngx_queue_t *q, *x; | |
913 | ngx_http_location_queue_t *lq, *lx; | |
914 | ||
915 | q = ngx_queue_head(locations); | |
916 | ||
917 | while (q != ngx_queue_last(locations)) { | |
918 | ||
919 | x = ngx_queue_next(q); | |
920 | ||
921 | lq = (ngx_http_location_queue_t *) q; | |
922 | lx = (ngx_http_location_queue_t *) x; | |
923 | ||
924 | if (ngx_strcmp(lq->name->data, lx->name->data) == 0) { | |
925 | ||
926 | if ((lq->exact && lx->exact) || (lq->inclusive && lx->inclusive)) { | |
927 | ngx_log_error(NGX_LOG_EMERG, cf->log, 0, | |
928 | "duplicate location \"%V\" in %s:%ui", | |
929 | lx->name, lx->file_name, lx->line); | |
930 | ||
931 | return NGX_ERROR; | |
932 | } | |
933 | ||
934 | lq->inclusive = lx->inclusive; | |
935 | ||
936 | ngx_queue_remove(x); | |
937 | ||
938 | continue; | |
939 | } | |
940 | ||
941 | q = ngx_queue_next(q); | |
942 | } | |
943 | ||
944 | return NGX_OK; | |
945 | } | |
946 | ||
947 | ||
948 | static void | |
949 | ngx_http_create_locations_list(ngx_queue_t *locations, ngx_queue_t *q) | |
950 | { | |
951 | u_char *name; | |
952 | size_t len; | |
953 | ngx_queue_t *x, tail; | |
954 | ngx_http_location_queue_t *lq, *lx; | |
955 | ||
956 | if (q == ngx_queue_last(locations)) { | |
957 | return; | |
958 | } | |
959 | ||
960 | lq = (ngx_http_location_queue_t *) q; | |
961 | ||
962 | if (lq->inclusive == NULL) { | |
963 | ngx_http_create_locations_list(locations, ngx_queue_next(q)); | |
964 | return; | |
965 | } | |
966 | ||
967 | len = lq->name->len; | |
968 | name = lq->name->data; | |
969 | ||
970 | for (x = ngx_queue_next(q); | |
971 | x != ngx_queue_sentinel(locations); | |
972 | x = ngx_queue_next(x)) | |
973 | { | |
974 | lx = (ngx_http_location_queue_t *) x; | |
975 | ||
976 | if (len > lx->name->len | |
977 | || (ngx_strncmp(name, lx->name->data, len) != 0)) | |
978 | { | |
979 | break; | |
980 | } | |
981 | } | |
982 | ||
983 | q = ngx_queue_next(q); | |
984 | ||
985 | if (q == x) { | |
986 | ngx_http_create_locations_list(locations, x); | |
987 | return; | |
988 | } | |
989 | ||
990 | ngx_queue_split(locations, q, &tail); | |
991 | ngx_queue_add(&lq->list, &tail); | |
992 | ||
993 | if (x == ngx_queue_sentinel(locations)) { | |
994 | ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list)); | |
995 | return; | |
996 | } | |
997 | ||
998 | ngx_queue_split(&lq->list, x, &tail); | |
999 | ngx_queue_add(locations, &tail); | |
1000 | ||
1001 | ngx_http_create_locations_list(&lq->list, ngx_queue_head(&lq->list)); | |
1002 | ||
1003 | ngx_http_create_locations_list(locations, x); | |
1004 | } | |
1005 | ||
1006 | ||
1007 | /* | |
1008 | * to keep cache locality for left leaf nodes, allocate nodes in following | |
1009 | * order: node, left subtree, right subtree, inclusive subtree | |
1010 | */ | |
1011 | ||
1012 | static ngx_http_location_tree_node_t * | |
1013 | ngx_http_create_locations_tree(ngx_conf_t *cf, ngx_queue_t *locations, | |
1014 | size_t prefix) | |
1015 | { | |
1016 | size_t len; | |
1017 | ngx_queue_t *q, tail; | |
1018 | ngx_http_location_queue_t *lq; | |
1019 | ngx_http_location_tree_node_t *node; | |
1020 | ||
1021 | q = ngx_queue_middle(locations); | |
1022 | ||
1023 | lq = (ngx_http_location_queue_t *) q; | |
1024 | len = lq->name->len - prefix; | |
1025 | ||
1026 | node = ngx_pcalloc(cf->pool, | |
1027 | offsetof(ngx_http_location_tree_node_t, name) + len); | |
1028 | if (node == NULL) { | |
1029 | return NULL; | |
1030 | } | |
1031 | ||
1032 | node->exact = lq->exact; | |
1033 | node->inclusive = lq->inclusive; | |
1034 | ||
1035 | node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect) | |
1036 | || (lq->inclusive && lq->inclusive->auto_redirect)); | |
1037 | ||
1038 | node->len = (u_char) len; | |
1039 | ngx_memcpy(node->name, &lq->name->data[prefix], len); | |
1040 | ||
1041 | ngx_queue_split(locations, q, &tail); | |
1042 | ||
1043 | if (ngx_queue_empty(locations)) { | |
1044 | /* | |
1045 | * ngx_queue_split() insures that if left part is empty, | |
1046 | * then right one is empty too | |
1047 | */ | |
1048 | goto inclusive; | |
1049 | } | |
1050 | ||
1051 | node->left = ngx_http_create_locations_tree(cf, locations, prefix); | |
1052 | if (node->left == NULL) { | |
1053 | return NULL; | |
1054 | } | |
1055 | ||
1056 | ngx_queue_remove(q); | |
1057 | ||
1058 | if (ngx_queue_empty(&tail)) { | |
1059 | goto inclusive; | |
1060 | } | |
1061 | ||
1062 | node->right = ngx_http_create_locations_tree(cf, &tail, prefix); | |
1063 | if (node->right == NULL) { | |
1064 | return NULL; | |
1065 | } | |
1066 | ||
1067 | inclusive: | |
1068 | ||
1069 | if (ngx_queue_empty(&lq->list)) { | |
1070 | return node; | |
1071 | } | |
1072 | ||
1073 | node->tree = ngx_http_create_locations_tree(cf, &lq->list, prefix + len); | |
1074 | if (node->tree == NULL) { | |
1075 | return NULL; | |
1076 | } | |
1077 | ||
1078 | return node; | |
543 | 1079 | } |
544 | 1080 | |
545 | 1081 | |
755 | 1291 | } |
756 | 1292 | |
757 | 1293 | |
758 | static char * | |
759 | ngx_http_merge_locations(ngx_conf_t *cf, ngx_array_t *locations, | |
760 | void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index) | |
761 | { | |
762 | char *rv; | |
763 | ngx_uint_t i; | |
764 | ngx_http_core_loc_conf_t **clcfp; | |
765 | ||
766 | clcfp = locations->elts; | |
767 | ||
768 | for (i = 0; i < locations->nelts; i++) { | |
769 | rv = module->merge_loc_conf(cf, loc_conf[ctx_index], | |
770 | clcfp[i]->loc_conf[ctx_index]); | |
771 | if (rv != NGX_CONF_OK) { | |
772 | return rv; | |
773 | } | |
774 | ||
775 | if (clcfp[i]->locations == NULL) { | |
776 | continue; | |
777 | } | |
778 | ||
779 | rv = ngx_http_merge_locations(cf, clcfp[i]->locations, | |
780 | clcfp[i]->loc_conf, module, ctx_index); | |
781 | if (rv != NGX_CONF_OK) { | |
782 | return rv; | |
783 | } | |
784 | } | |
785 | ||
786 | return NGX_CONF_OK; | |
787 | } | |
788 | ||
789 | ||
790 | 1294 | static ngx_int_t |
791 | 1295 | ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, |
792 | 1296 | ngx_array_t *in_ports) |
56 | 56 | #define ngx_http_set_ctx(r, c, module) r->ctx[module.ctx_index] = c; |
57 | 57 | |
58 | 58 | |
59 | ngx_int_t ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations, | |
60 | ngx_http_core_loc_conf_t *clcf); | |
61 | ||
62 | ||
59 | 63 | void ngx_http_init_connection(ngx_connection_t *c); |
60 | 64 | |
61 | 65 | #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME |
16 | 16 | } ngx_http_method_name_t; |
17 | 17 | |
18 | 18 | |
19 | #define NGX_HTTP_LOCATION_EXACT 1 | |
20 | #define NGX_HTTP_LOCATION_AUTO_REDIRECT 2 | |
21 | #define NGX_HTTP_LOCATION_NOREGEX 3 | |
22 | #define NGX_HTTP_LOCATION_REGEX 4 | |
23 | ||
24 | ||
25 | 19 | #define NGX_HTTP_REQUEST_BODY_FILE_OFF 0 |
26 | 20 | #define NGX_HTTP_REQUEST_BODY_FILE_ON 1 |
27 | 21 | #define NGX_HTTP_REQUEST_BODY_FILE_CLEAN 2 |
28 | 22 | |
29 | 23 | |
30 | static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r, | |
31 | ngx_array_t *locations, ngx_uint_t regex_start, size_t len); | |
24 | static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r); | |
25 | static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r, | |
26 | ngx_http_location_tree_node_t *node); | |
32 | 27 | |
33 | 28 | static ngx_int_t ngx_http_core_preconfiguration(ngx_conf_t *cf); |
34 | 29 | static void *ngx_http_core_create_main_conf(ngx_conf_t *cf); |
44 | 39 | void *dummy); |
45 | 40 | static char *ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, |
46 | 41 | void *dummy); |
47 | static ngx_int_t ngx_http_core_cmp_locations(const void *first, | |
48 | const void *second); | |
49 | 42 | |
50 | 43 | static char *ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd, |
51 | 44 | void *conf); |
786 | 779 | size_t len; |
787 | 780 | ngx_int_t rc; |
788 | 781 | ngx_http_core_loc_conf_t *clcf; |
789 | ngx_http_core_srv_conf_t *cscf; | |
790 | 782 | |
791 | 783 | r->content_handler = NULL; |
792 | 784 | r->uri_changed = 0; |
793 | 785 | |
794 | cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); | |
795 | ||
796 | rc = ngx_http_core_find_location(r, &cscf->locations, cscf->regex_start, 0); | |
786 | rc = ngx_http_core_find_location(r); | |
797 | 787 | |
798 | 788 | if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) { |
799 | 789 | ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
831 | 821 | return NGX_OK; |
832 | 822 | } |
833 | 823 | |
834 | ||
835 | if (rc == NGX_HTTP_LOCATION_AUTO_REDIRECT) { | |
824 | if (rc == NGX_DONE) { | |
836 | 825 | r->headers_out.location = ngx_list_push(&r->headers_out.headers); |
837 | 826 | if (r->headers_out.location == NULL) { |
838 | 827 | ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
1111 | 1100 | |
1112 | 1101 | |
1113 | 1102 | static ngx_int_t |
1114 | ngx_http_core_find_location(ngx_http_request_t *r, | |
1115 | ngx_array_t *locations, ngx_uint_t regex_start, size_t len) | |
1116 | { | |
1117 | ngx_int_t n, rc; | |
1118 | ngx_uint_t i, found; | |
1103 | ngx_http_core_find_location(ngx_http_request_t *r) | |
1104 | { | |
1105 | ngx_int_t rc; | |
1106 | ngx_http_core_loc_conf_t *pclcf; | |
1107 | ||
1108 | pclcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
1109 | ||
1110 | rc = ngx_http_core_find_static_location(r, pclcf->static_locations); | |
1111 | ||
1112 | if (rc == NGX_AGAIN) { | |
1113 | /* look up nested locations */ | |
1114 | rc = ngx_http_core_find_location(r); | |
1115 | } | |
1116 | ||
1117 | if (rc == NGX_OK || rc == NGX_DONE) { | |
1118 | return rc; | |
1119 | } | |
1120 | ||
1121 | /* rc == NGX_DECLINED or rc == NGX_AGAIN in nested location */ | |
1122 | ||
1123 | #if (NGX_PCRE) | |
1124 | { | |
1125 | ngx_int_t n; | |
1119 | 1126 | ngx_http_core_loc_conf_t *clcf, **clcfp; |
1120 | #if (NGX_PCRE) | |
1121 | ngx_uint_t noregex; | |
1122 | #endif | |
1123 | ||
1124 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1125 | "find location for \"%V\"", &r->uri); | |
1126 | ||
1127 | found = 0; | |
1128 | #if (NGX_PCRE) | |
1129 | noregex = 0; | |
1130 | #endif | |
1131 | ||
1132 | clcfp = locations->elts; | |
1133 | for (i = 0; i < locations->nelts; i++) { | |
1134 | ||
1135 | if (clcfp[i]->noname | |
1136 | #if (NGX_PCRE) | |
1137 | || clcfp[i]->regex | |
1138 | #endif | |
1139 | || clcfp[i]->named) | |
1140 | { | |
1141 | break; | |
1142 | } | |
1143 | ||
1144 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1145 | "find location: %s\"%V\"", | |
1146 | clcfp[i]->exact_match ? "= " : "", &clcfp[i]->name); | |
1147 | ||
1148 | if (clcfp[i]->auto_redirect | |
1149 | && r->uri.len == clcfp[i]->name.len - 1 | |
1150 | && ngx_strncmp(r->uri.data, clcfp[i]->name.data, | |
1151 | clcfp[i]->name.len - 1) | |
1152 | == 0) | |
1153 | { | |
1154 | /* the locations are lexicographically sorted */ | |
1155 | ||
1156 | r->loc_conf = clcfp[i]->loc_conf; | |
1157 | ||
1158 | return NGX_HTTP_LOCATION_AUTO_REDIRECT; | |
1159 | } | |
1160 | ||
1161 | if (r->uri.len < clcfp[i]->name.len) { | |
1162 | continue; | |
1163 | } | |
1164 | ||
1165 | n = ngx_strncmp(r->uri.data, clcfp[i]->name.data, clcfp[i]->name.len); | |
1166 | ||
1167 | if (n < 0) { | |
1168 | /* the locations are lexicographically sorted */ | |
1169 | break; | |
1170 | } | |
1171 | ||
1172 | if (n == 0) { | |
1173 | if (clcfp[i]->exact_match) { | |
1174 | ||
1175 | if (r->uri.len == clcfp[i]->name.len) { | |
1176 | r->loc_conf = clcfp[i]->loc_conf; | |
1177 | return NGX_HTTP_LOCATION_EXACT; | |
1178 | } | |
1179 | ||
1127 | ||
1128 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
1129 | ||
1130 | if (clcf->noregex == 0 && pclcf->regex_locations) { | |
1131 | ||
1132 | for (clcfp = pclcf->regex_locations; *clcfp; clcfp++) { | |
1133 | ||
1134 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1135 | "test location: ~ \"%V\"", &(*clcfp)->name); | |
1136 | ||
1137 | n = ngx_regex_exec((*clcfp)->regex, &r->uri, NULL, 0); | |
1138 | ||
1139 | if (n == NGX_REGEX_NO_MATCHED) { | |
1180 | 1140 | continue; |
1181 | 1141 | } |
1182 | 1142 | |
1183 | if (len > clcfp[i]->name.len) { | |
1184 | /* the previous match is longer */ | |
1185 | break; | |
1143 | if (n < 0) { | |
1144 | ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
1145 | ngx_regex_exec_n | |
1146 | " failed: %d on \"%V\" using \"%V\"", | |
1147 | n, &r->uri, &(*clcfp)->name); | |
1148 | return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
1186 | 1149 | } |
1187 | 1150 | |
1188 | found = 1; | |
1189 | ||
1190 | r->loc_conf = clcfp[i]->loc_conf; | |
1191 | #if (NGX_PCRE) | |
1192 | noregex = clcfp[i]->noregex; | |
1151 | /* match */ | |
1152 | ||
1153 | r->loc_conf = (*clcfp)->loc_conf; | |
1154 | ||
1155 | /* look up nested locations */ | |
1156 | ||
1157 | return ngx_http_core_find_location(r); | |
1158 | } | |
1159 | } | |
1160 | } | |
1193 | 1161 | #endif |
1194 | } | |
1195 | } | |
1196 | ||
1197 | if (found) { | |
1198 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
1199 | ||
1200 | if (clcf->locations) { | |
1201 | rc = ngx_http_core_find_location(r, clcf->locations, | |
1202 | clcf->regex_start, len); | |
1203 | ||
1204 | if (rc != NGX_OK) { | |
1205 | return rc; | |
1162 | ||
1163 | return rc; | |
1164 | } | |
1165 | ||
1166 | ||
1167 | /* | |
1168 | * NGX_OK - exact match | |
1169 | * NGX_DONE - auto redirect | |
1170 | * NGX_AGAIN - inclusive match | |
1171 | * NGX_DECLINED - no match | |
1172 | */ | |
1173 | ||
1174 | static ngx_int_t | |
1175 | ngx_http_core_find_static_location(ngx_http_request_t *r, | |
1176 | ngx_http_location_tree_node_t *node) | |
1177 | { | |
1178 | u_char *uri; | |
1179 | size_t len, n; | |
1180 | ngx_int_t rc, rv; | |
1181 | ||
1182 | len = r->uri.len; | |
1183 | uri = r->uri.data; | |
1184 | ||
1185 | rv = NGX_DECLINED; | |
1186 | ||
1187 | for ( ;; ) { | |
1188 | ||
1189 | if (node == NULL) { | |
1190 | return rv; | |
1191 | } | |
1192 | ||
1193 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1194 | "test location: \"%*s\"", node->len, node->name); | |
1195 | ||
1196 | n = (len <= (size_t) node->len) ? len : node->len; | |
1197 | ||
1198 | rc = ngx_memcmp(uri, node->name, n); | |
1199 | ||
1200 | if (rc != 0) { | |
1201 | node = (rc < 0) ? node->left : node->right; | |
1202 | ||
1203 | continue; | |
1204 | } | |
1205 | ||
1206 | if (len > (size_t) node->len) { | |
1207 | ||
1208 | if (node->inclusive) { | |
1209 | ||
1210 | r->loc_conf = node->inclusive->loc_conf; | |
1211 | rv = NGX_AGAIN; | |
1212 | ||
1213 | node = node->tree; | |
1214 | uri += n; | |
1215 | len -= n; | |
1216 | ||
1217 | continue; | |
1206 | 1218 | } |
1207 | } | |
1208 | } | |
1209 | ||
1210 | #if (NGX_PCRE) | |
1211 | ||
1212 | if (noregex) { | |
1213 | return NGX_HTTP_LOCATION_NOREGEX; | |
1214 | } | |
1215 | ||
1216 | /* regex matches */ | |
1217 | ||
1218 | for (i = regex_start; i < locations->nelts; i++) { | |
1219 | ||
1220 | if (!clcfp[i]->regex) { | |
1221 | break; | |
1222 | } | |
1223 | ||
1224 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1225 | "find location: ~ \"%V\"", &clcfp[i]->name); | |
1226 | ||
1227 | n = ngx_regex_exec(clcfp[i]->regex, &r->uri, NULL, 0); | |
1228 | ||
1229 | if (n == NGX_REGEX_NO_MATCHED) { | |
1219 | ||
1220 | /* exact only */ | |
1221 | ||
1222 | node = node->right; | |
1223 | ||
1230 | 1224 | continue; |
1231 | 1225 | } |
1232 | 1226 | |
1233 | if (n < 0) { | |
1234 | ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
1235 | ngx_regex_exec_n | |
1236 | " failed: %d on \"%V\" using \"%V\"", | |
1237 | n, &r->uri, &clcfp[i]->name); | |
1238 | return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
1239 | } | |
1240 | ||
1241 | /* match */ | |
1242 | ||
1243 | r->loc_conf = clcfp[i]->loc_conf; | |
1244 | ||
1245 | return NGX_HTTP_LOCATION_REGEX; | |
1246 | } | |
1247 | ||
1248 | #endif /* NGX_PCRE */ | |
1249 | ||
1250 | return NGX_OK; | |
1227 | if (len == (size_t) node->len) { | |
1228 | ||
1229 | r->loc_conf = (node->exact) ? node->exact->loc_conf: | |
1230 | node->inclusive->loc_conf; | |
1231 | return NGX_OK; | |
1232 | } | |
1233 | ||
1234 | /* len < node->len */ | |
1235 | ||
1236 | if (len + 1 == (size_t) node->len && node->auto_redirect) { | |
1237 | ||
1238 | r->loc_conf = (node->exact) ? node->exact->loc_conf: | |
1239 | node->inclusive->loc_conf; | |
1240 | rv = NGX_DONE; | |
1241 | } | |
1242 | ||
1243 | node = node->left; | |
1244 | } | |
1251 | 1245 | } |
1252 | 1246 | |
1253 | 1247 | |
1895 | 1889 | ngx_int_t |
1896 | 1890 | ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name) |
1897 | 1891 | { |
1898 | ngx_uint_t i; | |
1899 | 1892 | ngx_http_core_srv_conf_t *cscf; |
1900 | 1893 | ngx_http_core_loc_conf_t **clcfp; |
1901 | 1894 | ngx_http_core_main_conf_t *cmcf; |
1902 | 1895 | |
1903 | 1896 | cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); |
1904 | 1897 | |
1905 | clcfp = cscf->locations.elts; | |
1906 | ||
1907 | for (i = cscf->named_start; i < cscf->locations.nelts; i++) { | |
1908 | ||
1909 | if (name->len != clcfp[i]->name.len | |
1910 | || ngx_strncmp(name->data, clcfp[i]->name.data, name->len) != 0) | |
1898 | for (clcfp = cscf->named_locations; *clcfp; clcfp++) { | |
1899 | ||
1900 | ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1901 | "test location: \"%V\"", &(*clcfp)->name); | |
1902 | ||
1903 | if (name->len != (*clcfp)->name.len | |
1904 | || ngx_strncmp(name->data, (*clcfp)->name.data, name->len) != 0) | |
1911 | 1905 | { |
1912 | 1906 | continue; |
1913 | 1907 | } |
1914 | 1908 | |
1915 | 1909 | ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1916 | "named location: %V \"%V?%V\"", name, &r->uri, &r->args); | |
1910 | "using location: %V \"%V?%V\"", name, &r->uri, &r->args); | |
1917 | 1911 | |
1918 | 1912 | r->internal = 1; |
1919 | 1913 | r->content_handler = NULL; |
1920 | r->loc_conf = clcfp[i]->loc_conf; | |
1914 | r->loc_conf = (*clcfp)->loc_conf; | |
1921 | 1915 | |
1922 | 1916 | ngx_http_update_location_config(r); |
1923 | 1917 | |
1934 | 1928 | "could not find named location \"%V\"", name); |
1935 | 1929 | |
1936 | 1930 | ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
1931 | ||
1937 | 1932 | return NGX_DONE; |
1938 | 1933 | } |
1939 | 1934 | |
1982 | 1977 | ngx_http_module_t *module; |
1983 | 1978 | ngx_http_conf_ctx_t *ctx, *http_ctx; |
1984 | 1979 | ngx_http_core_srv_conf_t *cscf, **cscfp; |
1985 | ngx_http_core_loc_conf_t **clcfp; | |
1986 | 1980 | ngx_http_core_main_conf_t *cmcf; |
1987 | 1981 | |
1988 | 1982 | ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); |
2059 | 2053 | rv = ngx_conf_parse(cf, NULL); |
2060 | 2054 | |
2061 | 2055 | *cf = pcf; |
2062 | ||
2063 | if (rv != NGX_CONF_OK) { | |
2064 | return rv; | |
2065 | } | |
2066 | ||
2067 | ngx_sort(cscf->locations.elts, (size_t) cscf->locations.nelts, | |
2068 | sizeof(ngx_http_core_loc_conf_t *), ngx_http_core_cmp_locations); | |
2069 | ||
2070 | clcfp = cscf->locations.elts; | |
2071 | ||
2072 | #if (NGX_PCRE) | |
2073 | ||
2074 | cscf->regex_start = cscf->locations.nelts; | |
2075 | ||
2076 | for (i = 0; i < cscf->locations.nelts; i++) { | |
2077 | if (clcfp[i]->regex) { | |
2078 | cscf->regex_start = i; | |
2079 | break; | |
2080 | } | |
2081 | } | |
2082 | ||
2083 | #endif | |
2084 | ||
2085 | cscf->named_start = cscf->locations.nelts; | |
2086 | ||
2087 | for (i = 0; i < cscf->locations.nelts; i++) { | |
2088 | if (clcfp[i]->named) { | |
2089 | cscf->named_start = i; | |
2090 | break; | |
2091 | } | |
2092 | } | |
2093 | 2056 | |
2094 | 2057 | return rv; |
2095 | 2058 | } |
2104 | 2067 | ngx_conf_t save; |
2105 | 2068 | ngx_http_module_t *module; |
2106 | 2069 | ngx_http_conf_ctx_t *ctx, *pctx; |
2107 | ngx_http_core_srv_conf_t *cscf; | |
2108 | ngx_http_core_loc_conf_t *clcf, *pclcf, **clcfp; | |
2070 | ngx_http_core_loc_conf_t *clcf, *pclcf; | |
2109 | 2071 | |
2110 | 2072 | ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); |
2111 | 2073 | if (ctx == NULL) { |
2200 | 2162 | |
2201 | 2163 | pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index]; |
2202 | 2164 | |
2203 | if (pclcf->name.len == 0) { | |
2204 | cscf = ctx->srv_conf[ngx_http_core_module.ctx_index]; | |
2205 | ||
2206 | clcfp = ngx_array_push(&cscf->locations); | |
2207 | if (clcfp == NULL) { | |
2208 | return NGX_CONF_ERROR; | |
2209 | } | |
2210 | ||
2211 | } else { | |
2165 | if (pclcf->name.len) { | |
2166 | ||
2167 | /* nested location */ | |
2168 | ||
2212 | 2169 | #if 0 |
2213 | 2170 | clcf->prev_location = pclcf; |
2214 | 2171 | #endif |
2226 | 2183 | "location \"%V\" could not be inside " |
2227 | 2184 | "the named location \"%V\"", |
2228 | 2185 | &clcf->name, &pclcf->name); |
2186 | return NGX_CONF_ERROR; | |
2187 | } | |
2188 | ||
2189 | if (clcf->named) { | |
2190 | ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
2191 | "named location \"%V\" must be " | |
2192 | "on server level only", | |
2193 | &clcf->name); | |
2229 | 2194 | return NGX_CONF_ERROR; |
2230 | 2195 | } |
2231 | 2196 | |
2243 | 2208 | &clcf->name, &pclcf->name); |
2244 | 2209 | return NGX_CONF_ERROR; |
2245 | 2210 | } |
2246 | ||
2247 | if (pclcf->locations == NULL) { | |
2248 | pclcf->locations = ngx_array_create(cf->pool, 2, sizeof(void *)); | |
2249 | ||
2250 | if (pclcf->locations == NULL) { | |
2251 | return NGX_CONF_ERROR; | |
2252 | } | |
2253 | } | |
2254 | ||
2255 | clcfp = ngx_array_push(pclcf->locations); | |
2256 | if (clcfp == NULL) { | |
2257 | return NGX_CONF_ERROR; | |
2258 | } | |
2259 | } | |
2260 | ||
2261 | *clcfp = clcf; | |
2211 | } | |
2212 | ||
2213 | if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) { | |
2214 | return NGX_CONF_ERROR; | |
2215 | } | |
2262 | 2216 | |
2263 | 2217 | save = *cf; |
2264 | 2218 | cf->ctx = ctx; |
2268 | 2222 | |
2269 | 2223 | *cf = save; |
2270 | 2224 | |
2271 | if (rv != NGX_CONF_OK) { | |
2272 | return rv; | |
2273 | } | |
2274 | ||
2275 | if (clcf->locations == NULL) { | |
2276 | return rv; | |
2277 | } | |
2278 | ||
2279 | ngx_sort(clcf->locations->elts, (size_t) clcf->locations->nelts, | |
2280 | sizeof(ngx_http_core_loc_conf_t *), ngx_http_core_cmp_locations); | |
2281 | ||
2282 | #if (NGX_PCRE) | |
2283 | ||
2284 | clcf->regex_start = clcf->locations->nelts; | |
2285 | clcfp = clcf->locations->elts; | |
2286 | ||
2287 | for (i = 0; i < clcf->locations->nelts; i++) { | |
2288 | if (clcfp[i]->regex) { | |
2289 | clcf->regex_start = i; | |
2290 | break; | |
2291 | } | |
2292 | } | |
2293 | ||
2294 | #endif | |
2295 | ||
2296 | 2225 | return rv; |
2297 | } | |
2298 | ||
2299 | ||
2300 | static ngx_int_t | |
2301 | ngx_http_core_cmp_locations(const void *one, const void *two) | |
2302 | { | |
2303 | ngx_int_t rc; | |
2304 | ngx_http_core_loc_conf_t *first, *second; | |
2305 | ||
2306 | first = *(ngx_http_core_loc_conf_t **) one; | |
2307 | second = *(ngx_http_core_loc_conf_t **) two; | |
2308 | ||
2309 | if (first->named && !second->named) { | |
2310 | /* shift named locations to the end */ | |
2311 | return 1; | |
2312 | } | |
2313 | ||
2314 | if (!first->named && second->named) { | |
2315 | /* shift named locations to the end */ | |
2316 | return -1; | |
2317 | } | |
2318 | ||
2319 | if (first->named && second->named) { | |
2320 | return ngx_strcmp(first->name.data, second->name.data); | |
2321 | } | |
2322 | ||
2323 | if (first->noname && !second->noname) { | |
2324 | /* shift no named locations to the end */ | |
2325 | return 1; | |
2326 | } | |
2327 | ||
2328 | if (!first->noname && second->noname) { | |
2329 | /* shift no named locations to the end */ | |
2330 | return -1; | |
2331 | } | |
2332 | ||
2333 | if (first->noname || second->noname) { | |
2334 | /* do not sort no named locations */ | |
2335 | return 0; | |
2336 | } | |
2337 | ||
2338 | #if (NGX_PCRE) | |
2339 | ||
2340 | if (first->regex && !second->regex) { | |
2341 | /* shift the regex matches to the end */ | |
2342 | return 1; | |
2343 | } | |
2344 | ||
2345 | if (!first->regex && second->regex) { | |
2346 | /* shift the regex matches to the end */ | |
2347 | return -1; | |
2348 | } | |
2349 | ||
2350 | if (first->regex || second->regex) { | |
2351 | /* do not sort the regex matches */ | |
2352 | return 0; | |
2353 | } | |
2354 | ||
2355 | #endif | |
2356 | ||
2357 | rc = ngx_strcmp(first->name.data, second->name.data); | |
2358 | ||
2359 | if (rc == 0 && second->exact_match) { | |
2360 | /* an exact match must be before the same inclusive one */ | |
2361 | return 1; | |
2362 | } | |
2363 | ||
2364 | return rc; | |
2365 | 2226 | } |
2366 | 2227 | |
2367 | 2228 | |
2539 | 2400 | * |
2540 | 2401 | * conf->client_large_buffers.num = 0; |
2541 | 2402 | */ |
2542 | ||
2543 | if (ngx_array_init(&cscf->locations, cf->pool, 4, sizeof(void *)) | |
2544 | == NGX_ERROR) | |
2545 | { | |
2546 | return NGX_CONF_ERROR; | |
2547 | } | |
2548 | 2403 | |
2549 | 2404 | if (ngx_array_init(&cscf->listen, cf->pool, 4, sizeof(ngx_http_listen_t)) |
2550 | 2405 | == NGX_ERROR) |
3344 | 3199 | static char * |
3345 | 3200 | ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
3346 | 3201 | { |
3347 | ngx_http_core_loc_conf_t *clcf = conf; | |
3202 | ngx_http_core_loc_conf_t *pclcf = conf; | |
3348 | 3203 | |
3349 | 3204 | char *rv; |
3350 | 3205 | void *mconf; |
3354 | 3209 | ngx_http_module_t *module; |
3355 | 3210 | ngx_http_conf_ctx_t *ctx, *pctx; |
3356 | 3211 | ngx_http_method_name_t *name; |
3357 | ngx_http_core_loc_conf_t *lcf, **clcfp; | |
3358 | ||
3359 | if (clcf->limit_except) { | |
3212 | ngx_http_core_loc_conf_t *clcf; | |
3213 | ||
3214 | if (pclcf->limit_except) { | |
3360 | 3215 | return "duplicate"; |
3361 | 3216 | } |
3362 | 3217 | |
3363 | clcf->limit_except = 0xffffffff; | |
3218 | pclcf->limit_except = 0xffffffff; | |
3364 | 3219 | |
3365 | 3220 | value = cf->args->elts; |
3366 | 3221 | |
3368 | 3223 | for (name = ngx_methods_names; name->name; name++) { |
3369 | 3224 | |
3370 | 3225 | if (ngx_strcasecmp(value[i].data, name->name) == 0) { |
3371 | clcf->limit_except &= name->method; | |
3226 | pclcf->limit_except &= name->method; | |
3372 | 3227 | goto next; |
3373 | 3228 | } |
3374 | 3229 | } |
3381 | 3236 | continue; |
3382 | 3237 | } |
3383 | 3238 | |
3384 | if (!(clcf->limit_except & NGX_HTTP_GET)) { | |
3385 | clcf->limit_except &= (uint32_t) ~NGX_HTTP_HEAD; | |
3239 | if (!(pclcf->limit_except & NGX_HTTP_GET)) { | |
3240 | pclcf->limit_except &= (uint32_t) ~NGX_HTTP_HEAD; | |
3386 | 3241 | } |
3387 | 3242 | |
3388 | 3243 | ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); |
3418 | 3273 | } |
3419 | 3274 | |
3420 | 3275 | |
3421 | lcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; | |
3422 | clcf->limit_except_loc_conf = ctx->loc_conf; | |
3423 | lcf->loc_conf = ctx->loc_conf; | |
3424 | lcf->name = clcf->name; | |
3425 | lcf->noname = 1; | |
3426 | ||
3427 | if (clcf->locations == NULL) { | |
3428 | clcf->locations = ngx_array_create(cf->pool, 2, sizeof(void *)); | |
3429 | if (clcf->locations == NULL) { | |
3430 | return NGX_CONF_ERROR; | |
3431 | } | |
3432 | } | |
3433 | ||
3434 | clcfp = ngx_array_push(clcf->locations); | |
3435 | if (clcfp == NULL) { | |
3276 | clcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; | |
3277 | pclcf->limit_except_loc_conf = ctx->loc_conf; | |
3278 | clcf->loc_conf = ctx->loc_conf; | |
3279 | clcf->name = pclcf->name; | |
3280 | clcf->noname = 1; | |
3281 | ||
3282 | if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) { | |
3436 | 3283 | return NGX_CONF_ERROR; |
3437 | 3284 | } |
3438 | ||
3439 | *clcfp = lcf; | |
3440 | ||
3441 | 3285 | |
3442 | 3286 | save = *cf; |
3443 | 3287 | cf->ctx = ctx; |
27 | 27 | #define NGX_HTTP_SATISFY_ANY 1 |
28 | 28 | |
29 | 29 | |
30 | typedef struct ngx_http_location_tree_node_s ngx_http_location_tree_node_t; | |
31 | typedef struct ngx_http_core_loc_conf_s ngx_http_core_loc_conf_t; | |
32 | ||
33 | ||
30 | 34 | typedef struct { |
31 | 35 | unsigned default_server:1; |
32 | 36 | unsigned bind:1; |
126 | 130 | |
127 | 131 | |
128 | 132 | typedef struct { |
129 | /* | |
130 | * array of the ngx_http_core_loc_conf_t *, | |
131 | * used in the ngx_http_core_find_location() and in the merge phase | |
132 | */ | |
133 | ngx_array_t locations; | |
134 | ||
135 | unsigned regex_start:15; | |
136 | unsigned named_start:15; | |
137 | ||
138 | 133 | /* array of the ngx_http_listen_t, "listen" directive */ |
139 | ngx_array_t listen; | |
134 | ngx_array_t listen; | |
140 | 135 | |
141 | 136 | /* array of the ngx_http_server_name_t, "server_name" directive */ |
142 | ngx_array_t server_names; | |
137 | ngx_array_t server_names; | |
143 | 138 | |
144 | 139 | /* server ctx */ |
145 | ngx_http_conf_ctx_t *ctx; | |
146 | ||
147 | ngx_str_t server_name; | |
148 | ||
149 | size_t connection_pool_size; | |
150 | size_t request_pool_size; | |
151 | size_t client_header_buffer_size; | |
152 | ||
153 | ngx_bufs_t large_client_header_buffers; | |
154 | ||
155 | ngx_msec_t client_header_timeout; | |
156 | ||
157 | ngx_flag_t optimize_server_names; | |
158 | ngx_flag_t ignore_invalid_headers; | |
159 | ngx_flag_t merge_slashes; | |
140 | ngx_http_conf_ctx_t *ctx; | |
141 | ||
142 | ngx_str_t server_name; | |
143 | ||
144 | size_t connection_pool_size; | |
145 | size_t request_pool_size; | |
146 | size_t client_header_buffer_size; | |
147 | ||
148 | ngx_bufs_t large_client_header_buffers; | |
149 | ||
150 | ngx_msec_t client_header_timeout; | |
151 | ||
152 | ngx_flag_t optimize_server_names; | |
153 | ngx_flag_t ignore_invalid_headers; | |
154 | ngx_flag_t merge_slashes; | |
155 | ||
156 | ngx_http_core_loc_conf_t **named_locations; | |
160 | 157 | } ngx_http_core_srv_conf_t; |
161 | 158 | |
162 | 159 | |
230 | 227 | } ngx_http_err_page_t; |
231 | 228 | |
232 | 229 | |
233 | typedef struct ngx_http_core_loc_conf_s ngx_http_core_loc_conf_t; | |
234 | ||
235 | 230 | struct ngx_http_core_loc_conf_s { |
236 | 231 | ngx_str_t name; /* location name */ |
237 | 232 | |
239 | 234 | ngx_regex_t *regex; |
240 | 235 | #endif |
241 | 236 | |
242 | unsigned regex_start:15; | |
243 | ||
244 | 237 | unsigned noname:1; /* "if () {}" block or limit_except */ |
245 | 238 | unsigned named:1; |
246 | 239 | |
250 | 243 | unsigned auto_redirect:1; |
251 | 244 | unsigned alias:1; |
252 | 245 | |
253 | /* array of inclusive ngx_http_core_loc_conf_t */ | |
254 | ngx_array_t *locations; | |
246 | ngx_queue_t *locations; | |
247 | ||
248 | ngx_http_location_tree_node_t *static_locations; | |
249 | ngx_http_core_loc_conf_t **regex_locations; | |
255 | 250 | |
256 | 251 | /* pointer to the modules' loc_conf */ |
257 | 252 | void **loc_conf; |
335 | 330 | #if 0 |
336 | 331 | ngx_http_core_loc_conf_t *prev_location; |
337 | 332 | #endif |
333 | }; | |
334 | ||
335 | ||
336 | typedef struct { | |
337 | ngx_queue_t queue; | |
338 | ngx_http_core_loc_conf_t *exact; | |
339 | ngx_http_core_loc_conf_t *inclusive; | |
340 | ngx_str_t *name; | |
341 | u_char *file_name; | |
342 | ngx_uint_t line; | |
343 | ngx_queue_t list; | |
344 | } ngx_http_location_queue_t; | |
345 | ||
346 | ||
347 | struct ngx_http_location_tree_node_s { | |
348 | ngx_http_location_tree_node_t *left; | |
349 | ngx_http_location_tree_node_t *right; | |
350 | ngx_http_location_tree_node_t *tree; | |
351 | ||
352 | ngx_http_core_loc_conf_t *exact; | |
353 | ngx_http_core_loc_conf_t *inclusive; | |
354 | ||
355 | u_char auto_redirect; | |
356 | u_char len; | |
357 | u_char name[1]; | |
338 | 358 | }; |
339 | 359 | |
340 | 360 |