54 return NULL; |
54 return NULL; |
55 } |
55 } |
56 return ms; |
56 return ms; |
57 } |
57 } |
58 |
58 |
59 static int send_xml_root(Multistatus *ms, Writer *out) { |
|
60 writer_puts(out, S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" |
|
61 "<D:multistatus")); |
|
62 |
|
63 // write the namespaces definitions |
|
64 // key is the namespace prefix |
|
65 // the map always contains the "DAV:" namespace with the prefix "D" |
|
66 UcxMapIterator i = ucx_map_iterator(ms->namespaces); |
|
67 char *href; |
|
68 UCX_MAP_FOREACH(key, href, i) { |
|
69 writer_puts(out, S(" xmlns:")); |
|
70 writer_put(out, key.data, key.len); |
|
71 writer_puts(out, S("=\"")); |
|
72 writer_puts(out, sstr(href)); |
|
73 writer_puts(out, S("\"")); |
|
74 } |
|
75 |
|
76 writer_puts(out, S(">\n")); |
|
77 |
|
78 return out->error; |
|
79 } |
|
80 |
|
81 static int send_prop_name( |
|
82 Multistatus *ms, |
|
83 WebdavProperty *p, |
|
84 Writer *out, |
|
85 char *prefixbuf, |
|
86 int *prefixbuflen) |
|
87 { |
|
88 int in_prefix_len = *prefixbuflen; |
|
89 *prefixbuflen = 0; |
|
90 |
|
91 writer_putc(out, '<'); |
|
92 |
|
93 const char *prefix = NULL; |
|
94 const char *href = NULL; |
|
95 |
|
96 if(p->namespace && p->namespace->href) { |
|
97 href = (const char*)p->namespace->href; |
|
98 |
|
99 if(p->namespace->prefix) { |
|
100 // check if there is a namespace with this prefix already defined |
|
101 // and has the same namespace uri |
|
102 prefix = (const char*)p->namespace->prefix; |
|
103 char *nshref = ucx_map_cstr_get( |
|
104 ms->namespaces, |
|
105 (const char*)p->namespace->prefix); |
|
106 if(!strcmp(nshref, href)) { |
|
107 href = NULL; // we don't need a new xmlns def |
|
108 } |
|
109 } else { |
|
110 // generate new prefix |
|
111 for(int i=0;i<1024;i++) { |
|
112 int len = snprintf(prefixbuf, in_prefix_len, "x%d\0", i); |
|
113 char *test = ucx_map_cstr_get(ms->namespaces, prefixbuf); |
|
114 if(!test) { |
|
115 prefix = prefixbuf; |
|
116 *prefixbuflen = len; |
|
117 break; // found an unused prefix |
|
118 } |
|
119 if(!prefix) { |
|
120 // What? Can't find a free prefix? |
|
121 return 1; |
|
122 } |
|
123 } |
|
124 } |
|
125 } |
|
126 |
|
127 if(prefix) { |
|
128 writer_put(out, prefix, strlen(prefix)); |
|
129 writer_put(out, ":", 1); |
|
130 } |
|
131 |
|
132 // write xml element name |
|
133 writer_put(out, (const char*)p->name, strlen((const char*)p->name)); |
|
134 |
|
135 if(href) { |
|
136 writer_puts(out, S(" xmlns:")); |
|
137 writer_put(out, prefix, strlen(prefix)); |
|
138 writer_puts(out, S("=\"")); |
|
139 writer_put(out, href, strlen(href)); |
|
140 writer_putc(out, '\"'); |
|
141 } |
|
142 |
|
143 if(p->lang) { |
|
144 writer_puts(out, S(" lang=\"")); |
|
145 writer_puts(out, sstr(p->lang)); |
|
146 writer_putc(out, '\"'); |
|
147 } |
|
148 |
|
149 writer_putc(out, '>'); |
|
150 |
|
151 return out->error; |
|
152 } |
|
153 |
|
154 |
|
155 |
|
156 #define MAX_XML_TREE_DEPTH 128 |
|
157 static int send_xml(Multistatus *ms, Writer *out, WSXmlNode *node, WSNamespace *rootns, int depth) { |
|
158 int ret = 0; |
|
159 const char *s; |
|
160 while(node) { |
|
161 switch(node->type) { |
|
162 case XML_ELEMENT_NODE: { |
|
163 writer_putc(out, '<'); |
|
164 if(node->ns && node->ns->prefix) { |
|
165 s = (const char*)node->ns->prefix; |
|
166 writer_put(out, s, strlen(s)); |
|
167 writer_putc(out, ':'); |
|
168 } |
|
169 s = (const char*)node->name; |
|
170 writer_put(out, s, strlen(s)); |
|
171 |
|
172 |
|
173 } |
|
174 |
|
175 } |
|
176 node = node->next; |
|
177 } |
|
178 |
|
179 return ret; |
|
180 } |
|
181 |
|
182 static int send_response_tag(Multistatus *ms, MSResponse *rp, Writer *out) { |
|
183 writer_puts(out, S(" <D:response>\n" |
|
184 " <D:href>")); |
|
185 writer_puts(out, sstr(rp->resource.href)); |
|
186 writer_puts(out, S("</href>\n")); |
|
187 |
|
188 if(rp->plist_begin) { |
|
189 writer_puts(out, S(" <D:propstat>" |
|
190 " <D:prop>\n")); |
|
191 WebdavPList *p = rp->plist_begin; |
|
192 char prefix[16]; |
|
193 while(p) { |
|
194 WebdavProperty *prop = p->property; |
|
195 int prefixlen = 16; |
|
196 if(send_prop_name(ms, prop, out, prefix, &prefixlen)) { |
|
197 return 1; |
|
198 } |
|
199 |
|
200 // send content |
|
201 |
|
202 |
|
203 // send end tag |
|
204 writer_put(out, "<", 1); |
|
205 if(prop->namespace && prop->namespace->href) { |
|
206 const char *pre = NULL; |
|
207 if(prop->namespace->prefix) { |
|
208 pre = (const char*)prop->namespace->prefix; |
|
209 } else if(prefixlen > 0) { |
|
210 pre = prefix; |
|
211 } |
|
212 |
|
213 if(pre) { |
|
214 writer_put(out, pre, strlen(pre)); |
|
215 writer_put(out, ":", 1); |
|
216 } |
|
217 } |
|
218 writer_put(out, prop->name, strlen(prop->name)); |
|
219 writer_put(out, ">", 1); |
|
220 |
|
221 if(out->error) { |
|
222 return 1; |
|
223 } |
|
224 |
|
225 p = p->next; |
|
226 } |
|
227 writer_puts(out, S(" </D:prop>\n" |
|
228 " <D:status>HTTP/1.1 200 OK</D:status>" |
|
229 " </D:propstat>\n")); |
|
230 } |
|
231 |
|
232 return out->error; |
|
233 } |
|
234 |
|
235 int multistatus_send(Multistatus *ms, SYS_NETFD net) { |
59 int multistatus_send(Multistatus *ms, SYS_NETFD net) { |
236 char buffer[MULTISTATUS_BUFFER_LENGTH]; |
60 char buffer[MULTISTATUS_BUFFER_LENGTH]; |
237 Writer writer; |
61 Writer writer; |
238 Writer *out = &writer; |
62 Writer *out = &writer; |
239 writer_init(out, net, buffer, MULTISTATUS_BUFFER_LENGTH); |
63 writer_init(out, net, buffer, MULTISTATUS_BUFFER_LENGTH); |
240 |
64 |
241 // send the xml root element with namespace defs |
65 |
242 if(send_xml_root(ms, out)) { |
66 } |
243 return 1; |
|
244 } |
|
245 |
|
246 // send response tags |
|
247 MSResponse *response = ms->first; |
|
248 while(response) { |
|
249 if(send_response_tag(ms, response, out)) { |
|
250 return 1; |
|
251 } |
|
252 response = response->next; |
|
253 } |
|
254 |
|
255 return 0; |
|
256 } |
|
257 |
|
258 |
67 |
259 WebdavResource * multistatus_addresource( |
68 WebdavResource * multistatus_addresource( |
260 WebdavResponse *response, |
69 WebdavResponse *response, |
261 const char *path) |
70 const char *path) |
262 { |
71 { |
300 "%s", |
115 "%s", |
301 "webdav: cannot add property to closed response tag"); |
116 "webdav: cannot add property to closed response tag"); |
302 return 0; |
117 return 0; |
303 } |
118 } |
304 |
119 |
|
120 // some WebdavProperty checks to make sure nothing explodes |
|
121 if(!property->namespace || !property->namespace->href) { |
|
122 // error: namespace is required |
|
123 log_ereport( |
|
124 LOG_FAILURE, |
|
125 "%s", |
|
126 "webdav: property '%s' has no namespace", |
|
127 property->name); |
|
128 return 1; |
|
129 } |
|
130 if(property->nsdef) { |
|
131 // error: nsdef MUST be NULL, only fill nsdef in this func |
|
132 log_ereport( |
|
133 LOG_FAILURE, |
|
134 "%s", |
|
135 "webdav: property '%s': nsdef must be null", |
|
136 property->name); |
|
137 return 1; |
|
138 } |
|
139 |
305 // add namespace of this property to the namespace map |
140 // add namespace of this property to the namespace map |
306 if(property->namespace && property->namespace->prefix) { |
141 // the namespace map will be used for global namespace definitions |
|
142 if(property->namespace->prefix) { |
307 char *ns = ucx_map_cstr_get( |
143 char *ns = ucx_map_cstr_get( |
308 response->multistatus->namespaces, |
144 response->multistatus->namespaces, |
309 (const char*)property->namespace->prefix); |
145 (const char*)property->namespace->prefix); |
310 if(!ns) { |
146 if(!ns) { |
|
147 // prefix is not in use -> we can add the namespace to the ns map |
311 int err = ucx_map_cstr_put( |
148 int err = ucx_map_cstr_put( |
312 response->multistatus->namespaces, |
149 response->multistatus->namespaces, |
313 (const char*)property->namespace->prefix, |
150 (const char*)property->namespace->prefix, |
314 property->namespace->href); |
151 property->namespace->href); |
315 if(err) { |
152 if(err) { |
316 return 1; |
153 return 1; // OOM |
317 } |
154 } |
318 } |
155 } else if(strcmp((char*)property->namespace->href, ns)) { |
319 } |
156 // global namespace != local namespace |
320 |
157 // therefore we need a namespace definition in this element |
321 if(status != 200) { |
158 |
|
159 if(webdav_property_add_nsdef( |
|
160 property, |
|
161 response->multistatus->sn->pool, |
|
162 (const char*)property->namespace->prefix, |
|
163 (const char*)property->namespace->href)) |
|
164 { |
|
165 return 1; // OOM |
|
166 } |
|
167 } |
|
168 } |
|
169 |
|
170 // error properties will be added to a separate list |
|
171 if(status != 200) { |
322 return msresponse_addproperror(response, property, status); |
172 return msresponse_addproperror(response, property, status); |
323 } |
173 } |
|
174 |
|
175 // add all namespaces used by this property to the nsdef list |
|
176 if(property->vtype == WS_VALUE_XML_NODE) { |
|
177 // iterate over xml tree and collect all namespaces |
|
178 |
|
179 // TODO: implement |
|
180 } else if(property->vtype == WS_VALUE_XML_DATA) { |
|
181 // xml data contains a list of all used namespaces |
|
182 WebdavNSList *nslist = property->value.data->namespaces; |
|
183 while(nslist) { |
|
184 // only add the namespace to the definitions list, if it isn't |
|
185 // property namespace, because the prop ns is already added |
|
186 // to the element's def list or global definitions list |
|
187 if(strcmp( |
|
188 (const char*)nslist->namespace->prefix, |
|
189 (const char*)property->namespace->prefix)) |
|
190 { |
|
191 // ns-prefix != property-prefix -> add ns to nsdef |
|
192 if(webdav_property_add_nsdef( |
|
193 property, |
|
194 response->multistatus->sn->pool, |
|
195 (const char*)nslist->namespace->prefix, |
|
196 (const char*)nslist->namespace->href)) |
|
197 { |
|
198 return 1; // OOM |
|
199 } |
|
200 } |
|
201 nslist = nslist->next; |
|
202 } |
|
203 } // other value types don't contain xml namespaces |
324 |
204 |
325 // add property to the list |
205 // add property to the list |
326 WebdavPList *listelm = pool_malloc( |
206 WebdavPList *listelm = pool_malloc( |
327 response->multistatus->sn->pool, |
207 response->multistatus->sn->pool, |
328 sizeof(WebdavPList)); |
208 sizeof(WebdavPList)); |