src/server/webdav/webdav.c

changeset 26
37ff8bf54b89
parent 24
1a7853a4257e
child 27
05b7576dca2b
equal deleted inserted replaced
25:5dee29c7c530 26:37ff8bf54b89
36 #include "../util/pblock.h" 36 #include "../util/pblock.h"
37 37
38 #include "davparser.h" 38 #include "davparser.h"
39 39
40 int webdav_service(pblock *pb, Session *sn, Request *rq) { 40 int webdav_service(pblock *pb, Session *sn, Request *rq) {
41 /* TODO: 41 return webdav_propfind(pb, sn, rq);
42 * Dies ist die Implementierung für PROPFIND. Es sollte für jede webdav- 42 }
43 * Methode eine eigene Service-Funktion geben. Solange die anderen 43
44 * Methoden nicht implementiert werden, behandelt webdav_service nur 44 int webdav_propfind(pblock *pb, Session *sn, Request *rq) {
45 * PROPFIND.
46 */
47
48 /* TODO: clean up if errors occurs */ 45 /* TODO: clean up if errors occurs */
49 46
50 /* Get request body which contains the webdav XML request */ 47 /* Get request body which contains the webdav XML request */
51 char *xml_body; 48 char *xml_body;
52 size_t xml_len = 0; 49 size_t xml_len = 0;
59 printf("invalid request\n"); 56 printf("invalid request\n");
60 return REQ_ABORTED; 57 return REQ_ABORTED;
61 } 58 }
62 59
63 xml_body = pool_malloc(sn->pool, xml_len + 1); 60 xml_body = pool_malloc(sn->pool, xml_len + 1);
61 if(xml_body == NULL) {
62 return REQ_ABORTED;
63 }
64 xml_body[xml_len] = 0; 64 xml_body[xml_len] = 0;
65 if(!xml_body) { 65 if(!xml_body) {
66 /* server error */ 66 /* server error */
67 printf("server error\n"); 67 printf("server error\n");
68 return REQ_ABORTED; 68 return REQ_ABORTED;
75 while((r = netbuf_getbytes(sn->inbuf, xb, xl)) != NETBUF_EOF) { 75 while((r = netbuf_getbytes(sn->inbuf, xb, xl)) != NETBUF_EOF) {
76 xb += r; 76 xb += r;
77 xl -= xml_len; 77 xl -= xml_len;
78 } 78 }
79 79
80 /*
81 * get requested properties and initialize some stuff
82 */
80 PropfindRequest *davrq = dav_parse_propfind(sn, rq, xml_body, xml_len); 83 PropfindRequest *davrq = dav_parse_propfind(sn, rq, xml_body, xml_len);
81 davrq->sn = sn; 84 davrq->sn = sn;
82 davrq->rq = rq; 85 davrq->rq = rq;
86 davrq->out = sbuf_new(512);
83 davrq->propertyBackend = create_property_backend(); 87 davrq->propertyBackend = create_property_backend();
84 davrq->notFoundProps = NULL; 88
85 davrq->forbiddenProps = NULL; 89 /* write xml response header */
86 davrq->out = sbuf_new(512);
87
88 /* write header */
89 sbuf_puts(davrq->out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); 90 sbuf_puts(davrq->out, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
90 sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n"); 91 sbuf_puts(davrq->out, "<D:multistatus xmlns:D=\"DAV:\">\n");
91 92
92 /* get stat of file */ 93 /* begin multistatus response */
94 int is_dir = 0;
95 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
93 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars); 96 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars);
94 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); 97
95
96 struct stat st; 98 struct stat st;
97 if(stat(ppath, &st) != 0) { 99 if(stat(ppath, &st) != 0) {
98 perror("webdav_service: stat"); 100 perror("webdav_propfind: stat");
99 return REQ_ABORTED; 101 return REQ_ABORTED;
100 } 102 }
101 /* TODO: check for more modes */ 103
104 /*
105 * if the requested webdav resource(file) is a directory, we create
106 * a response for every child
107 */
102 if(S_ISDIR(st.st_mode)) { 108 if(S_ISDIR(st.st_mode)) {
103 DIR *dir = opendir(ppath); 109 DIR *dir = opendir(ppath);
104 if(dir == NULL) { 110 if(dir == NULL) {
105 protocol_status(sn, rq, 500, NULL); 111 protocol_status(sn, rq, 500, NULL);
106 printf("webdav_service: DIR is null\n"); 112 printf("webdav_propfind: DIR is null\n");
107 return REQ_ABORTED; 113 return REQ_ABORTED;
108 } 114 }
109 115
110 struct dirent *f; 116 struct dirent *f;
111 while((f = readdir(dir)) != NULL) { 117 while((f = readdir(dir)) != NULL) {
112 if(strcmp(f->d_name, ".") == 0 || strcmp(f->d_name, "..") == 0) { 118 if(strcmp(f->d_name, ".") == 0 || strcmp(f->d_name, "..") == 0) {
113 continue; 119 continue;
114 } 120 }
115 121
116 sstr_t filename = sstr(f->d_name); 122 sstr_t filename = sstr(f->d_name);
117 sstr_t _path = sstr(ppath); 123 sstr_t _path = sstr(ppath);
118 sstr_t _uri = sstr(uri); 124 sstr_t _uri = sstr(uri);
119 125
120 sstr_t newuri; 126 sstr_t newuri;
121 newuri.length = filename.length + _uri.length; 127 newuri.length = filename.length + _uri.length;
122 newuri.ptr = alloca(newuri.length + 1); 128 newuri.ptr = alloca(newuri.length + 1);
123 newuri = sstrncat(2, newuri, _uri, filename); 129 newuri = sstrncat(2, newuri, _uri, filename);
124 130
125 sstr_t newpath; 131 sstr_t newpath;
126 newpath.length = _path.length + filename.length; 132 newpath.length = _path.length + filename.length;
127 newpath.ptr = alloca(newpath.length + 1); 133 newpath.ptr = alloca(newpath.length + 1);
128 newpath = sstrncat(2, newpath, _path, filename); 134 newpath = sstrncat(2, newpath, _path, filename);
129 135
130 davrq->path = newpath.ptr; 136 /* child response */
131 davrq->uri = newuri.ptr; 137 dav_resource_response(davrq, newpath, newuri);
132 dav_create_response(davrq); 138 }
133 } 139 }
134 } 140
135 davrq->path = ppath; 141 /* create the response for the requested resource */
136 davrq->uri = uri; 142 dav_resource_response(davrq, sstr(ppath), sstr(uri));
137 dav_create_response(davrq); 143
138 144 /* end xml */
139 sbuf_puts(davrq->out, "</D:multistatus>\n"); 145 sbuf_puts(davrq->out, "</D:multistatus>\n");
140 146
141 /* send buffer to client */ 147 /* send the xml response to the client */
148 protocol_status(sn, rq, 207, "Multi Status");
142 pblock_removekey(pb_key_content_type, rq->srvhdrs); 149 pblock_removekey(pb_key_content_type, rq->srvhdrs);
143 pblock_nvinsert("content-type", "text/xml", rq->srvhdrs); 150 pblock_nvinsert("content-type", "text/xml", rq->srvhdrs);
144 pblock_nninsert("content-length", davrq->out->length, rq->srvhdrs); 151 pblock_nninsert("content-length", davrq->out->length, rq->srvhdrs);
145 152
146 protocol_status(sn, rq, 207, NULL); 153 pblock_nvinsert("connection", "close", rq->srvhdrs);
147 http_start_response(sn, rq); 154 http_start_response(sn, rq);
148 155
149 net_write(sn->csd, davrq->out->ptr, davrq->out->length); 156 net_write(sn->csd, davrq->out->ptr, davrq->out->length);
150 157
158
159
160
151 return REQ_PROCEED; 161 return REQ_PROCEED;
152 } 162 }
153 163
154 int dav_foreach_reqprop(UcxDlist *list, PropfindRequest *davrq) { 164 void dav_resource_response(PropfindRequest *davrq, sstr_t path, sstr_t uri) {
155 DavProperty *prop = list->data; 165 printf("dav_resource_response %s %s\n", sstrdub(path).ptr, sstrdub(uri).ptr);
156 int error = 0; 166
157 167 sbuf_puts(davrq->out, "<D:response>\n");
158 char *str = davrq->propertyBackend->get_property( 168 sbuf_puts(davrq->out, "<D:href>");
159 davrq->propertyBackend, 169 sbuf_append(davrq->out, uri);
160 davrq, 170 sbuf_puts(davrq->out, "</D:href>\n");
161 davrq->path, 171
162 prop->xmlns, 172 davrq->propertyBackend->propfind(davrq->propertyBackend, davrq, path.ptr);
163 prop->name, 173
164 &error); 174 if(davrq->prop) {
165 if(str == NULL) { 175 /*
166 UcxDlist **dl = NULL; 176 * there are some properties written, so we close the
167 if(error == 404) { 177 * prop and propstat tag
168 dl = &davrq->notFoundProps; 178 */
179 sbuf_puts(davrq->out, "</D:prop>\n");
180 sbuf_puts(davrq->out, "<D:status>HTTP/1.1 200 OK</D:status>\n");
181 sbuf_puts(davrq->out, "</D:propstat>\n");
182 }
183
184 if(davrq->notFoundProps != NULL) {
185 sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
186 DAV_FOREACH(elm, davrq->notFoundProps) {
187 DavProperty *prop = (DavProperty*)elm->data;
188 sbuf_puts(davrq->out, "<D:");
189 sbuf_puts(davrq->out, prop->name);
190 sbuf_puts(davrq->out, " />\n");
191 }
192 sbuf_puts(davrq->out, "</D:prop>\n");
193 sbuf_puts(davrq->out, "<D:status>HTTP/1.1 404 Not Found</D:status>\n");
194 sbuf_puts(davrq->out, "</D:propstat>\n");
195 }
196
197 sbuf_puts(davrq->out, "</D:response>\n");
198
199 /* reset */
200 davrq->prop = 0;
201 davrq->notFoundProps = NULL;
202 davrq->forbiddenProps = NULL;
203
204 }
205
206 void dav_propfind_add_str_prop(
207 PropfindRequest *davrq,
208 DavProperty* prop,
209 char *str,
210 size_t len)
211 {
212 if(!davrq->prop) {
213 sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
214 davrq->prop = 1;
215 }
216
217 sbuf_puts(davrq->out, "<D:");
218 sbuf_puts(davrq->out, prop->name);
219 sbuf_puts(davrq->out, ">");
220
221 sbuf_append(davrq->out, sstrn(str, len));
222
223 sbuf_puts(davrq->out, "</D:");
224 sbuf_puts(davrq->out, prop->name);
225 sbuf_puts(davrq->out, ">\n");
226 }
227
228 void dav_propfind_add_prop_error(
229 PropfindRequest *davrq,
230 DavProperty *prop,
231 int error)
232 {
233 davrq->notFoundProps = ucx_dlist_append(davrq->notFoundProps, prop);
234 }
235
236
237
238
239 /* WebDAV Default Backend */
240 DAVPropertyBackend* create_property_backend() {
241 DAVPropertyBackend *pb = malloc(sizeof(DAVPropertyBackend));
242 if(pb == NULL) {
243 //
244 }
245 pb->propfind = dav_rq_propfind;
246 return pb;
247 }
248
249 void dav_rq_propfind(DAVPropertyBackend *b, PropfindRequest *rq ,char *path) {
250 struct stat st;
251 if(stat(path, &st) != 0) {
252 perror("dav_be_propfind");
253 fprintf(stderr, "Cannot get stat of file: %s\n", path);
254 }
255
256 DAV_FOREACH(elm, rq->properties) {
257 DavProperty *prop = (DavProperty*)elm->data;
258
259 char *s = prop->name;
260 if(!strcmp(s, "resourcetype")) {
261 if(S_ISDIR(st.st_mode)) {
262 dav_propfind_add_str_prop(rq, prop, "<D:collection/>", 15);
263 } else {
264 dav_propfind_add_str_prop(rq, prop, NULL, 0);
265 }
266 } else if(!strcmp(s, "getcontentlength") && !S_ISDIR(st.st_mode)) {
267 char buf[32];
268 size_t n = snprintf(buf, 32, "%d", st.st_size);
269 dav_propfind_add_str_prop(rq, prop, buf, n);
169 } else { 270 } else {
170 dl = &davrq->forbiddenProps; 271 dav_propfind_add_prop_error(rq, prop, 404);
171 } 272 }
172 *dl = ucx_dlist_append(*dl, prop); 273 }
173 } else { 274 }
174 //printf("dav property: {%s|%s::%s\n", prop->xmlns, prop->name, str);
175 sbuf_puts(davrq->out, "<D:");
176 sbuf_puts(davrq->out, prop->name);
177 sbuf_puts(davrq->out, ">");
178 sbuf_puts(davrq->out, str);
179 sbuf_puts(davrq->out, "</D:");
180 sbuf_puts(davrq->out, prop->name);
181 sbuf_puts(davrq->out, ">\n");
182 }
183 return 0;
184 }
185
186 void dav_create_response(PropfindRequest *davrq) {
187 sbuf_puts(davrq->out, "<D:response>\n");
188
189 sbuf_puts(davrq->out, "<D:href>");
190 sbuf_puts(davrq->out, davrq->uri);
191 sbuf_puts(davrq->out, "</D:href>\n");
192
193 sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
194
195 ucx_dlist_foreach(
196 davrq->properties,
197 (ucx_callback)dav_foreach_reqprop,
198 davrq);
199
200 sbuf_puts(davrq->out, "</D:prop>\n<D:status>HTTP/1.1 200 OK</D:status>\n");
201 sbuf_puts(davrq->out, "</D:propstat>\n");
202
203 /* 404 props */
204 sbuf_puts(davrq->out, "<D:propstat>\n<D:prop>\n");
205 UcxDlist *dl = davrq->notFoundProps;
206 while(dl != NULL) {
207 DavProperty *nfp = dl->data;
208 sbuf_puts(davrq->out, "<D:");
209 sbuf_puts(davrq->out, nfp->name);
210 sbuf_puts(davrq->out, " />\n");
211 dl = dl->next;
212 }
213 sbuf_puts(davrq->out, "</D:prop>\n");
214 sbuf_puts(davrq->out, "<D:status>HTTP/1.1 404 Not Found</D:status>\n");
215 sbuf_puts(davrq->out, "</D:propstat>\n");
216
217 /* end */
218 sbuf_puts(davrq->out, "</D:response>\n");
219
220 }
221
222 char* dav_get_property(
223 DAVPropertyBackend *b,
224 PropfindRequest *davrq,
225 char *path,
226 char *xmlns,
227 char *name,
228 int *error)
229 {
230 DAVDefaultBackend *be = (DAVDefaultBackend*)b;
231 *error = 200;
232
233 if(strcmp(name, "getcontentlength") == 0) {
234 struct stat s;
235 if(stat(davrq->path, &s) != 0) {
236 *error = 403; /* really? */
237 return NULL;
238 }
239 if(S_ISDIR(s.st_mode)) {
240 *error = 404;
241 return NULL;
242 }
243 char *buf = pool_malloc(davrq->sn->pool, 24);
244 sprintf(buf, "%d", s.st_size);
245 return buf;
246 }
247
248 *error = 404;
249 return NULL;
250 }
251
252 DAVPropertyBackend* create_property_backend() {
253 DAVDefaultBackend *backend = malloc(sizeof(DAVDefaultBackend));
254 backend->backend.get_property = dav_get_property;
255 backend->path = NULL;
256 backend->s = 0;
257 return (DAVPropertyBackend*)backend;
258 }

mercurial