Klaus Demo nginx / e55988c
locations tree Igor Sysoev 14 years ago
5 changed file(s) with 791 addition(s) and 430 deletion(s). Raw diff Collapse all Expand all
523523 ngx_conf_t save;
524524 ngx_http_module_t *module;
525525 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;
527527 ngx_http_script_if_code_t *if_code;
528528 ngx_http_rewrite_loc_conf_t *nlcf;
529529
566566 clcf->name = pclcf->name;
567567 clcf->noname = 1;
568568
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 }
583572
584573 if (ngx_http_rewrite_if_condition(cf, lcf) != NGX_CONF_OK) {
585574 return NGX_CONF_ERROR;
2626 ngx_http_core_srv_conf_t *cscf, ngx_http_conf_in_addr_t *in_addr);
2727
2828 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,
3030 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);
3144
3245 static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf,
3346 ngx_http_core_main_conf_t *cmcf, ngx_array_t *in_ports);
90103 ngx_array_t in_ports;
91104 ngx_http_module_t *module;
92105 ngx_http_conf_ctx_t *ctx;
106 ngx_http_core_loc_conf_t *clcf;
93107 ngx_http_core_srv_conf_t **cscfp;
94108 ngx_http_core_main_conf_t *cmcf;
95109
205219 rv = ngx_conf_parse(cf, NULL);
206220
207221 if (rv != NGX_CONF_OK) {
208 *cf = pcf;
209 return rv;
222 goto failed;
210223 }
211224
212225 /*
230243 if (module->init_main_conf) {
231244 rv = module->init_main_conf(cf, ctx->main_conf[mi]);
232245 if (rv != NGX_CONF_OK) {
233 *cf = pcf;
234 return rv;
246 goto failed;
235247 }
236248 }
237249
240252 /* merge the server{}s' srv_conf's */
241253
242254 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],
245256 cscfp[s]->ctx->srv_conf[mi]);
246257 if (rv != NGX_CONF_OK) {
247 *cf = pcf;
248 return rv;
258 goto failed;
249259 }
250260 }
251261
253263
254264 /* merge the server{}'s loc_conf */
255265
256 rv = module->merge_loc_conf(cf,
257 ctx->loc_conf[mi],
266 rv = module->merge_loc_conf(cf, ctx->loc_conf[mi],
258267 cscfp[s]->ctx->loc_conf[mi]);
259268 if (rv != NGX_CONF_OK) {
260 *cf = pcf;
261 return rv;
269 goto failed;
262270 }
263271
264272 /* merge the locations{}' loc_conf's */
265273
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,
267277 cscfp[s]->ctx->loc_conf,
268278 module, mi);
269279 if (rv != NGX_CONF_OK) {
270 *cf = pcf;
271 return rv;
280 goto failed;
272281 }
273282 }
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;
274299 }
275300 }
276301
336361 }
337362
338363 return NGX_CONF_OK;
364
365 failed:
366
367 *cf = pcf;
368
369 return rv;
339370 }
340371
341372
540571 }
541572
542573 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;
5431079 }
5441080
5451081
7551291 }
7561292
7571293
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
7901294 static ngx_int_t
7911295 ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
7921296 ngx_array_t *in_ports)
5656 #define ngx_http_set_ctx(r, c, module) r->ctx[module.ctx_index] = c;
5757
5858
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
5963 void ngx_http_init_connection(ngx_connection_t *c);
6064
6165 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
1616 } ngx_http_method_name_t;
1717
1818
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
2519 #define NGX_HTTP_REQUEST_BODY_FILE_OFF 0
2620 #define NGX_HTTP_REQUEST_BODY_FILE_ON 1
2721 #define NGX_HTTP_REQUEST_BODY_FILE_CLEAN 2
2822
2923
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);
3227
3328 static ngx_int_t ngx_http_core_preconfiguration(ngx_conf_t *cf);
3429 static void *ngx_http_core_create_main_conf(ngx_conf_t *cf);
4439 void *dummy);
4540 static char *ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd,
4641 void *dummy);
47 static ngx_int_t ngx_http_core_cmp_locations(const void *first,
48 const void *second);
4942
5043 static char *ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd,
5144 void *conf);
786779 size_t len;
787780 ngx_int_t rc;
788781 ngx_http_core_loc_conf_t *clcf;
789 ngx_http_core_srv_conf_t *cscf;
790782
791783 r->content_handler = NULL;
792784 r->uri_changed = 0;
793785
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);
797787
798788 if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
799789 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
831821 return NGX_OK;
832822 }
833823
834
835 if (rc == NGX_HTTP_LOCATION_AUTO_REDIRECT) {
824 if (rc == NGX_DONE) {
836825 r->headers_out.location = ngx_list_push(&r->headers_out.headers);
837826 if (r->headers_out.location == NULL) {
838827 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
11111100
11121101
11131102 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;
11191126 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) {
11801140 continue;
11811141 }
11821142
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;
11861149 }
11871150
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 }
11931161 #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;
12061218 }
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
12301224 continue;
12311225 }
12321226
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 }
12511245 }
12521246
12531247
18951889 ngx_int_t
18961890 ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name)
18971891 {
1898 ngx_uint_t i;
18991892 ngx_http_core_srv_conf_t *cscf;
19001893 ngx_http_core_loc_conf_t **clcfp;
19011894 ngx_http_core_main_conf_t *cmcf;
19021895
19031896 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
19041897
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)
19111905 {
19121906 continue;
19131907 }
19141908
19151909 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);
19171911
19181912 r->internal = 1;
19191913 r->content_handler = NULL;
1920 r->loc_conf = clcfp[i]->loc_conf;
1914 r->loc_conf = (*clcfp)->loc_conf;
19211915
19221916 ngx_http_update_location_config(r);
19231917
19341928 "could not find named location \"%V\"", name);
19351929
19361930 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1931
19371932 return NGX_DONE;
19381933 }
19391934
19821977 ngx_http_module_t *module;
19831978 ngx_http_conf_ctx_t *ctx, *http_ctx;
19841979 ngx_http_core_srv_conf_t *cscf, **cscfp;
1985 ngx_http_core_loc_conf_t **clcfp;
19861980 ngx_http_core_main_conf_t *cmcf;
19871981
19881982 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
20592053 rv = ngx_conf_parse(cf, NULL);
20602054
20612055 *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 }
20932056
20942057 return rv;
20952058 }
21042067 ngx_conf_t save;
21052068 ngx_http_module_t *module;
21062069 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;
21092071
21102072 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
21112073 if (ctx == NULL) {
22002162
22012163 pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
22022164
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
22122169 #if 0
22132170 clcf->prev_location = pclcf;
22142171 #endif
22262183 "location \"%V\" could not be inside "
22272184 "the named location \"%V\"",
22282185 &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);
22292194 return NGX_CONF_ERROR;
22302195 }
22312196
22432208 &clcf->name, &pclcf->name);
22442209 return NGX_CONF_ERROR;
22452210 }
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 }
22622216
22632217 save = *cf;
22642218 cf->ctx = ctx;
22682222
22692223 *cf = save;
22702224
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
22962225 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;
23652226 }
23662227
23672228
25392400 *
25402401 * conf->client_large_buffers.num = 0;
25412402 */
2542
2543 if (ngx_array_init(&cscf->locations, cf->pool, 4, sizeof(void *))
2544 == NGX_ERROR)
2545 {
2546 return NGX_CONF_ERROR;
2547 }
25482403
25492404 if (ngx_array_init(&cscf->listen, cf->pool, 4, sizeof(ngx_http_listen_t))
25502405 == NGX_ERROR)
33443199 static char *
33453200 ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
33463201 {
3347 ngx_http_core_loc_conf_t *clcf = conf;
3202 ngx_http_core_loc_conf_t *pclcf = conf;
33483203
33493204 char *rv;
33503205 void *mconf;
33543209 ngx_http_module_t *module;
33553210 ngx_http_conf_ctx_t *ctx, *pctx;
33563211 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) {
33603215 return "duplicate";
33613216 }
33623217
3363 clcf->limit_except = 0xffffffff;
3218 pclcf->limit_except = 0xffffffff;
33643219
33653220 value = cf->args->elts;
33663221
33683223 for (name = ngx_methods_names; name->name; name++) {
33693224
33703225 if (ngx_strcasecmp(value[i].data, name->name) == 0) {
3371 clcf->limit_except &= name->method;
3226 pclcf->limit_except &= name->method;
33723227 goto next;
33733228 }
33743229 }
33813236 continue;
33823237 }
33833238
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;
33863241 }
33873242
33883243 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
34183273 }
34193274
34203275
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) {
34363283 return NGX_CONF_ERROR;
34373284 }
3438
3439 *clcfp = lcf;
3440
34413285
34423286 save = *cf;
34433287 cf->ctx = ctx;
2727 #define NGX_HTTP_SATISFY_ANY 1
2828
2929
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
3034 typedef struct {
3135 unsigned default_server:1;
3236 unsigned bind:1;
126130
127131
128132 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
138133 /* array of the ngx_http_listen_t, "listen" directive */
139 ngx_array_t listen;
134 ngx_array_t listen;
140135
141136 /* array of the ngx_http_server_name_t, "server_name" directive */
142 ngx_array_t server_names;
137 ngx_array_t server_names;
143138
144139 /* 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;
160157 } ngx_http_core_srv_conf_t;
161158
162159
230227 } ngx_http_err_page_t;
231228
232229
233 typedef struct ngx_http_core_loc_conf_s ngx_http_core_loc_conf_t;
234
235230 struct ngx_http_core_loc_conf_s {
236231 ngx_str_t name; /* location name */
237232
239234 ngx_regex_t *regex;
240235 #endif
241236
242 unsigned regex_start:15;
243
244237 unsigned noname:1; /* "if () {}" block or limit_except */
245238 unsigned named:1;
246239
250243 unsigned auto_redirect:1;
251244 unsigned alias:1;
252245
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;
255250
256251 /* pointer to the modules' loc_conf */
257252 void **loc_conf;
335330 #if 0
336331 ngx_http_core_loc_conf_t *prev_location;
337332 #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];
338358 };
339359
340360