1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "location.h"
30 #include "config.h"
31 #include "request.h"
32 #include "rewrite.h"
33 #include "../util/util.h"
34 #include "../util/pblock.h"
35 #include "../util/pool.h"
36 #include "vserver.h"
37 #include <cx/linked_list.h>
38 #include <cx/array_list.h>
39
40 #define DIR_CHECK_ARGC(n)
if(argc != n) { \
41 log_ereport(
LOG_FAILURE,
"%s directive argc != %d", name.ptr, n); \
42 return 1; \
43 }
44
45 static void location_list_add(WSLocation *location, WSLocation *sub) {
46 void **begin = (
void**)&location->children_begin;
47 void **end = (
void**)&location->children_end;
48 cx_linked_list_add(begin, end, offsetof(WSLocation, prev), offsetof(WSLocation, next), sub);
49 }
50
51 static int add_location_config(ServerConfiguration *cfg, WSLocation *location, ConfigNode *dir) {
52 const CxAllocator *a = cfg->a;
53
54 cxmutstr name = dir->name;
55 int argc = serverconfig_directive_count_args(dir);
56 if(!cx_strcasecmp(name,
"DirectoryIndex")) {
57 DIR_CHECK_ARGC(
1);
58 location->config.set_dirindex =
TRUE;
59 location->config.dirindex = util_getboolean_s(cx_strcast(dir->args->value),
FALSE);
60 }
else if(!cx_strcasecmp(name,
"DocumentRoot")) {
61 DIR_CHECK_ARGC(
1);
62 location->config.docroot = cx_strdup_a(a, dir->args->value);
63 }
else if(!cx_strcasecmp(name,
"AddACL")) {
64 DIR_CHECK_ARGC(
1);
65 if(!location->config.acls) {
66 CxList *aclList = cxLinkedListCreate(cfg->a,
NULL,
CX_STORE_POINTERS);
67 if(!aclList) {
68 return 1;
69 }
70 location->config.acls = aclList;
71 cxmutstr aclName = dir->args->value;
72 if(cxListAdd(aclList, aclName.ptr)) {
73 return 1;
74 }
75 }
76 }
else if(!cx_strcasecmp(name,
"VFS")) {
77 DIR_CHECK_ARGC(
1);
78 location->config.vfs = cx_strdup_a(a, dir->args->value);
79 VfsType *vfs = vfs_get_type(cx_strcast(location->config.vfs));
80 if(!vfs) {
81 log_ereport(
LOG_MISCONFIG,
"unknown VFS type %s", location->config.vfs.ptr);
82 }
83 }
else if(!cx_strcasecmp(name,
"Location")) {
84 WSLocation *sub_location = cfg_location_get(cfg, dir);
85 if(!sub_location) {
86 return 1;
87 }
88 location_list_add(location, sub_location);
89 }
else if(!cx_strcasecmp(name,
"Rewrite")) {
90 cxmutstr regex = (cxmutstr){
NULL,
0};
91 cxmutstr url = (cxmutstr){
NULL,
0};
92 if(argc ==
1) {
93
94 url = dir->args->value;
95 }
else if(argc ==
2) {
96
97 regex = dir->args->value;
98 url = dir->args->next->value;
99 }
else {
100 log_ereport(
LOG_FAILURE,
"rewrite [regex] <url>: illegal argc %d", argc);
101 return 1;
102 }
103
104 RewriteRule *rule = rewrite_rule_create(cfg, regex, url);
105 if(!rule) {
106 return 1;
107 }
108
109 if(!location->rewrite) {
110 location->rewrite = cxLinkedListCreate(a,
NULL,
CX_STORE_POINTERS);
111 if(!location->rewrite) {
112 return 1;
113 }
114 }
115
116 if(cxListAdd(location->rewrite, rule)) {
117 return 1;
118 }
119 }
120
121 return 0;
122 }
123
124
125 static void location_free_regex(WSLocation *loc) {
126 regfree(&loc->regex);
127 }
128
129 WSLocation* cfg_location_get(ServerConfiguration *cfg, ConfigNode *obj) {
130 const CxAllocator *a = cfg->a;
131
132 WSLocationMatch match =
WS_LOCATION_MATCH_EXACT;
133 cxmutstr match_str;
134
135 int regex_flags =
REG_EXTENDED;
136 int argc = serverconfig_directive_count_args(obj);
137 if(argc ==
2) {
138
139 cxmutstr type_str = obj->args->value;
140 if(!cx_strcmp(type_str,
"=")) {
141
142 }
else if(!cx_strcmp(type_str,
"^~")) {
143 match =
WS_LOCATION_MATCH_PREFIX;
144 }
else if(!cx_strcmp(type_str,
"~")) {
145 match =
WS_LOCATION_MATCH_CS_REGEX;
146 }
else if(!cx_strcmp(type_str,
"~*")) {
147 match =
WS_LOCATION_MATCH_CI_REGEX;
148 regex_flags |=
REG_ICASE;
149 }
else {
150 log_ereport(
LOG_FAILURE,
"Location: unknown operator %.*s", (
int)type_str.length, type_str.ptr);
151 return NULL;
152 }
153
154
155 match_str = obj->args->next->value;
156 }
else if(argc ==
1) {
157
158 match_str = obj->args->value;
159 }
else if(argc >
2) {
160 log_ereport(
LOG_FAILURE,
"Location directive must have 0-2 args");
161 return NULL;
162 }
163
164 WSLocation *location = cxZalloc(a,
sizeof(WSLocation));
165 location->match = match;
166 location->match_string = cx_strdup_a((a), match_str);
167
168 if(match ==
WS_LOCATION_MATCH_CS_REGEX || match ==
WS_LOCATION_MATCH_CI_REGEX) {
169 if(regcomp(&location->regex, match_str.ptr, regex_flags)) {
170 log_ereport(
LOG_FAILURE,
"Location: cannot compile regex pattern %s", match_str.ptr);
171 return NULL;
172 }
173 ScfgDestr destr;
174 destr.destr = (cx_destructor_func)location_free_regex;
175 destr.data = location;
176 if(cxListAdd(cfg->destr, &destr)) {
177 return NULL;
178 }
179 }
180
181 ConfigNode *dir = obj->children_begin;
182 while(dir) {
183 if(dir->type ==
CONFIG_NODE_OBJECT || dir->type ==
CONFIG_NODE_DIRECTIVE) {
184 if(add_location_config(cfg, location, dir)) {
185 log_ereport(
LOG_FAILURE,
"Location %s: abort", match_str.ptr);
186 return NULL;
187 }
188 }
189 dir = dir->next;
190 }
191
192
193
194 return location;
195 }
196
197 int location_apply_config(WSLocationConfig *target, WSLocation *loc) {
198 WSLocationConfig *src = &loc->config;
199 if(src->set_dirindex) {
200 target->set_dirindex =
TRUE;
201 target->dirindex = src->dirindex;
202 }
203 if(src->set_forcetls) {
204 target->set_forcetls =
TRUE;
205 target->forcetls = src->forcetls;
206 }
207 if(src->docroot.ptr) {
208 target->docroot = src->docroot;
209 }
210 if(src->name.ptr) {
211 target->name = src->name;
212 }
213 if(src->dav) {
214 target->dav = src->dav;
215 }
216
217
218 return 0;
219 }
220
221 int location_match(WSLocation *loc, cxstring uri,
regmatch_t *match) {
222 if(loc->match ==
WS_LOCATION_MATCH_EXACT) {
223 return !cx_strcmp(loc->match_string, uri);
224 }
else if(loc->match ==
WS_LOCATION_MATCH_PREFIX) {
225 return cx_strprefix(uri, loc->match_string);
226 }
else {
227 return regexec(&loc->regex, uri.ptr,
WS_LOCATION_NMATCH, match,
0) ==
0;
228 }
229 return 0;
230 }
231
232 WSLocationConfig* location_match_and_get_config(
pool_handle_t *pool, Request *rq, cxstring uri, WSLocation *loc) {
233 WSLocationConfig *config = pool_malloc(pool,
sizeof(WSLocationConfig));
234 if(!config) {
235 return NULL;
236 }
237 ZERO(config,
sizeof(WSLocationConfig));
238 for(
int i=
0;i<
WS_LOCATION_NMATCH;i++) {
239 config->match[i].rm_so =
-1;
240 config->match[i].rm_eo =
-1;
241 }
242
243 const CxAllocator *a = pool_allocator(pool);
244
245 while(loc) {
246 if(location_match(loc, uri, config->match)) {
247
248 CxIterator iter = cxListIterator(loc->rewrite);
249 cx_foreach(RewriteRule *, rule, iter) {
250 char *new_url =
NULL;
251 if(!rewrite_url(rule, config->match,
WS_LOCATION_NMATCH, a, uri.ptr, &new_url)) {
252 pblock_removekey(pb_key_uri, rq->reqpb);
253 if(pblock_kvinsert(pb_key_uri, new_url, strlen(new_url), rq->reqpb) ==
NULL) {
254 return NULL;
255 }
256 }
257 }
258
259 if(location_apply_config(config, loc)) {
260 return NULL;
261 }
262 }
263 loc = loc->next;
264 }
265
266
267 return config;
268 }
269
270 WSLocationConfig* cfg_location_match(Session *sn, Request *rq) {
271 NSAPIRequest *req = (NSAPIRequest*)rq;
272 WSLocation *loc = req->vs->locations_begin;
273 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
274 return location_match_and_get_config(sn->pool, rq, cx_str(uri), loc);
275 }
276