completed PROPPATCH

This commit is contained in:
Unbit
2013-04-28 09:46:10 +02:00
parent 34452376db
commit 0a6eb596bb
+153 -1
View File
@@ -26,7 +26,7 @@
3) realpath() on it
step 3 could file (for example on MKCOL or PUT). In such a case:
step 3 could be a non-existent file (for example on MKCOL or PUT). In such a case:
4) find the last / in the path_info, and try realpath() on it, if success the resource can be created
@@ -350,6 +350,157 @@ static int uwsgi_wevdav_manage_propfind(struct wsgi_request *wsgi_req, xmlDoc *
return UWSGI_OK;
}
static int uwsgi_webdav_prop_set(char *filename, char *attr, char *ns, char *body) {
int ret = 0;
#ifdef __linux__
char *xattr_name = NULL;
if (ns) {
xattr_name = uwsgi_concat4("user.uwsgi.webdav.", ns, "|", attr);
}
else {
xattr_name = uwsgi_concat2("user.uwsgi.webdav.", attr);
}
ret = setxattr(filename, xattr_name, body, strlen(body), 0);
free(xattr_name);
#endif
return ret;
}
static int uwsgi_webdav_prop_del(char *filename, char *attr, char *ns) {
int ret = 0;
#ifdef __linux__
char *xattr_name = NULL;
if (ns) {
xattr_name = uwsgi_concat4("user.uwsgi.webdav.", ns, "|", attr);
}
else {
xattr_name = uwsgi_concat2("user.uwsgi.webdav.", attr);
}
ret = removexattr(filename, xattr_name);
free(xattr_name);
#endif
return ret;
}
static void uwsgi_webdav_do_prop_update(struct wsgi_request *wsgi_req, xmlNode *prop, xmlNode *response, char *filename, uint8_t action) {
xmlNode *node;
// search for "prop"
for (node = prop->children; node; node = node->next) {
if (node->type == XML_ELEMENT_NODE) {
xmlNode *propstat = xmlNewChild(response, NULL, BAD_CAST "propstat", NULL);
xmlNode *r_prop = xmlNewChild(propstat, NULL, BAD_CAST "prop" , NULL);
xmlNode *new_prop = xmlNewChild(r_prop, NULL, node->name, NULL);
if (node->ns) {
xmlNsPtr xattr_ns = xmlNewNs(new_prop, node->ns->href, NULL);
xmlSetNs(new_prop, xattr_ns);
}
if (action == 0) {
if (uwsgi_webdav_prop_set(filename, (char *) node->name, node->ns ? (char *) node->ns->href : NULL, node->children ? (char *) node->children->content : "")) {
char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 403 Forbidden", 14);
xmlNewChild(r_prop, NULL, BAD_CAST "status", BAD_CAST r_status);
free(r_status);
}
else {
char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 200 OK", 7);
xmlNewChild(r_prop, NULL, BAD_CAST "status", BAD_CAST r_status);
free(r_status);
}
}
else if (action == 1) {
if (uwsgi_webdav_prop_del(filename, (char *) node->name, node->ns ? (char *) node->ns->href : NULL)) {
char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 403 Forbidden", 14);
xmlNewChild(r_prop, NULL, BAD_CAST "status", BAD_CAST r_status);
free(r_status);
}
else {
char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 200 OK", 7);
xmlNewChild(r_prop, NULL, BAD_CAST "status", BAD_CAST r_status);
free(r_status);
}
}
}
}
}
// action 0 is set, 1 is remove
static void uwsgi_webdav_manage_prop_update(struct wsgi_request *wsgi_req, xmlNode *parent, xmlNode *response, char *filename, uint8_t action) {
xmlNode *node;
// search for "prop"
for (node = parent->children; node; node = node->next) {
if (node->type == XML_ELEMENT_NODE) {
if (node->ns && !strcmp((char *) node->ns->href, "DAV:")) {
if (!strcmp((char *) node->name, "prop")) {
uwsgi_webdav_do_prop_update(wsgi_req, node, response, filename, action);
}
}
}
}
}
static int uwsgi_wevdav_manage_proppatch(struct wsgi_request *wsgi_req, xmlDoc * doc) {
char filename[PATH_MAX];
size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename);
if (filename_len == 0) {
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
xmlNode *element = xmlDocGetRootElement(doc);
if (!element) return -1;
if (!element || strcmp((char *) element->name, "propertyupdate")) return -1;
if (uwsgi_response_prepare_headers(wsgi_req, "207 Multi-Status", 16))
return -1;
if (uwsgi_response_add_content_type(wsgi_req, "application/xml; charset=\"utf-8\"", 32))
return -1;
xmlDoc *rdoc = xmlNewDoc(BAD_CAST "1.0");
xmlNode *multistatus = xmlNewNode(NULL, BAD_CAST "multistatus");
xmlDocSetRootElement(rdoc, multistatus);
xmlNsPtr dav_ns = xmlNewNs(multistatus, BAD_CAST "DAV:", BAD_CAST "D");
xmlSetNs(multistatus, dav_ns);
xmlNode *response = xmlNewChild(multistatus, dav_ns, BAD_CAST "response", NULL);
char *uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0);
uint16_t uri_len = strlen(uri) ;
char *encoded_uri = uwsgi_malloc( (uri_len * 3) + 1);
http_url_encode(uri, &uri_len, encoded_uri);
encoded_uri[uri_len] = 0;
xmlNewChild(response, dav_ns, BAD_CAST "href", BAD_CAST encoded_uri);
free(encoded_uri);
// propfind can be "set" or "remove"
xmlNode *node;
for (node = element->children; node; node = node->next) {
if (node->type == XML_ELEMENT_NODE) {
if (node->ns && !strcmp((char *) node->ns->href, "DAV:")) {
if (!strcmp((char *) node->name, "set")) {
uwsgi_webdav_manage_prop_update(wsgi_req, node, response, filename, 0);
}
else if (!strcmp((char *) node->name, "remove")) {
uwsgi_webdav_manage_prop_update(wsgi_req, node, response, filename, 1);
}
}
}
}
if (!rdoc) return UWSGI_OK;
xmlChar *xmlbuf;
int xlen = 0;
xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1);
uwsgi_response_add_content_length(wsgi_req, xlen);
uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen);
#ifdef UWSGI_DEBUG
uwsgi_log("\n%.*s\n", xlen, xmlbuf);
#endif
xmlFreeDoc(rdoc);
xmlFree(xmlbuf);
return UWSGI_OK;
}
static int uwsgi_wevdav_manage_put(struct wsgi_request *wsgi_req) {
char filename[PATH_MAX];
size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename);
@@ -830,6 +981,7 @@ static int uwsgi_webdav_request(struct wsgi_request *wsgi_req) {
#endif
xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0);
if (!doc) goto end;
uwsgi_wevdav_manage_proppatch(wsgi_req, doc);
xmlFreeDoc(doc);
}