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