diff -r 5dee29c7c530 -r 37ff8bf54b89 src/server/webdav/webdav.c --- a/src/server/webdav/webdav.c Sat Feb 25 12:43:26 2012 +0100 +++ b/src/server/webdav/webdav.c Sun Feb 26 19:51:14 2012 +0100 @@ -38,13 +38,10 @@ #include "davparser.h" int webdav_service(pblock *pb, Session *sn, Request *rq) { - /* TODO: - * Dies ist die Implementierung für PROPFIND. Es sollte für jede webdav- - * Methode eine eigene Service-Funktion geben. Solange die anderen - * Methoden nicht implementiert werden, behandelt webdav_service nur - * PROPFIND. - */ + return webdav_propfind(pb, sn, rq); +} +int webdav_propfind(pblock *pb, Session *sn, Request *rq) { /* TODO: clean up if errors occurs */ /* Get request body which contains the webdav XML request */ @@ -61,6 +58,9 @@ } xml_body = pool_malloc(sn->pool, xml_len + 1); + if(xml_body == NULL) { + return REQ_ABORTED; + } xml_body[xml_len] = 0; if(!xml_body) { /* server error */ @@ -77,182 +77,198 @@ xl -= xml_len; } + /* + * get requested properties and initialize some stuff + */ PropfindRequest *davrq = dav_parse_propfind(sn, rq, xml_body, xml_len); davrq->sn = sn; davrq->rq = rq; + davrq->out = sbuf_new(512); davrq->propertyBackend = create_property_backend(); - davrq->notFoundProps = NULL; - davrq->forbiddenProps = NULL; - davrq->out = sbuf_new(512); - - /* write header */ + + /* write xml response header */ sbuf_puts(davrq->out, "\n"); sbuf_puts(davrq->out, "\n"); - - /* get stat of file */ + + /* begin multistatus response */ + int is_dir = 0; + char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars); - char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); - + struct stat st; if(stat(ppath, &st) != 0) { - perror("webdav_service: stat"); + perror("webdav_propfind: stat"); return REQ_ABORTED; - } - /* TODO: check for more modes */ + } + + /* + * if the requested webdav resource(file) is a directory, we create + * a response for every child + */ if(S_ISDIR(st.st_mode)) { DIR *dir = opendir(ppath); if(dir == NULL) { protocol_status(sn, rq, 500, NULL); - printf("webdav_service: DIR is null\n"); + printf("webdav_propfind: DIR is null\n"); return REQ_ABORTED; } - + struct dirent *f; while((f = readdir(dir)) != NULL) { if(strcmp(f->d_name, ".") == 0 || strcmp(f->d_name, "..") == 0) { continue; } - + sstr_t filename = sstr(f->d_name); - sstr_t _path = sstr(ppath); + sstr_t _path = sstr(ppath); sstr_t _uri = sstr(uri); - + sstr_t newuri; newuri.length = filename.length + _uri.length; newuri.ptr = alloca(newuri.length + 1); newuri = sstrncat(2, newuri, _uri, filename); - + sstr_t newpath; newpath.length = _path.length + filename.length; newpath.ptr = alloca(newpath.length + 1); newpath = sstrncat(2, newpath, _path, filename); - - davrq->path = newpath.ptr; - davrq->uri = newuri.ptr; - dav_create_response(davrq); + + /* child response */ + dav_resource_response(davrq, newpath, newuri); } } - davrq->path = ppath; - davrq->uri = uri; - dav_create_response(davrq); - + + /* create the response for the requested resource */ + dav_resource_response(davrq, sstr(ppath), sstr(uri)); + + /* end xml */ sbuf_puts(davrq->out, "\n"); - - /* send buffer to client */ + + /* send the xml response to the client */ + protocol_status(sn, rq, 207, "Multi Status"); pblock_removekey(pb_key_content_type, rq->srvhdrs); pblock_nvinsert("content-type", "text/xml", rq->srvhdrs); pblock_nninsert("content-length", davrq->out->length, rq->srvhdrs); - - protocol_status(sn, rq, 207, NULL); + + pblock_nvinsert("connection", "close", rq->srvhdrs); http_start_response(sn, rq); - + net_write(sn->csd, davrq->out->ptr, davrq->out->length); + + + return REQ_PROCEED; } -int dav_foreach_reqprop(UcxDlist *list, PropfindRequest *davrq) { - DavProperty *prop = list->data; - int error = 0; +void dav_resource_response(PropfindRequest *davrq, sstr_t path, sstr_t uri) { + printf("dav_resource_response %s %s\n", sstrdub(path).ptr, sstrdub(uri).ptr); + + sbuf_puts(davrq->out, "\n"); + sbuf_puts(davrq->out, ""); + sbuf_append(davrq->out, uri); + sbuf_puts(davrq->out, "\n"); - char *str = davrq->propertyBackend->get_property( - davrq->propertyBackend, - davrq, - davrq->path, - prop->xmlns, - prop->name, - &error); - if(str == NULL) { - UcxDlist **dl = NULL; - if(error == 404) { - dl = &davrq->notFoundProps; - } else { - dl = &davrq->forbiddenProps; - } - *dl = ucx_dlist_append(*dl, prop); - } else { - //printf("dav property: {%s|%s::%s\n", prop->xmlns, prop->name, str); - sbuf_puts(davrq->out, "out, prop->name); - sbuf_puts(davrq->out, ">"); - sbuf_puts(davrq->out, str); - sbuf_puts(davrq->out, "out, prop->name); - sbuf_puts(davrq->out, ">\n"); + davrq->propertyBackend->propfind(davrq->propertyBackend, davrq, path.ptr); + + if(davrq->prop) { + /* + * there are some properties written, so we close the + * prop and propstat tag + */ + sbuf_puts(davrq->out, "\n"); + sbuf_puts(davrq->out, "HTTP/1.1 200 OK\n"); + sbuf_puts(davrq->out, "\n"); } - return 0; -} - -void dav_create_response(PropfindRequest *davrq) { - sbuf_puts(davrq->out, "\n"); - - sbuf_puts(davrq->out, ""); - sbuf_puts(davrq->out, davrq->uri); - sbuf_puts(davrq->out, "\n"); - - sbuf_puts(davrq->out, "\n\n"); - ucx_dlist_foreach( - davrq->properties, - (ucx_callback)dav_foreach_reqprop, - davrq); - - sbuf_puts(davrq->out, "\nHTTP/1.1 200 OK\n"); - sbuf_puts(davrq->out, "\n"); - - /* 404 props */ - sbuf_puts(davrq->out, "\n\n"); - UcxDlist *dl = davrq->notFoundProps; - while(dl != NULL) { - DavProperty *nfp = dl->data; - sbuf_puts(davrq->out, "out, nfp->name); - sbuf_puts(davrq->out, " />\n"); - dl = dl->next; + if(davrq->notFoundProps != NULL) { + sbuf_puts(davrq->out, "\n\n"); + DAV_FOREACH(elm, davrq->notFoundProps) { + DavProperty *prop = (DavProperty*)elm->data; + sbuf_puts(davrq->out, "out, prop->name); + sbuf_puts(davrq->out, " />\n"); + } + sbuf_puts(davrq->out, "\n"); + sbuf_puts(davrq->out, "HTTP/1.1 404 Not Found\n"); + sbuf_puts(davrq->out, "\n"); } - sbuf_puts(davrq->out, "\n"); - sbuf_puts(davrq->out, "HTTP/1.1 404 Not Found\n"); - sbuf_puts(davrq->out, "\n"); - - /* end */ + sbuf_puts(davrq->out, "\n"); + /* reset */ + davrq->prop = 0; + davrq->notFoundProps = NULL; + davrq->forbiddenProps = NULL; + } -char* dav_get_property( - DAVPropertyBackend *b, +void dav_propfind_add_str_prop( PropfindRequest *davrq, - char *path, - char *xmlns, - char *name, - int *error) + DavProperty* prop, + char *str, + size_t len) { - DAVDefaultBackend *be = (DAVDefaultBackend*)b; - *error = 200; + if(!davrq->prop) { + sbuf_puts(davrq->out, "\n\n"); + davrq->prop = 1; + } + + sbuf_puts(davrq->out, "out, prop->name); + sbuf_puts(davrq->out, ">"); + + sbuf_append(davrq->out, sstrn(str, len)); + + sbuf_puts(davrq->out, "out, prop->name); + sbuf_puts(davrq->out, ">\n"); +} - if(strcmp(name, "getcontentlength") == 0) { - struct stat s; - if(stat(davrq->path, &s) != 0) { - *error = 403; /* really? */ - return NULL; - } - if(S_ISDIR(s.st_mode)) { - *error = 404; - return NULL; - } - char *buf = pool_malloc(davrq->sn->pool, 24); - sprintf(buf, "%d", s.st_size); - return buf; - } - - *error = 404; - return NULL; +void dav_propfind_add_prop_error( + PropfindRequest *davrq, + DavProperty *prop, + int error) +{ + davrq->notFoundProps = ucx_dlist_append(davrq->notFoundProps, prop); } + + + +/* WebDAV Default Backend */ DAVPropertyBackend* create_property_backend() { - DAVDefaultBackend *backend = malloc(sizeof(DAVDefaultBackend)); - backend->backend.get_property = dav_get_property; - backend->path = NULL; - backend->s = 0; - return (DAVPropertyBackend*)backend; + DAVPropertyBackend *pb = malloc(sizeof(DAVPropertyBackend)); + if(pb == NULL) { + // + } + pb->propfind = dav_rq_propfind; + return pb; } + +void dav_rq_propfind(DAVPropertyBackend *b, PropfindRequest *rq ,char *path) { + struct stat st; + if(stat(path, &st) != 0) { + perror("dav_be_propfind"); + fprintf(stderr, "Cannot get stat of file: %s\n", path); + } + + DAV_FOREACH(elm, rq->properties) { + DavProperty *prop = (DavProperty*)elm->data; + + char *s = prop->name; + if(!strcmp(s, "resourcetype")) { + if(S_ISDIR(st.st_mode)) { + dav_propfind_add_str_prop(rq, prop, "", 15); + } else { + dav_propfind_add_str_prop(rq, prop, NULL, 0); + } + } else if(!strcmp(s, "getcontentlength") && !S_ISDIR(st.st_mode)) { + char buf[32]; + size_t n = snprintf(buf, 32, "%d", st.st_size); + dav_propfind_add_str_prop(rq, prop, buf, n); + } else { + dav_propfind_add_prop_error(rq, prop, 404); + } + } +}