src/server/webdav/multistatus.c

branch
webdav
changeset 222
5f05e56cb8e2
parent 217
8ed14d76db42
child 223
bbaec8415c10
equal deleted inserted replaced
221:ff5826fc6a6c 222:5f05e56cb8e2
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 {
265 if(!res) { 74 if(!res) {
266 return NULL; 75 return NULL;
267 } 76 }
268 ZERO(res, sizeof(MSResponse)); 77 ZERO(res, sizeof(MSResponse));
269 78
79 // set href
80 res->resource.href = pool_strdup(response->op->sn->pool, path);
81
82 // add resource funcs
270 res->resource.addproperty = msresponse_addproperty; 83 res->resource.addproperty = msresponse_addproperty;
271 res->resource.close = msresponse_close; 84 res->resource.close = msresponse_close;
272 85
273 res->multistatus = ms; 86 res->multistatus = ms;
274 res->errors = NULL; 87 res->errors = NULL;
275 res->resource.isclosed = 0; 88 res->resource.isclosed = 0;
276 res->closing = 0; 89 res->closing = 0;
277 90
91 // add new resource to the resource list
278 if(ms->current) { 92 if(ms->current) {
93 // before adding a new resource, the current resource must be closed
279 if(!ms->current->resource.isclosed) { 94 if(!ms->current->resource.isclosed) {
280 msresponse_close((WebdavResource*)ms->current); 95 msresponse_close((WebdavResource*)ms->current);
281 } 96 }
282 ms->current->next = res; 97 ms->current->next = res;
283 } else { 98 } else {
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));

mercurial