src/server/webdav.c

changeset 14
b8bf95b39952
parent 13
1fdbf4170ef4
child 15
cff9c4101dd7
equal deleted inserted replaced
13:1fdbf4170ef4 14:b8bf95b39952
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2011 Olaf Wintermann. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "webdav.h"
34 #include "sstring.h"
35 #include "pool.h"
36 #include "pblock.h"
37
38 #include "davparser.h"
39
40 int webdav_service(pblock *pb, Session *sn, Request *rq) {
41 /* TODO:
42 * Dies ist die Implementierung für PROPFIND. Es sollte für jede webdav-
43 * Methode eine eigene Service-Funktion geben. Solange die anderen
44 * Methoden nicht implementiert werden, behandelt webdav_service nur
45 * PROPFIND.
46 */
47
48 /* TODO: clean up if errors occurs */
49
50 /* Get request body which contains the webdav XML request */
51 char *xml_body;
52 size_t xml_len = 0;
53
54 char *ctlen = pblock_findkeyval(pb_key_content_length, rq->headers);
55 if(ctlen) {
56 xml_len = atoi(ctlen);
57 } else {
58 /* invalid request */
59 return REQ_ABORTED;
60 }
61
62 xml_body = pool_malloc(sn->pool, xml_len + 1);
63 xml_body[xml_len] = 0;
64 if(!xml_body) {
65 /* server error */
66 return REQ_ABORTED;
67 }
68
69 /* TODO: bug with multi reads */
70 int r = 0;
71 char *xb = xml_body;
72 size_t xl = xml_len;
73 while((r = netbuf_getbytes(sn->inbuf, xb, xl)) != NETBUF_EOF) {
74 xb += r;
75 xl -= xml_len;
76 }
77
78 PropfindRequest *davrq = dav_parse_propfind(sn, rq, xml_body, xml_len);
79 davrq->sn = sn;
80 davrq->rq = rq;
81 davrq->propertyBackend = create_property_backend();
82 davrq->notFoundProps = NULL;
83 davrq->forbiddenProps = NULL;
84 davrq->out = sbuf_new(512);
85
86 /* write header */
87 sbuf_puts(davrq->out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
88 sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n");
89
90 /* get stat of file */
91 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
92 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
93
94 struct stat st;
95 if(stat(ppath, &st) != 0) {
96 perror("webdav_service: stat");
97 return REQ_ABORTED;
98 }
99 /* TODO: check for more modes */
100 if(S_ISDIR(st.st_mode)) {
101 DIR *dir = opendir(ppath);
102 if(dir == NULL) {
103 protocol_status(sn, rq, 500, NULL);
104 printf("webdav_service: DIR is null\n");
105 return REQ_ABORTED;
106 }
107
108 struct dirent *f;
109 while((f = readdir(dir)) != NULL) {
110 if(strcmp(f->d_name, ".") == 0 || strcmp(f->d_name, "..") == 0) {
111 continue;
112 }
113
114 sstr_t filename = sstr(f->d_name);
115 sstr_t _path = sstr(ppath);
116 sstr_t _uri = sstr(uri);
117
118 sstr_t newuri;
119 newuri.length = filename.length + _uri.length;
120 newuri.ptr = alloca(newuri.length + 1);
121 newuri = sstrncat(2, newuri, _uri, filename);
122
123 sstr_t newpath;
124 newpath.length = _path.length + filename.length;
125 newpath.ptr = alloca(newpath.length + 1);
126 newpath = sstrncat(2, newpath, _path, filename);
127
128 davrq->path = newpath.ptr;
129 davrq->uri = newuri.ptr;
130 dav_create_response(davrq);
131 }
132 }
133 davrq->path = ppath;
134 davrq->uri = uri;
135 dav_create_response(davrq);
136
137 sbuf_puts(davrq->out, "</D:multistatus>\n");
138
139 /* send buffer to client */
140 pblock_removekey(pb_key_content_type, rq->srvhdrs);
141 pblock_nvinsert("content-type", "text/xml", rq->srvhdrs);
142 pblock_nninsert("content-length", davrq->out->length, rq->srvhdrs);
143
144 protocol_status(sn, rq, 207, NULL);
145 http_start_response(sn, rq);
146
147 net_write(sn->csd, davrq->out->ptr, davrq->out->length);
148
149 return REQ_PROCEED;
150 }
151
152 int dav_foreach_reqprop(UcxDlist *list, PropfindRequest *davrq) {
153 DavProperty *prop = list->data;
154 int error = 0;
155
156 char *str = davrq->propertyBackend->get_property(
157 davrq->propertyBackend,
158 davrq,
159 davrq->path,
160 prop->xmlns,
161 prop->name,
162 &error);
163 if(str == NULL) {
164 UcxDlist **dl = NULL;
165 if(error == 404) {
166 dl = &davrq->notFoundProps;
167 } else {
168 dl = &davrq->forbiddenProps;
169 }
170 *dl = ucx_dlist_append(*dl, prop);
171 } else {
172 //printf("dav property: {%s|%s::%s\n", prop->xmlns, prop->name, str);
173 sbuf_puts(davrq->out, "<D:");
174 sbuf_puts(davrq->out, prop->name);
175 sbuf_puts(davrq->out, ">");
176 sbuf_puts(davrq->out, str);
177 sbuf_puts(davrq->out, "</D:");
178 sbuf_puts(davrq->out, prop->name);
179 sbuf_puts(davrq->out, ">\n");
180 }
181 return 0;
182 }
183
184 void dav_create_response(PropfindRequest *davrq) {
185 sbuf_puts(davrq->out, "<D:response>\n");
186
187 sbuf_puts(davrq->out, "<D:href>");
188 sbuf_puts(davrq->out, davrq->uri);
189 sbuf_puts(davrq->out, "</D:href>\n");
190
191 sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
192
193 ucx_dlist_foreach(
194 davrq->properties,
195 (ucx_callback)dav_foreach_reqprop,
196 davrq);
197
198 sbuf_puts(davrq->out, "</D:prop>\n<D:status>HTTP/1.1 200 OK</D:status>\n");
199 sbuf_puts(davrq->out, "</D:propstat>\n");
200
201 /* 404 props */
202 sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
203 UcxDlist *dl = davrq->notFoundProps;
204 while(dl != NULL) {
205 DavProperty *nfp = dl->data;
206 sbuf_puts(davrq->out, "<D:");
207 sbuf_puts(davrq->out, nfp->name);
208 sbuf_puts(davrq->out, " />\n");
209 dl = dl->next;
210 }
211 sbuf_puts(davrq->out, "</D:prop>\n");
212 sbuf_puts(davrq->out, "<D:status>HTTP/1.1 404 Not Found</D:status>\n");
213 sbuf_puts(davrq->out, "</D:propstat>\n");
214
215 /* end */
216 sbuf_puts(davrq->out, "</D:response>\n");
217
218 }
219
220 char* dav_get_property(
221 DAVPropertyBackend *b,
222 PropfindRequest *davrq,
223 char *path,
224 char *xmlns,
225 char *name,
226 int *error)
227 {
228 DAVDefaultBackend *be = (DAVDefaultBackend*)b;
229 *error = 200;
230
231 if(strcmp(name, "getcontentlength") == 0) {
232 struct stat s;
233 if(stat(davrq->path, &s) != 0) {
234 *error = 403; /* really? */
235 return NULL;
236 }
237 if(S_ISDIR(s.st_mode)) {
238 *error = 404;
239 return NULL;
240 }
241 char *buf = pool_malloc(davrq->sn->pool, 24);
242 sprintf(buf, "%d", s.st_size);
243 return buf;
244 }
245
246 *error = 404;
247 return NULL;
248 }
249
250 DAVPropertyBackend* create_property_backend() {
251 DAVDefaultBackend *backend = malloc(sizeof(DAVDefaultBackend));
252 backend->backend.get_property = dav_get_property;
253 backend->path = NULL;
254 backend->s = 0;
255 return (DAVPropertyBackend*)backend;
256 }

mercurial