src/server/webdav/requestparser.c

changeset 385
a1f4cb076d2f
parent 373
f78a585e1a2f
child 415
d938228c382e
equal deleted inserted replaced
210:21274e5950af 385:a1f4cb076d2f
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2019 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 <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <ucx/string.h>
34 #include <ucx/utils.h>
35 #include <ucx/map.h>
36
37 #include "requestparser.h"
38 #include "webdav.h"
39
40 #define xstreq(a, b) !strcmp((const char*)a, (const char*)b)
41
42 void proplist_free(pool_handle_t *pool, WebdavPList *list) {
43 while(list) {
44 WebdavPList *next = list->next;
45 pool_free(pool, list);
46 list = next;
47 }
48 }
49
50 WebdavProperty* prop_create(
51 pool_handle_t *pool,
52 WSNamespace *ns,
53 const char *name)
54 {
55 WebdavProperty *prop = pool_malloc(pool, sizeof(WebdavProperty));
56 memset(prop, 0, sizeof(WebdavProperty));
57 prop->lang = NULL;
58 prop->name = (char*)name;
59 prop->namespace = ns;
60 return prop;
61 }
62
63 static int parse_prop(
64 Session *sn,
65 xmlNode *node,
66 UcxMap *propmap,
67 WebdavPList **plist_begin,
68 WebdavPList **plist_end,
69 size_t *propcount,
70 int proppatch,
71 int *error)
72 {
73 xmlNode *pnode = node->children;
74 for(;pnode;pnode=pnode->next) {
75 if(pnode->type != XML_ELEMENT_NODE) {
76 continue;
77 }
78
79 const char* ns = (const char*)pnode->ns->href;
80 const char* name = (const char*)pnode->name;
81
82 // check for prop duplicates
83 UcxKey k = webdav_property_key((const char*)ns, (const char*)name);
84 if(!k.data) {
85 *error = proppatch ? PROPPATCH_PARSER_OOM : PROPFIND_PARSER_OOM;
86 return 1;
87 }
88 void *c = ucx_map_get(propmap, k);
89 if(!c) {
90 if(ucx_map_put(propmap, k, (void*)1)) {
91 *error = proppatch ? PROPPATCH_PARSER_OOM : PROPFIND_PARSER_OOM;
92 }
93
94 // no duplicate
95 // create property elment and add it to the list
96 WebdavProperty *prop = prop_create(sn->pool, pnode->ns, name);
97 if(proppatch) {
98 prop->value.node = pnode->children;
99 prop->vtype = WS_VALUE_XML_NODE;
100 }
101 if(prop) {
102 if(webdav_plist_add(sn->pool, plist_begin, plist_end, prop)) {
103 *error = proppatch ?
104 PROPPATCH_PARSER_OOM : PROPFIND_PARSER_OOM;
105 }
106 (*propcount)++;
107 } else {
108 *error = proppatch ? PROPPATCH_PARSER_OOM : PROPFIND_PARSER_OOM;
109 }
110 } else if(proppatch) {
111 *error = PROPPATCH_PARSER_DUPLICATE;
112 }
113
114 free((void*)k.data);
115 if(*error) {
116 return 1;
117 }
118 }
119 return 0;
120 }
121
122 WebdavPropfindRequest* propfind_parse(
123 Session *sn,
124 Request *rq,
125 const char *buf,
126 size_t buflen,
127 int *error)
128 {
129 xmlDoc *doc = xmlReadMemory(buf, buflen, NULL, NULL, 0);
130 if(!doc) {
131 *error = PROPFIND_PARSER_INVALID_REQUEST;
132 return NULL;
133 }
134
135 // ret vars
136 *error = 0;
137
138 WSBool allprop = FALSE;
139 WSBool propname = FALSE;
140 WebdavPList *plist_begin = NULL;
141 WebdavPList *plist_end = NULL;
142 size_t propcount = 0;
143 int depth = webdav_getdepth(rq);
144
145 xmlNode *root = xmlDocGetRootElement(doc);
146 xmlNode *node = root->children;
147
148 // check if the root element is DAV:propfind
149 if(
150 !(root->ns
151 && xstreq(root->ns->href, "DAV:")
152 && xstreq(root->name, "propfind")))
153 {
154 *error = PROPFIND_PARSER_NO_PROPFIND;
155 xmlFreeDoc(doc);
156 return NULL;
157 }
158
159 UcxMap *propmap = ucx_map_new(32);
160 if(!propmap) {
161 *error = PROPFIND_PARSER_OOM;
162 xmlFreeDoc(doc);
163 return NULL;
164 }
165
166 int ret = 0;
167 while(node && !ret) {
168 if(node->type == XML_ELEMENT_NODE) {
169 if(xstreq(node->ns->href, "DAV:") && !allprop && !propname) {
170 // a propfind request can contain a prop element
171 // with specified properties or the allprop or propname
172 // element
173 if(xstreq(node->name, "prop")) {
174 ret = parse_prop(
175 sn,
176 node,
177 propmap,
178 &plist_begin,
179 &plist_end,
180 &propcount,
181 0, // proppatch = false
182 error);
183 } else if(xstreq(node->name, "allprop")) {
184 allprop = TRUE;
185 } else if(xstreq(node->name, "propname")) {
186 propname = TRUE;
187 }
188 }
189 }
190 node = node->next;
191 }
192
193 ucx_map_free(propmap); // no allocated content must be freed
194
195 if(ret) {
196 // parse_prop failed
197 // in this case, error is already set
198 xmlFreeDoc(doc);
199 return NULL;
200 }
201
202 if(!allprop && !propname && propcount == 0) {
203 *error = PROPFIND_PARSER_NO_PROPERTIES;
204 xmlFreeDoc(doc);
205 return NULL;
206 }
207
208 WebdavPropfindRequest *request = pool_malloc(
209 sn->pool,
210 sizeof(WebdavPropfindRequest));
211 if(!request) {
212 *error = PROPFIND_PARSER_OOM;
213 xmlFreeDoc(doc);
214 return NULL;
215 }
216 request->sn = sn;
217 request->rq = rq;
218 request->properties = NULL;
219 request->propcount = 0;
220 request->depth = depth;
221 request->doc = doc;
222 if(allprop) {
223 request->allprop = TRUE;
224 request->propname = FALSE; // we cannot have allprop and propname
225 } else if(propname) {
226 request->allprop = FALSE;
227 request->propname = TRUE;
228 } else {
229 request->allprop = FALSE;
230 request->propname = FALSE;
231 request->properties = plist_begin;
232 request->propcount = propcount;
233 }
234
235 if(!request->properties && plist_begin) {
236 proplist_free(sn->pool, plist_begin);
237 }
238 return request;
239 }
240
241 WebdavProppatchRequest* proppatch_parse(
242 Session *sn,
243 Request *rq,
244 const char *buf,
245 size_t buflen,
246 int *error)
247 {
248 return webdav_parse_set(
249 sn, rq, buf, buflen, "DAV:", "propertyupdate", TRUE, error);
250 }
251
252 static xmlNode* find_child(xmlNode *node, const char *name) {
253 xmlNode *c = node->children;
254 while(c) {
255 if(c->ns) {
256 if(xstreq(c->ns->href, "DAV:") && xstreq(c->name, name)) {
257 return c;
258 }
259 }
260 c = c->next;
261 }
262 return NULL;
263 }
264
265 WebdavProppatchRequest* webdav_parse_set(
266 Session *sn,
267 Request *rq,
268 const char *buf,
269 size_t buflen,
270 const char *rootns,
271 const char *rootname,
272 WSBool allowremove,
273 int *error)
274 {
275 xmlDoc *doc = xmlReadMemory(buf, buflen, NULL, NULL, 0);
276 if(!doc) {
277 *error = PROPPATCH_PARSER_INVALID_REQUEST;
278 return NULL;
279 }
280
281 xmlNode *root = xmlDocGetRootElement(doc);
282 xmlNode *node = root->children;
283
284 // check if the root element is correct
285 if(
286 !(root->ns
287 && xstreq(root->ns->href, rootns)
288 && xstreq(root->name, rootname)))
289 {
290 *error = PROPPATCH_PARSER_NO_PROPERTYUPDATE;
291 xmlFreeDoc(doc);
292 return NULL;
293 }
294
295 // ret vars
296 *error = 0;
297
298 UcxMap *propmap = ucx_map_new(32); // map for duplicate checking
299 if(!propmap) {
300 *error = PROPPATCH_PARSER_OOM;
301 xmlFreeDoc(doc);
302 return NULL;
303 }
304
305 WebdavPList *set_begin = NULL;
306 WebdavPList *set_end = NULL;
307 WebdavPList *remove_begin = NULL;
308 WebdavPList *remove_end = NULL;
309 size_t set_count = 0;
310 size_t remove_count = 0;
311
312 int ret = 0;
313 while(node && !ret) {
314 if(node->type == XML_ELEMENT_NODE) {
315 if(node->ns && xstreq(node->ns->href, "DAV:")) {
316 // a propfind request can contain a prop element
317 // with specified properties or the allprop or propname
318 // element
319 if(xstreq(node->name, "set")) {
320 xmlNode *prop = find_child(node, "prop");
321 ret = parse_prop(
322 sn,
323 prop,
324 propmap,
325 &set_begin,
326 &set_end,
327 &set_count,
328 TRUE, // proppatch = true
329 error);
330 } else if(xstreq(node->name, "remove")) {
331 if(!allowremove) {
332 *error = PROPPATCH_PARSER_INVALID_REQUEST;
333 ret = 1;
334 break;
335 }
336 xmlNode *prop = find_child(node, "prop");
337 ret = parse_prop(
338 sn,
339 prop,
340 propmap,
341 &remove_begin,
342 &remove_end,
343 &remove_count,
344 TRUE, // proppatch = true
345 error);
346 }
347
348 }
349 }
350 node = node->next;
351 }
352
353 ucx_map_free(propmap); // allocated content must not be freed
354
355 if(set_count + remove_count == 0) {
356 *error = PROPPATCH_PARSER_NO_PROPERTIES;
357 ret = 1;
358 }
359
360 if(ret) {
361 xmlFreeDoc(doc);
362 return NULL;
363 }
364
365 WebdavProppatchRequest *request = pool_malloc(
366 sn->pool,
367 sizeof(WebdavProppatchRequest));
368 if(!request) {
369 *error = PROPPATCH_PARSER_OOM;
370 xmlFreeDoc(doc);
371 return NULL;
372 }
373 request->sn = sn;
374 request->rq = rq;
375 request->doc = doc;
376 request->set = set_begin;
377 request->setcount = set_count;
378 request->remove = remove_begin;
379 request->removecount = remove_count;
380 return request;
381 }
382
383 WebdavLockRequest* lock_parse(
384 Session *sn,
385 Request *rq,
386 const char *buf,
387 size_t buflen,
388 int *error)
389 {
390 xmlDoc *doc = xmlReadMemory(buf, buflen, NULL, NULL, 0);
391 if(!doc) {
392 *error = LOCK_PARSER_INVALID_REQUEST;
393 return NULL;
394 }
395
396 xmlNode *root = xmlDocGetRootElement(doc);
397 xmlNode *node = root->children;
398
399 // check if the root element is correct
400 if(
401 !(root->ns
402 && xstreq(root->ns->href, "DAV:")
403 && xstreq(root->name, "lockinfo")))
404 {
405 *error = LOCK_PARSER_NO_LOCKINFO;
406 xmlFreeDoc(doc);
407 return NULL;
408 }
409
410 WebdavLockScope lockscope = WEBDAV_LOCK_SCOPE_UNKNOWN;
411 WebdavLockType locktype = WEBDAV_LOCK_TYPE_UNKNOWN;
412 WSXmlNode *owner = NULL;
413
414 int ret = 0;
415 while(node && !ret) {
416 if(
417 node->type == XML_ELEMENT_NODE
418 && node->ns
419 && xstreq(node->ns->href, "DAV:"))
420 {
421 char *name = (char*)node->name;
422 if(xstreq(name, "lockscope")) {
423 xmlNode *s = node->children;
424 while(s) {
425 if(
426 s->type == XML_ELEMENT_NODE
427 && s->ns
428 && xstreq(s->ns->href, "DAV:"))
429 {
430 if(xstreq(s->name, "exclusive")) {
431 lockscope = WEBDAV_LOCK_EXCLUSIVE;
432 } else if(xstreq(s->name, "shared")) {
433 lockscope = WEBDAV_LOCK_SHARED;
434 } else {
435 // don't ignore unknown lockscope
436 *error = LOCK_PARSER_UNKNOWN_ELEMENT;
437 ret = 1;
438 break;
439 }
440 }
441 s = s->next;
442 }
443 } else if(xstreq(name, "locktype")) {
444 xmlNode *t = node->children;
445 while(t) {
446 if(
447 t->type == XML_ELEMENT_NODE
448 && t->ns
449 && xstreq(t->ns->href, "DAV:"))
450 {
451 if(xstreq(t->name, "write")) {
452 locktype = WEBDAV_LOCK_WRITE;
453 } else {
454 *error = LOCK_PARSER_UNKNOWN_ELEMENT;
455 ret = 1;
456 break;
457 }
458 }
459 t = t->next;
460 }
461 } else if(xstreq(name, "owner")) {
462 owner = node->children;
463 }
464 }
465 node = node->next;
466 }
467
468 if(ret) {
469 xmlFreeDoc(doc);
470 return NULL;
471 }
472
473 WebdavLockRequest *request = pool_malloc(
474 sn->pool,
475 sizeof(WebdavLockRequest));
476 if(!request) {
477 *error = LOCK_PARSER_OOM;
478 xmlFreeDoc(doc);
479 return NULL;
480 }
481 request->sn = sn;
482 request->rq = rq;
483 request->doc = doc;
484
485 if(locktype == WEBDAV_LOCK_TYPE_UNKNOWN) {
486 locktype = WEBDAV_LOCK_WRITE;
487 }
488 if(lockscope == WEBDAV_LOCK_SCOPE_UNKNOWN) {
489 lockscope = WEBDAV_LOCK_EXCLUSIVE;
490 }
491 request->scope = lockscope;
492 request->type = locktype;
493 request->owner = owner;
494 return request;
495 }
496

mercurial