48 ms->rq = rq; |
51 ms->rq = rq; |
49 ms->namespaces = ucx_map_new_a(session_get_allocator(ms->sn), 8); |
52 ms->namespaces = ucx_map_new_a(session_get_allocator(ms->sn), 8); |
50 if(!ms->namespaces) { |
53 if(!ms->namespaces) { |
51 return NULL; |
54 return NULL; |
52 } |
55 } |
53 if(ucx_map_cstr_put(ms->namespaces, "D", "DAV:")) { |
56 if(ucx_map_cstr_put(ms->namespaces, "D", webdav_dav_namespace())) { |
54 return NULL; |
57 return NULL; |
55 } |
58 } |
56 return ms; |
59 return ms; |
|
60 } |
|
61 |
|
62 static int send_xml_root(Multistatus *ms, Writer *out) { |
|
63 writer_puts(out, S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" |
|
64 "<D:multistatus")); |
|
65 |
|
66 // write the namespaces definitions |
|
67 // key is the namespace prefix |
|
68 // the map always contains the "DAV:" namespace with the prefix "D" |
|
69 UcxMapIterator i = ucx_map_iterator(ms->namespaces); |
|
70 WSNamespace *ns; |
|
71 UCX_MAP_FOREACH(key, ns, i) { |
|
72 writer_puts(out, S(" xmlns:")); |
|
73 writer_put(out, key.data, key.len); |
|
74 writer_puts(out, S("=\"")); |
|
75 writer_puts(out, sstr((char*)ns->href)); |
|
76 writer_puts(out, S("\"")); |
|
77 } |
|
78 |
|
79 writer_puts(out, S(">\n")); |
|
80 |
|
81 return out->error; |
|
82 } |
|
83 |
|
84 static void send_nsdef(WSNamespace *ns, Writer *out) { |
|
85 writer_puts(out, S(" xmlns:")); |
|
86 writer_puts(out, sstr((char*)ns->prefix)); |
|
87 writer_puts(out, S("=\"")); |
|
88 writer_puts(out, sstr((char*)ns->href)); |
|
89 writer_putc(out, '\"'); |
|
90 } |
|
91 |
|
92 static int send_property( |
|
93 Multistatus *ms, |
|
94 WebdavProperty *property, |
|
95 WebdavNSList *nsdef, |
|
96 WSBool writeContent, |
|
97 Writer *out) |
|
98 { |
|
99 // write: "<prefix:name" |
|
100 writer_puts(out, S(" <")); |
|
101 writer_puts(out, sstr((char*)property->namespace->prefix)); |
|
102 writer_putc(out, ':'); |
|
103 writer_puts(out, sstr((char*)property->name)); |
|
104 |
|
105 // check if the namespace is already defined |
|
106 WSBool need_nsdef = TRUE; |
|
107 WSNamespace *ns = ucx_map_cstr_get( |
|
108 ms->namespaces, |
|
109 (char*)property->namespace->prefix); |
|
110 if(ns && !strcmp( |
|
111 (const char*)ns->href, |
|
112 (const char*)property->namespace->href)) |
|
113 { |
|
114 need_nsdef = FALSE; // prefix and href are the same, no need for nsdef |
|
115 } |
|
116 |
|
117 // send definition for the element's namespace |
|
118 if(need_nsdef) { |
|
119 send_nsdef(property->namespace, out); |
|
120 } |
|
121 |
|
122 // send additional namespace definitions required for the value |
|
123 WebdavNSList *def = nsdef; |
|
124 while(def) { |
|
125 send_nsdef(def->namespace, out); |
|
126 def = def->next; |
|
127 } |
|
128 |
|
129 // send xml lang attribute |
|
130 if(property->lang) { |
|
131 writer_puts(out, S(" xml:lang=\"")); |
|
132 writer_puts(out, sstr((char*)property->lang)); |
|
133 writer_putc(out, '\"'); |
|
134 } |
|
135 |
|
136 // end property tag and write content |
|
137 if(writeContent) { |
|
138 writer_putc(out, '>'); |
|
139 |
|
140 // content |
|
141 switch(property->vtype) { |
|
142 case WS_VALUE_NO_TYPE: break; |
|
143 case WS_VALUE_XML_NODE: { |
|
144 // TODO |
|
145 break; |
|
146 } |
|
147 case WS_VALUE_XML_DATA: { |
|
148 // only write data, data->namespaces is already handled |
|
149 writer_put( |
|
150 out, |
|
151 property->value.data->data, |
|
152 property->value.data->length); |
|
153 break; |
|
154 } |
|
155 case WS_VALUE_TEXT: { |
|
156 // asume the text is already escaped |
|
157 writer_put( |
|
158 out, |
|
159 property->value.text.str, |
|
160 property->value.text.length); |
|
161 break; |
|
162 } |
|
163 } |
|
164 |
|
165 // end tag |
|
166 writer_putc(out, '<'); |
|
167 writer_puts(out, sstr((char*)property->namespace->prefix)); |
|
168 writer_putc(out, ':'); |
|
169 writer_puts(out, sstr((char*)property->name)); |
|
170 writer_putc(out, '>'); |
|
171 } else { |
|
172 writer_putc(out, '/>'); |
|
173 } |
|
174 |
|
175 return out->error; |
|
176 } |
|
177 |
|
178 static int send_response_tag(Multistatus *ms, MSResponse *rp, Writer *out) { |
|
179 writer_puts(out, S(" <D:response>\n" |
|
180 " <D:href>")); |
|
181 writer_puts(out, sstr(rp->resource.href)); |
|
182 writer_puts(out, S("</href>\n")); |
|
183 |
|
184 if(rp->plist_begin) { |
|
185 writer_puts(out, S(" <D:propstat>" |
|
186 " <D:prop>\n")); |
|
187 // send properties |
|
188 PropertyOkList *p = rp->plist_begin; |
|
189 while(p) { |
|
190 if(send_property(ms, p->property, p->nsdef, TRUE, out)) { |
|
191 return out->error; |
|
192 } |
|
193 p = p->next; |
|
194 } |
|
195 |
|
196 writer_puts(out, S(" </D:prop>\n" |
|
197 " <D:status>HTTP/1.1 200 OK</D:status>" |
|
198 " </D:propstat>\n")); |
|
199 } |
|
200 |
|
201 // send error properties |
|
202 PropertyErrorList *error = rp->errors; |
|
203 while(error) { |
|
204 WebdavPList *errprop = error->begin; |
|
205 while(errprop) { |
|
206 if(send_property(ms, errprop->property, NULL, FALSE, out)) { |
|
207 return out->error; |
|
208 } |
|
209 errprop = errprop->next; |
|
210 } |
|
211 error = error->next; |
|
212 } |
|
213 |
|
214 return out->error; |
57 } |
215 } |
58 |
216 |
59 int multistatus_send(Multistatus *ms, SYS_NETFD net) { |
217 int multistatus_send(Multistatus *ms, SYS_NETFD net) { |
60 char buffer[MULTISTATUS_BUFFER_LENGTH]; |
218 char buffer[MULTISTATUS_BUFFER_LENGTH]; |
61 // create a writer, that flushes the buffer when it is filled |
219 // create a writer, that flushes the buffer when it is filled |
62 Writer writer; |
220 Writer writer; |
63 Writer *out = &writer; |
221 Writer *out = &writer; |
64 writer_init(out, net, buffer, MULTISTATUS_BUFFER_LENGTH); |
222 writer_init(out, net, buffer, MULTISTATUS_BUFFER_LENGTH); |
65 |
223 |
66 |
224 // send the xml root element with namespace defs |
|
225 if(send_xml_root(ms, out)) { |
|
226 return 1; |
|
227 } |
|
228 |
|
229 // send response tags |
|
230 MSResponse *response = ms->first; |
|
231 while(response) { |
|
232 if(send_response_tag(ms, response, out)) { |
|
233 return 1; |
|
234 } |
|
235 response = response->next; |
|
236 } |
67 |
237 |
68 return 0; |
238 return 0; |
69 } |
239 } |
70 |
240 |
71 WebdavResource * multistatus_addresource( |
241 WebdavResource * multistatus_addresource( |
178 if(ucx_map_sstr_put(response->properties, key, property)) { |
348 if(ucx_map_sstr_put(response->properties, key, property)) { |
179 return 1; // OOM |
349 return 1; // OOM |
180 } |
350 } |
181 a->free(a->pool, key.ptr); |
351 a->free(a->pool, key.ptr); |
182 |
352 |
|
353 // list of namespace definitions for this property |
|
354 WebdavNSList *nsdef_begin = NULL; |
|
355 WebdavNSList *nsdef_end = NULL; |
|
356 |
|
357 // add namespace of this property to the namespace map |
|
358 // the namespace map will be used for global namespace definitions |
|
359 if(property->namespace->prefix) { |
|
360 WSNamespace *ns = ucx_map_cstr_get( |
|
361 response->multistatus->namespaces, |
|
362 (const char*)property->namespace->prefix); |
|
363 if(!ns) { |
|
364 // prefix is not in use -> we can add the namespace to the ns map |
|
365 int err = ucx_map_cstr_put( |
|
366 response->multistatus->namespaces, |
|
367 (const char*)property->namespace->prefix, |
|
368 property->namespace); |
|
369 if(err) { |
|
370 return 1; // OOM |
|
371 } |
|
372 } else if( |
|
373 strcmp((const char*)property->namespace->href, |
|
374 (const char*)ns->href)) |
|
375 { |
|
376 // global namespace != local namespace |
|
377 // therefore we need a namespace definition in this element |
|
378 |
|
379 // ns-prefix != property-prefix -> add ns to nsdef |
|
380 if(webdav_nslist_add( |
|
381 sn->pool, |
|
382 &nsdef_begin, |
|
383 &nsdef_end, |
|
384 property->namespace)) |
|
385 { |
|
386 return 1; // OOM |
|
387 } |
|
388 } |
|
389 } |
|
390 |
183 // error properties will be added to a separate list |
391 // error properties will be added to a separate list |
184 if(status != 200) { |
392 if(status != 200) { |
185 return msresponse_addproperror(response, property, status); |
393 return msresponse_addproperror(response, property, status); |
186 } |
394 } |
187 |
395 |