| |
1 /* |
| |
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
| |
3 * |
| |
4 * Copyright 2025 Olaf Wintermann. All rights reserved. |
| |
5 * |
| |
6 * Redistribution and use in source and binary forms, with or without |
| |
7 * modification, are permitted provided that the following conditions are met: |
| |
8 * |
| |
9 * 1. Redistributions of source code must retain the above copyright |
| |
10 * notice, this list of conditions and the following disclaimer. |
| |
11 * |
| |
12 * 2. Redistributions in binary form must reproduce the above copyright |
| |
13 * notice, this list of conditions and the following disclaimer in the |
| |
14 * documentation and/or other materials provided with the distribution. |
| |
15 * |
| |
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| |
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| |
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| |
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| |
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| |
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| |
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| |
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| |
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| |
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| |
26 * POSSIBILITY OF SUCH DAMAGE. |
| |
27 */ |
| |
28 |
| |
29 #include "location.h" |
| |
30 #include "config.h" |
| |
31 #include "../util/util.h" |
| |
32 #include <cx/linked_list.h> |
| |
33 |
| |
34 #define DIR_CHECK_ARGC(n) if(argc != n) { \ |
| |
35 log_ereport(LOG_FAILURE, "%s directive argc != %d", name.ptr, n); \ |
| |
36 return 1; \ |
| |
37 } |
| |
38 |
| |
39 static void location_list_add(WSLocation *location, WSLocation *sub) { |
| |
40 void **begin = (void**)&location->children_begin; |
| |
41 void **end = (void**)&location->children_end; |
| |
42 cx_linked_list_add(begin, end, offsetof(WSLocation, prev), offsetof(WSLocation, next), sub); |
| |
43 } |
| |
44 |
| |
45 static int add_location_config(const CxAllocator *a, WSLocation *location, ConfigNode *dir) { |
| |
46 cxmutstr name = dir->name; |
| |
47 int argc = serverconfig_directive_count_args(dir); |
| |
48 if(!cx_strcasecmp(name, "DirectoryIndex")) { |
| |
49 DIR_CHECK_ARGC(1); |
| |
50 location->config.set_dirindex = TRUE; |
| |
51 location->config.dirindex = util_getboolean_s(cx_strcast(dir->args->value), FALSE); |
| |
52 } else if(!cx_strcasecmp(name, "DocumentRoot")) { |
| |
53 DIR_CHECK_ARGC(1); |
| |
54 location->config.docroot = cx_strdup_a(a, dir->args->value); |
| |
55 } else if(!cx_strcasecmp(name, "Location")) { |
| |
56 WSLocation *sub_location = cfg_location_get(a, dir); |
| |
57 if(!sub_location) { |
| |
58 return 1; |
| |
59 } |
| |
60 location_list_add(location, sub_location); |
| |
61 } |
| |
62 |
| |
63 return 0; |
| |
64 } |
| |
65 |
| |
66 |
| |
67 WSLocation* cfg_location_get(const CxAllocator *a, ConfigNode *obj) { |
| |
68 WSLocationMatch match = WS_LOCATION_MATCH_EXACT; |
| |
69 cxmutstr match_str; |
| |
70 |
| |
71 int regex_flags = REG_EXTENDED; |
| |
72 int argc = serverconfig_directive_count_args(obj); |
| |
73 if(argc == 2) { |
| |
74 // arg0: match type |
| |
75 cxmutstr type_str = obj->args->value; |
| |
76 if(!cx_strcmp(type_str, "=")) { |
| |
77 // noop |
| |
78 } else if(!cx_strcmp(type_str, "^~")) { |
| |
79 match = WS_LOCATION_MATCH_PREFIX; |
| |
80 } else if(!cx_strcmp(type_str, "~")) { |
| |
81 match = WS_LOCATION_MATCH_CS_REGEX; |
| |
82 } else if(!cx_strcmp(type_str, "~*")) { |
| |
83 match = WS_LOCATION_MATCH_CI_REGEX; |
| |
84 regex_flags |= REG_ICASE; |
| |
85 } else { |
| |
86 log_ereport(LOG_FAILURE, "Location: unknown operator %.*s", (int)type_str.length, type_str.ptr); |
| |
87 return NULL; |
| |
88 } |
| |
89 |
| |
90 // arg1: match_string |
| |
91 match_str = obj->args->next->value; |
| |
92 } else if(argc == 1) { |
| |
93 // arg0: match_string |
| |
94 match_str = obj->args->value; |
| |
95 } else if(argc > 2) { |
| |
96 log_ereport(LOG_FAILURE, "Location directive must have 0-2 args"); |
| |
97 return NULL; |
| |
98 } |
| |
99 |
| |
100 WSLocation *location = cxZalloc(a, sizeof(WSLocation)); |
| |
101 location->match_string = cx_strdup_a((a), match_str); |
| |
102 |
| |
103 if(match == WS_LOCATION_MATCH_CS_REGEX || match == WS_LOCATION_MATCH_CI_REGEX) { |
| |
104 if(regcomp(&location->regex, match_str.ptr, regex_flags)) { |
| |
105 log_ereport(LOG_FAILURE, "Location: cannot compile regex pattern %s", match_str.ptr); |
| |
106 return NULL; |
| |
107 } |
| |
108 } |
| |
109 |
| |
110 ConfigNode *dir = obj->children_begin; |
| |
111 while(dir) { |
| |
112 if(dir->type == CONFIG_NODE_OBJECT || dir->type == CONFIG_NODE_DIRECTIVE) { |
| |
113 if(add_location_config(a, location, dir)) { |
| |
114 log_ereport(LOG_FAILURE, "Location %s: abort", match_str.ptr); |
| |
115 return NULL; |
| |
116 } |
| |
117 } |
| |
118 dir = dir->next; |
| |
119 } |
| |
120 |
| |
121 |
| |
122 |
| |
123 return location; |
| |
124 } |