49 } |
50 } |
50 ZERO(ms, sizeof(Multistatus)); |
51 ZERO(ms, sizeof(Multistatus)); |
51 ms->response.addresource = multistatus_addresource; |
52 ms->response.addresource = multistatus_addresource; |
52 ms->sn = sn; |
53 ms->sn = sn; |
53 ms->rq = rq; |
54 ms->rq = rq; |
54 ms->namespaces = ucx_map_new_a(session_get_allocator(ms->sn), 8); |
55 ms->namespaces = cxHashMapCreate(pool_allocator(sn->pool), 8); |
55 ms->proppatch = FALSE; |
56 ms->proppatch = FALSE; |
56 if(!ms->namespaces) { |
57 if(!ms->namespaces) { |
57 return NULL; |
58 return NULL; |
58 } |
59 } |
59 if(ucx_map_cstr_put(ms->namespaces, "D", webdav_dav_namespace())) { |
60 if(cxMapPut(ms->namespaces, cx_hash_key_str("D"), webdav_dav_namespace())) { |
60 return NULL; |
61 return NULL; |
61 } |
62 } |
62 return ms; |
63 return ms; |
63 } |
64 } |
64 |
65 |
65 static int send_xml_root(Multistatus *ms, Writer *out) { |
66 static int send_xml_root(Multistatus *ms, Writer *out) { |
66 writer_puts(out, S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" |
67 writer_put_lit(out, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" |
67 "<D:multistatus")); |
68 "<D:multistatus"); |
68 |
69 |
69 // write the namespaces definitions |
70 // write the namespaces definitions |
70 // key is the namespace prefix |
71 // key is the namespace prefix |
71 // the map always contains the "DAV:" namespace with the prefix "D" |
72 // the map always contains the "DAV:" namespace with the prefix "D" |
72 UcxMapIterator i = ucx_map_iterator(ms->namespaces); |
73 CxIterator i = cxMapIterator(ms->namespaces); |
73 WSNamespace *ns; |
74 cx_foreach(CxMapEntry*, entry, i) { |
74 UCX_MAP_FOREACH(key, ns, i) { |
75 WSNamespace *ns = entry->value; |
75 writer_puts(out, S(" xmlns:")); |
76 writer_put_lit(out, " xmlns:"); |
76 writer_put(out, key.data, key.len); |
77 writer_put (out, entry->key->data.str, entry->key->len); |
77 writer_puts(out, S("=\"")); |
78 writer_put_lit(out, "=\""); |
78 writer_puts(out, sstr((char*)ns->href)); |
79 writer_put_str(out, (char*)ns->href); |
79 writer_puts(out, S("\"")); |
80 writer_put_lit(out, "\""); |
80 } |
81 } |
81 |
82 |
82 writer_puts(out, S(">\n")); |
83 writer_put_lit(out, ">\n"); |
83 |
84 |
84 return out->error; |
85 return out->error; |
85 } |
86 } |
86 |
87 |
87 static void send_nsdef(WSNamespace *ns, Writer *out) { |
88 static void send_nsdef(WSNamespace *ns, Writer *out) { |
88 writer_puts(out, S(" xmlns:")); |
89 writer_put_lit(out, " xmlns:"); |
89 writer_puts(out, sstr((char*)ns->prefix)); |
90 writer_put_str(out, (char*)ns->prefix); |
90 writer_puts(out, S("=\"")); |
91 writer_put_lit(out, "=\""); |
91 writer_puts(out, sstr((char*)ns->href)); |
92 writer_put_str(out, (char*)ns->href); |
92 writer_putc(out, '\"'); |
93 writer_putc (out, '\"'); |
93 } |
94 } |
94 |
95 |
95 static void send_string_escaped(Writer *out, sstr_t str) { |
96 static void send_string_escaped(Writer *out, cxmutstr str) { |
96 char *begin = str.ptr; |
97 char *begin = str.ptr; |
97 char *end = begin; |
98 char *end = begin; |
98 char *escape = NULL; |
99 char *escape = NULL; |
99 int esclen; |
100 int esclen; |
100 for(size_t i=0;i<str.length;i++) { |
101 for(size_t i=0;i<str.length;i++) { |
148 WebdavNSList *nsdef, |
149 WebdavNSList *nsdef, |
149 WSBool writeContent, |
150 WSBool writeContent, |
150 Writer *out) |
151 Writer *out) |
151 { |
152 { |
152 // write: "<prefix:name" |
153 // write: "<prefix:name" |
153 writer_putc(out, '<'); |
154 writer_putc (out, '<'); |
154 writer_puts(out, sstr((char*)property->namespace->prefix)); |
155 writer_put_str(out, (char*)property->namespace->prefix); |
155 writer_putc(out, ':'); |
156 writer_putc (out, ':'); |
156 writer_puts(out, sstr((char*)property->name)); |
157 writer_put_str(out, (char*)property->name); |
157 |
158 |
158 // send additional namespace definitions required for the value |
159 // send additional namespace definitions required for the value |
159 WebdavNSList *def = nsdef; |
160 WebdavNSList *def = nsdef; |
160 while(def) { |
161 while(def) { |
161 send_nsdef(def->namespace, out); |
162 send_nsdef(def->namespace, out); |
162 def = def->next; |
163 def = def->next; |
163 } |
164 } |
164 |
165 |
165 // send xml lang attribute |
166 // send xml lang attribute |
166 if(property->lang) { |
167 if(property->lang) { |
167 writer_puts(out, S(" xml:lang=\"")); |
168 writer_put_lit(out, " xml:lang=\""); |
168 writer_puts(out, sstr((char*)property->lang)); |
169 writer_put_str(out, (char*)property->lang); |
169 writer_putc(out, '\"'); |
170 writer_putc (out, '\"'); |
170 } |
171 } |
171 |
172 |
172 // end property tag and write content |
173 // end property tag and write content |
173 if(writeContent) { |
174 if(writeContent) { |
174 writer_putc(out, '>'); |
175 writer_putc(out, '>'); |
200 break; |
201 break; |
201 } |
202 } |
202 } |
203 } |
203 |
204 |
204 // end tag |
205 // end tag |
205 writer_puts(out, S("</")); |
206 writer_put_lit(out, "</"); |
206 writer_puts(out, sstr((char*)property->namespace->prefix)); |
207 writer_put_str(out, (char*)property->namespace->prefix); |
207 writer_putc(out, ':'); |
208 writer_putc (out, ':'); |
208 writer_puts(out, sstr((char*)property->name)); |
209 writer_put_str(out, (char*)property->name); |
209 writer_putc(out, '>'); |
210 writer_putc (out, '>'); |
210 } else { |
211 } else { |
211 writer_puts(out, S("/>")); |
212 writer_put_lit(out, "/>"); |
212 } |
213 } |
213 |
214 |
214 return out->error; |
215 return out->error; |
215 } |
216 } |
216 |
217 |
217 static int send_response_tag(Multistatus *ms, MSResponse *rp, Writer *out) { |
218 static int send_response_tag(Multistatus *ms, MSResponse *rp, Writer *out) { |
218 writer_puts(out, S(" <D:response>\n" |
219 writer_put_lit(out, " <D:response>\n" |
219 " <D:href>")); |
220 " <D:href>"); |
220 //writer_puts(out, sstr(rp->resource.href)); |
221 send_string_escaped(out, cx_mutstr(rp->resource.href)); |
221 send_string_escaped(out, sstr(rp->resource.href)); |
222 writer_put_lit(out, "</D:href>\n"); |
222 writer_puts(out, S("</D:href>\n")); |
|
223 |
223 |
224 WSBool writeContent = ms->proppatch ? FALSE : TRUE; |
224 WSBool writeContent = ms->proppatch ? FALSE : TRUE; |
225 |
225 |
226 if(rp->plist_begin) { |
226 if(rp->plist_begin) { |
227 writer_puts(out, S(" <D:propstat>\n" |
227 writer_put_lit(out, " <D:propstat>\n" |
228 " <D:prop>\n")); |
228 " <D:prop>\n"); |
229 // send properties |
229 // send properties |
230 PropertyOkList *p = rp->plist_begin; |
230 PropertyOkList *p = rp->plist_begin; |
231 while(p) { |
231 while(p) { |
232 writer_puts(out, S(" ")); |
232 writer_put_lit(out, " "); |
233 if(send_property(ms, p->property, p->nsdef, writeContent, out)) { |
233 if(send_property(ms, p->property, p->nsdef, writeContent, out)) { |
234 return out->error; |
234 return out->error; |
235 } |
235 } |
236 writer_puts(out, S("\n")); |
236 writer_put_lit(out, "\n"); |
237 p = p->next; |
237 p = p->next; |
238 } |
238 } |
239 |
239 |
240 writer_puts(out, S(" </D:prop>\n" |
240 writer_put_lit(out, " </D:prop>\n" |
241 " <D:status>HTTP/1.1 200 OK</D:status>\n" |
241 " <D:status>HTTP/1.1 200 OK</D:status>\n" |
242 " </D:propstat>\n")); |
242 " </D:propstat>\n"); |
243 } |
243 } |
244 |
244 |
245 // send error properties |
245 // send error properties |
246 PropertyErrorList *error = rp->errors; |
246 PropertyErrorList *error = rp->errors; |
247 while(error) { |
247 while(error) { |
248 writer_puts(out, S(" <D:propstat>\n" |
248 writer_put_lit(out, " <D:propstat>\n" |
249 " <D:prop>\n")); |
249 " <D:prop>\n"); |
250 |
250 |
251 WebdavPList *errprop = error->begin; |
251 WebdavPList *errprop = error->begin; |
252 while(errprop) { |
252 while(errprop) { |
253 writer_puts(out, S(" ")); |
253 writer_put_lit(out, " "); |
254 if(send_property(ms, errprop->property, NULL, FALSE, out)) { |
254 if(send_property(ms, errprop->property, NULL, FALSE, out)) { |
255 return out->error; |
255 return out->error; |
256 } |
256 } |
257 writer_putc(out, '\n'); |
257 writer_putc(out, '\n'); |
258 errprop = errprop->next; |
258 errprop = errprop->next; |
265 statuscode[1] = '0'; |
265 statuscode[1] = '0'; |
266 statuscode[2] = '0'; |
266 statuscode[2] = '0'; |
267 statuscode[3] = ' '; |
267 statuscode[3] = ' '; |
268 sclen = 4; |
268 sclen = 4; |
269 } |
269 } |
270 writer_puts(out, S(" </D:prop>\n" |
270 writer_put_lit(out, " </D:prop>\n" |
271 " <D:status>HTTP/1.1 ")); |
271 " <D:status>HTTP/1.1 "); |
272 writer_put(out, statuscode, sclen); |
272 writer_put(out, statuscode, sclen); |
273 const char *status_msg = protocol_status_message(error->status); |
273 const char *status_msg = protocol_status_message(error->status); |
274 if(status_msg) { |
274 if(status_msg) { |
275 writer_put(out, status_msg, strlen(status_msg)); |
275 writer_put(out, status_msg, strlen(status_msg)); |
276 } else { |
276 } else { |
277 writer_puts(out, S("Server Error")); |
277 writer_put_lit(out, "Server Error"); |
278 } |
278 } |
279 writer_puts(out, S("</D:status>\n" |
279 writer_put_lit(out, "</D:status>\n" |
280 " </D:propstat>\n")); |
280 " </D:propstat>\n"); |
281 |
281 |
282 |
282 |
283 error = error->next; |
283 error = error->next; |
284 } |
284 } |
285 |
285 |
286 // end response tag |
286 // end response tag |
287 writer_puts(out, S(" </D:response>\n")); |
287 writer_put_lit(out, " </D:response>\n"); |
288 |
288 |
289 return out->error; |
289 return out->error; |
290 } |
290 } |
291 |
291 |
292 int multistatus_send(Multistatus *ms, SYS_NETFD net) { |
292 int multistatus_send(Multistatus *ms, SYS_NETFD net) { |
455 // we have the list -> add the new element |
454 // we have the list -> add the new element |
456 if(webdav_plist_add(pool, &errlist->begin, &errlist->end, property)) { |
455 if(webdav_plist_add(pool, &errlist->begin, &errlist->end, property)) { |
457 return 1; |
456 return 1; |
458 } |
457 } |
459 return 0; |
458 return 0; |
|
459 } |
|
460 |
|
461 static CxHashKey ms_property_key( |
|
462 CxAllocator *a, |
|
463 const xmlChar *href, |
|
464 const char *property_name) |
|
465 { |
|
466 cxmutstr key_data = cx_strcat_a(a, 3, cx_str((const char*)href), (cxstring){ "\0", 1 }, cx_str(property_name)); |
|
467 return cx_hash_key_bytes((unsigned char*)key_data.ptr, key_data.length); |
460 } |
468 } |
461 |
469 |
462 int msresponse_addproperty( |
470 int msresponse_addproperty( |
463 WebdavResource *res, |
471 WebdavResource *res, |
464 WebdavProperty *property, |
472 WebdavProperty *property, |
484 property->name); |
492 property->name); |
485 return 1; |
493 return 1; |
486 } |
494 } |
487 |
495 |
488 // check if the property was already added to the resource |
496 // check if the property was already added to the resource |
489 UcxAllocator *a = session_get_allocator(sn); |
497 CxAllocator *a = pool_allocator(sn->pool); |
490 sstr_t key = sstrcat_a( |
498 CxHashKey key = ms_property_key(a, property->namespace->href, property->name); |
491 a, |
499 if(cxMapGet(response->properties, key)) { |
492 3, |
500 cxFree(a, key.data.bytes); |
493 sstr((char*)property->namespace->href), |
|
494 S("\0"), |
|
495 sstr((char*)property->name)); |
|
496 if(ucx_map_sstr_get(response->properties, key)) { |
|
497 a->free(a->pool, key.ptr); |
|
498 return 0; |
501 return 0; |
499 } |
502 } |
500 if(ucx_map_sstr_put(response->properties, key, property)) { |
503 if(cxMapPut(response->properties, key, property)) { |
501 return 1; // OOM |
504 return 1; // OOM |
502 } |
505 } |
503 a->free(a->pool, key.ptr); |
506 cxFree(a, key.data.bytes); |
504 |
507 |
505 // list of namespace definitions for this property |
508 // list of namespace definitions for this property |
506 WebdavNSList *nsdef_begin = NULL; |
509 WebdavNSList *nsdef_begin = NULL; |
507 WebdavNSList *nsdef_end = NULL; |
510 WebdavNSList *nsdef_end = NULL; |
508 |
511 |
509 // add namespace of this property to the namespace map |
512 // add namespace of this property to the namespace map |
510 // the namespace map will be used for global namespace definitions |
513 // the namespace map will be used for global namespace definitions |
511 if(property->namespace->prefix) { |
514 if(property->namespace->prefix) { |
512 WSNamespace *ns = ucx_map_cstr_get( |
515 WSNamespace *ns = cxMapGet( |
513 response->multistatus->namespaces, |
516 response->multistatus->namespaces, |
514 (const char*)property->namespace->prefix); |
517 cx_hash_key_str((const char*)property->namespace->prefix)); |
515 if(!ns) { |
518 if(!ns) { |
516 // prefix is not in use -> we can add the namespace to the ns map |
519 // prefix is not in use -> we can add the namespace to the ns map |
517 int err = ucx_map_cstr_put( |
520 int err = cxMapPut( |
518 response->multistatus->namespaces, |
521 response->multistatus->namespaces, |
519 (const char*)property->namespace->prefix, |
522 cx_hash_key_str((const char*)property->namespace->prefix), |
520 property->namespace); |
523 property->namespace); |
521 if(err) { |
524 if(err) { |
522 return 1; // OOM |
525 return 1; // OOM |
523 } |
526 } |
524 } else if( |
527 } else if( |
620 if(op->response_close(op, res)) { |
623 if(op->response_close(op, res)) { |
621 ret = REQ_ABORTED; |
624 ret = REQ_ABORTED; |
622 } |
625 } |
623 |
626 |
624 // add missing properties with status code 404 |
627 // add missing properties with status code 404 |
625 UcxAllocator *a = session_get_allocator(ms->sn); |
628 CxAllocator *a = pool_allocator(ms->sn->pool); |
626 WebdavPList *pl = ms->response.op->reqprops; |
629 WebdavPList *pl = ms->response.op->reqprops; |
627 while(pl) { |
630 while(pl) { |
628 sstr_t key = sstrcat_a( |
631 CxHashKey key = ms_property_key(a, pl->property->namespace->href, pl->property->name); |
629 a, |
632 if(!cxMapGet(response->properties, key)) { |
630 3, |
|
631 sstr((char*)pl->property->namespace->href), |
|
632 S("\0"), |
|
633 sstr((char*)pl->property->name)); |
|
634 if(!ucx_map_sstr_get(response->properties, key)) { |
|
635 // property was not added to this response |
633 // property was not added to this response |
636 if(ms->proppatch) { |
634 if(ms->proppatch) { |
637 if(msresponse_addproperty(res, pl->property, 424)) { |
635 if(msresponse_addproperty(res, pl->property, 424)) { |
638 ret = REQ_ABORTED; |
636 ret = REQ_ABORTED; |
639 break; |
637 break; |