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 } |
|