src/server/webdav/requestparser.c

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

mercurial