added the WebDAV plugin (beta)

This commit is contained in:
Unbit
2013-04-27 18:24:21 +02:00
parent cdc41c305e
commit ec491ebd83
3 changed files with 783 additions and 2 deletions
+8
View File
@@ -0,0 +1,8 @@
import os
NAME='webdav'
CFLAGS = os.popen('xml2-config --cflags').read().rstrip().split()
LDFLAGS = []
LIBS = os.popen('xml2-config --libs').read().rstrip().split()
GCC_LIST = ['webdav']
+773
View File
@@ -0,0 +1,773 @@
#include <uwsgi.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
/*
rfc4918 implementation (WebDAV)
requires libxml2
--webdav-mount [mountpoint=]<dir>
or
--webdav-use-docroot[=VAR]
steps to build a path:
1) get the mountpoint
2) concat the base with the path_info
3) realpath() on it
step 3 could 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
ALL MUST BE BOTH THREAD SAFE AND ASYNC SAFE !!!
Locking requires a cache (local or remote)
when a lock request is made, an item is added to the cache (directly using cache_set to avoid duplicates). The
item key is the full url of the request (host + path_info, in such a way we have virtualhosting for locks). The value is
a uuid.
if a lock_token is passed the url is checked in the cache and uuid compared
*/
extern struct uwsgi_server uwsgi;
struct uwsgi_plugin webdav_plugin;
struct uwsgi_webdav {
struct uwsgi_string_list *mountpoints;
struct uwsgi_string_list *css;
struct uwsgi_string_list *javascript;
char *class_directory;
char *div;
} udav;
struct uwsgi_option uwsgi_webdav_options[] = {
{ "webdav-mount", required_argument, 0, "map a filesystem directory as a webdav store", uwsgi_opt_add_string_list, &udav.mountpoints, UWSGI_OPT_MIME},
{ "webdav-css", required_argument, 0, "add a css url for automatic webdav directory listing", uwsgi_opt_add_string_list, &udav.css, UWSGI_OPT_MIME},
{ "webdav-javascript", required_argument, 0, "add a javascript url for automatic webdav directory listing", uwsgi_opt_add_string_list, &udav.javascript, UWSGI_OPT_MIME},
{ "webdav-js", required_argument, 0, "add a javascript url for automatic webdav directory listing", uwsgi_opt_add_string_list, &udav.javascript, UWSGI_OPT_MIME},
{ "webdav-class-directory", required_argument, 0, "set the css directory class for automatic webdav directory listing", uwsgi_opt_set_str, &udav.class_directory, UWSGI_OPT_MIME},
{ "webdav-div", required_argument, 0, "set the div id for automatic webdav directory listing", uwsgi_opt_set_str, &udav.div, UWSGI_OPT_MIME},
{ 0, 0, 0, 0, 0, 0, 0 },
};
/*
OPTIONS: if it is a valid webdav resource add Dav: to the response header
*/
static int uwsgi_wevdav_manage_options(struct wsgi_request *wsgi_req) {
uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6);
uwsgi_response_add_header(wsgi_req, "Dav", 3, "1, 2", 4);
return UWSGI_OK;
}
static char *uwsgi_webdav_new_date(uint64_t t) {
// 30+1
char d[31];
int len = uwsgi_http_date((time_t) t, d);
if (!len) {
return NULL;
}
return uwsgi_concat2n(d, len, "", 0);
}
static int uwsgi_webdav_add_props(struct wsgi_request *wsgi_req, xmlNode * multistatus, xmlNsPtr dav_ns, char *uri, char *filename) {
struct stat st;
if (stat(filename, &st)) {
uwsgi_error("uwsgi_webdav_add_props()/stat()");
return -1;
}
xmlNode *response = xmlNewChild(multistatus, dav_ns, BAD_CAST "response", NULL);
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);
xmlNode *r_propstat = xmlNewChild(response, dav_ns, BAD_CAST "propstat", NULL);
char *r_status = uwsgi_concat2n(wsgi_req->protocol, wsgi_req->protocol_len, " 200 OK", 7);
xmlNewChild(r_propstat, dav_ns, BAD_CAST "status", BAD_CAST r_status);
free(r_status);
xmlNode *r_prop = xmlNewChild(r_propstat, dav_ns, BAD_CAST "prop", NULL);
xmlNewChild(r_prop, dav_ns, BAD_CAST "displayname", BAD_CAST uri);
xmlNode *r_type = xmlNewChild(r_prop, dav_ns, BAD_CAST "resourcetype", NULL);
if (S_ISDIR(st.st_mode)) {
xmlNewChild(r_type, dav_ns, BAD_CAST "collection", NULL);
}
else {
char *r_contentlength = uwsgi_num2str(st.st_size);
xmlNewChild(r_prop, dav_ns, BAD_CAST "getcontentlength", BAD_CAST r_contentlength);
free(r_contentlength);
size_t mime_type_len = 0;
char *mime_type = uwsgi_get_mime_type(filename, strlen(filename), &mime_type_len);
if (mime_type) {
char *r_ctype = uwsgi_concat2n(mime_type, mime_type_len, "", 0);
xmlNewChild(r_prop, dav_ns, BAD_CAST "getcontenttype", BAD_CAST r_ctype);
free(r_ctype);
}
}
// there is no creation date on UNIX/POSIX, ctime is the nearest thing...
char *cdate = uwsgi_webdav_new_date(st.st_ctime);
if (cdate) {
xmlNewChild(r_prop, dav_ns, BAD_CAST "creationdate", BAD_CAST cdate);
free(cdate);
}
char *mdate = uwsgi_webdav_new_date(st.st_mtime);
if (mdate) {
xmlNewChild(r_prop, dav_ns, BAD_CAST "getlastmodified", BAD_CAST mdate);
free(mdate);
}
xmlNewChild(r_prop, dav_ns, BAD_CAST "executable", NULL);
return 0;
}
static size_t uwsgi_webdav_expand_path(struct wsgi_request *wsgi_req, char *item, uint16_t item_len, char *filename) {
struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id];
char *docroot = ua->interpreter;
size_t docroot_len = strlen(docroot);
// merge docroot with path_info
char *tmp_filename = uwsgi_concat3n(docroot, docroot_len, "/", 1, item, item_len);
// try expanding the path
if (!realpath(tmp_filename, filename)) {
free(tmp_filename);
return 0;
}
free(tmp_filename);
return strlen(filename);
}
static size_t uwsgi_webdav_expand_fake_path(struct wsgi_request *wsgi_req, char *item, uint16_t item_len, char *filename) {
char *last_slash = memrchr(item, '/', item_len);
if (!last_slash) return 0;
size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, item, last_slash - item, filename);
if (!filename_len) return 0;
// check for overflow
if (filename_len + (item_len - (last_slash - item)) >= PATH_MAX) return 0;
memcpy(filename + filename_len, last_slash, (item_len - (last_slash - item)));
filename_len += (item_len - (last_slash - item));
filename[(int)filename_len] = 0;
return filename_len;
}
static int uwsgi_wevdav_manage_propfind(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;
}
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;
xmlNode *element = xmlDocGetRootElement(doc);
if (!element) return -1;
if (!element || strcmp((char *) element->name, "propfind")) return -1;
// propfind must have a child (scan them until you find a valid one)
xmlNode *action = element->children;
if (!action) return -1;
#ifdef UWSGI_DEBUG
uwsgi_log("action = %s ns: %s\n", action->name, action->ns ? (char *) action->ns->href : "");
#endif
int depth = 0;
uint16_t http_depth_len = 0;
char *http_depth = uwsgi_get_var(wsgi_req, "HTTP_DEPTH", 10, &http_depth_len);
if (http_depth) {
depth = uwsgi_str_num(http_depth, http_depth_len);
}
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);
if (depth == 0) {
char *uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0);
uwsgi_webdav_add_props(wsgi_req, multistatus, dav_ns, uri, filename);
free(uri);
}
else {
DIR *collection = opendir(filename);
struct dirent de;
for (;;) {
struct dirent *de_r = NULL;
if (readdir_r(collection, &de, &de_r)) {
uwsgi_error("uwsgi_wevdav_manage_propfind()/readdir_r()");
break;
}
if (de_r == NULL) {
break;
}
char *uri = NULL;
char *direntry = NULL;
if (!strcmp(de.d_name, "..")) {
// skip ..
continue;
}
else if (!strcmp(de.d_name, ".")) {
uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0);
direntry = uwsgi_concat2n(filename, filename_len, "", 0);
}
else if (wsgi_req->path_info[wsgi_req->path_info_len - 1] == '/') {
uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, de.d_name, strlen(de.d_name));
direntry = uwsgi_concat3n(filename, filename_len, "/", 1, de.d_name, strlen(de.d_name));
}
else {
uri = uwsgi_concat3n(wsgi_req->path_info, wsgi_req->path_info_len, "/", 1, de.d_name, strlen(de.d_name));
direntry = uwsgi_concat3n(filename, filename_len, "/", 1, de.d_name, strlen(de.d_name));
}
uwsgi_webdav_add_props(wsgi_req, multistatus, dav_ns, uri, direntry);
free(uri);
free(direntry);
}
closedir(collection);
}
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);
// the collection does not exist, search for the last /
if (!filename_len) {
filename_len = uwsgi_webdav_expand_fake_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename);
if (!filename_len) {
uwsgi_response_prepare_headers(wsgi_req, "409 Conflict", 12);
return UWSGI_OK;
}
}
int fd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd < 0) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
if (uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11)) goto end;
size_t remains = wsgi_req->post_cl;
while(remains > 0) {
ssize_t body_len = 0;
char *body = uwsgi_request_body_read(wsgi_req, UMIN(remains, 32768) , &body_len);
if (!body || body == uwsgi.empty) break;
if (write(fd, body, body_len) != body_len) goto end;
}
end:
close(fd);
return UWSGI_OK;
}
static int uwsgi_webdav_massive_delete(char *dir) {
int ret = 0;
DIR *d = opendir(dir);
for (;;) {
struct dirent *de_r = NULL;
struct dirent de;
if (readdir_r(d, &de, &de_r)) {
ret = -1;
goto end;
}
if (de_r == NULL) break;
// skip myself and parent
if (!strcmp(de.d_name, ".") || !strcmp(de.d_name, "..")) continue;
char *item = uwsgi_concat3(dir, "/", de.d_name);
if (de.d_type == DT_DIR) {
if (uwsgi_webdav_massive_delete(item)) {
free(item);
ret = -1;
goto end;
}
}
else {
if (unlink(item)) {
free(item);
ret = -1;
goto end;
}
}
free(item);
}
if (rmdir(dir)) ret = -1;
end:
closedir(d);
return ret;
}
static int uwsgi_wevdav_manage_delete(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);
// the collection does not exists
if (!filename_len) {
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
if (uwsgi_is_dir(filename)) {
int ret = rmdir(filename);
if (ret < 0) {
if (errno == ENOTEMPTY) {
if (uwsgi_webdav_massive_delete(filename)) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
}
else {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
}
}
else {
if (unlink(filename)) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
}
uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6);
return UWSGI_OK;
}
static int uwsgi_webdav_dirlist_add_item(struct uwsgi_buffer *ub, char *item, size_t item_len, uint8_t is_dir) {
if (is_dir) {
if (udav.class_directory) {
if (uwsgi_buffer_append(ub, "<li class=\"", 11)) return -1;
if (uwsgi_buffer_append(ub, udav.class_directory, strlen(udav.class_directory))) return -1;
if (uwsgi_buffer_append(ub, "\"><a href=\"", 11)) return -1;
}
else {
if (uwsgi_buffer_append(ub, "<li class=\"directory\"><a href=\"", 31)) return -1;
}
}
else {
if (uwsgi_buffer_append(ub, "<li><a href=\"", 13)) return -1;
}
if (uwsgi_buffer_append(ub, item, item_len)) return -1;
if (is_dir) {
if (uwsgi_buffer_append(ub, "/\">", 3)) return -1;
if (uwsgi_buffer_append(ub, item, item_len)) return -1;
if (uwsgi_buffer_append(ub, "/", 1)) return -1;
}
else {
if (uwsgi_buffer_append(ub, "\">", 2)) return -1;
if (uwsgi_buffer_append(ub, item, item_len)) return -1;
}
if (uwsgi_buffer_append(ub, "</a></li>", 9)) return -1;
return 0;
}
static void uwsgi_webdav_dirlist(struct wsgi_request *wsgi_req, char *dir) {
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
if (uwsgi_buffer_append(ub, "<html><head><title>", 19)) goto end;
if (uwsgi_buffer_append(ub, dir, strlen(dir))) goto end;
if (uwsgi_buffer_append(ub, "</title>", 8)) goto end;
struct uwsgi_string_list *usl = udav.css;
while(usl) {
if (uwsgi_buffer_append(ub, "<link rel=\"stylesheet\" href=\"", 29)) goto end;
if (uwsgi_buffer_append(ub, usl->value, usl->len)) goto end;
if (uwsgi_buffer_append(ub, "\" type=\"text/css\">", 18)) goto end;
usl = usl->next;
}
usl = udav.javascript;
while(usl) {
if (uwsgi_buffer_append(ub, "<script src=\"", 13)) goto end;
if (uwsgi_buffer_append(ub, usl->value, usl->len)) goto end;
if (uwsgi_buffer_append(ub, "\"></script>", 11)) goto end;
usl = usl->next;
}
if (uwsgi_buffer_append(ub, "</head><body>", 13)) goto end;
if (udav.div) {
if (uwsgi_buffer_append(ub, "<div id=\"", 9)) goto end;
if (uwsgi_buffer_append(ub, udav.div, strlen(udav.div))) goto end;
if (uwsgi_buffer_append(ub, "\">", 2)) goto end;
}
else {
if (uwsgi_buffer_append(ub, "<div>", 5)) goto end;
}
if (uwsgi_webdav_dirlist_add_item(ub, "..", 2, 1)) goto end;
#ifdef __linux__
struct dirent **tasklist;
int n = scandir(dir, &tasklist, 0, versionsort);
if (n < 0) goto end;
int i;
for(i=0;i<n;i++) {
if (tasklist[i]->d_name[0] == '.') goto next;
if (uwsgi_webdav_dirlist_add_item(ub, tasklist[i]->d_name, strlen(tasklist[i]->d_name), tasklist[i]->d_type == DT_DIR ? 1 : 0)) {
free(tasklist[i]);
free(tasklist);
goto end;
}
next:
free(tasklist[i]);
}
free(tasklist);
#else
DIR *d = opendir(dir);
for (;;) {
struct dirent *de_r = NULL;
struct dirent de;
if (readdir_r(d, &de, &de_r)) goto end;
if (de_r == NULL) break;
// skip items startign with a dot
if (de.d_name[0] == '.') continue;
if (uwsgi_webdav_dirlist_add_item(ub, de.d_name[0], strlen(de.d_name[0]), de.d_type == DT_DIR ? 1 : 0) goto end;
}
closedir(d);
#endif
if (uwsgi_buffer_append(ub, "</ul></div></body></html>", 25)) goto end;
if (uwsgi_response_add_content_type(wsgi_req, "text/html", 9)) goto end;
if (uwsgi_response_add_content_length(wsgi_req, ub->pos)) goto end;
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
end:
uwsgi_buffer_destroy(ub);
}
static int uwsgi_wevdav_manage_get(struct wsgi_request *wsgi_req, int send_body) {
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) {
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
if (uwsgi_is_dir(filename)) {
uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6);
if (send_body) {
uwsgi_webdav_dirlist(wsgi_req, filename);
}
return UWSGI_OK;
}
int fd = open(filename, O_RDONLY);
if (fd < 0) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
struct stat st;
if (fstat(fd, &st)) {
close(fd);
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6))
goto end;
// add content_length
if (uwsgi_response_add_content_length(wsgi_req, st.st_size))
goto end;
// add last-modified
if (uwsgi_response_add_last_modified(wsgi_req, st.st_mtime))
goto end;
// add mime_type
size_t mime_type_len = 0;
char *mime_type = uwsgi_get_mime_type(filename, filename_len, &mime_type_len);
if (mime_type) {
if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len))
goto end;
}
// add ETag (based on file mtime, not rock-solid, but good enough)
// start sending the file (note: we do not use sendfile() api, for being able to use caching and transformations)
if (!send_body)
goto end;
// use a pretty big buffer (for performance reasons)
char buf[32768];
size_t remains = st.st_size;
while (remains > 0) {
ssize_t rlen = read(fd, buf, UMIN(32768, remains));
if (rlen <= 0) {
uwsgi_error("uwsgi_wevdav_manage_get/read()");
break;
}
remains -= rlen;
if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) {
break;
}
}
end:
close(fd);
return UWSGI_OK;
}
static int uwsgi_wevdav_manage_copy(struct wsgi_request *wsgi_req) {
uint16_t destination_len = 0;
char *destination = uwsgi_get_var(wsgi_req, "HTTP_DESTINATION", 16, &destination_len);
uwsgi_log("Destination: %.*s\n", destination_len, destination);
return -1;
}
static int uwsgi_wevdav_manage_move(struct wsgi_request *wsgi_req) {
char filename[PATH_MAX];
char d_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;
}
uint16_t destination_len = 0;
char *destination = uwsgi_get_var(wsgi_req, "HTTP_DESTINATION", 16, &destination_len);
if (destination_len == 0) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
uint16_t overwrite_len = 0;
int can_overwrite = 1;
char *overwrite = uwsgi_get_var(wsgi_req, "HTTP_OVERWRITE", 14, &overwrite_len);
if (overwrite) {
if (overwrite[0] == 'F') {
can_overwrite = 0;
}
}
uint16_t scheme_len = wsgi_req->scheme_len;
if (wsgi_req->scheme_len == 0) {
// http
scheme_len = 4;
}
uint16_t skip = scheme_len + 3 + wsgi_req->host_len;
int already_exists = 0;
size_t d_filename_len = uwsgi_webdav_expand_path(wsgi_req, destination + skip, destination_len - skip, d_filename);
if (d_filename_len > 0) {
already_exists = 1;
if (!can_overwrite) {
uwsgi_response_prepare_headers(wsgi_req, "412 Precondition Failed", 23);
return UWSGI_OK;
}
}
else {
d_filename_len = uwsgi_webdav_expand_fake_path(wsgi_req, destination + skip, destination_len - skip, d_filename);
}
if (d_filename_len == 0) {
uwsgi_response_prepare_headers(wsgi_req, "409 Conflict", 12);
return UWSGI_OK;
}
if (rename(filename, d_filename)) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
if (already_exists) {
uwsgi_response_prepare_headers(wsgi_req, "204 No Content", 14);
}
else {
uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11);
}
return UWSGI_OK;
}
static int uwsgi_wevdav_manage_mkcol(struct wsgi_request *wsgi_req) {
if (wsgi_req->post_cl > 0) {
uwsgi_response_prepare_headers(wsgi_req, "415 Unsupported Media Type", 26);
return UWSGI_OK;
}
char filename[PATH_MAX];
size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename);
// the collection already exists
if (filename_len > 0) {
uwsgi_response_prepare_headers(wsgi_req, "405 Method Not Allowed", 22);
return UWSGI_OK;
}
// remove the last slash (if needed)
if (wsgi_req->path_info_len > 1 && wsgi_req->path_info[wsgi_req->path_info_len-1] == '/') {
wsgi_req->path_info_len--;
}
filename_len = uwsgi_webdav_expand_fake_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename);
if (!filename_len) {
uwsgi_response_prepare_headers(wsgi_req, "409 Conflict", 12);
return UWSGI_OK;
}
// mkdir, if it fails, return a 409 (Conflict)
if (mkdir(filename, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
uwsgi_response_prepare_headers(wsgi_req, "409 Conflict", 12);
}
uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11);
return UWSGI_OK;
}
static int uwsgi_wevdav_manage_lock(struct wsgi_request *wsgi_req) {
uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11);
return UWSGI_OK;
}
static int uwsgi_webdav_request(struct wsgi_request *wsgi_req) {
if (!udav.mountpoints) {
uwsgi_500(wsgi_req);
return -1;
}
if (uwsgi_parse_vars(wsgi_req)) {
return -1;
}
if (wsgi_req->path_info_len == 0) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, webdav_plugin.modifier1);
if (wsgi_req->app_id == -1) {
uwsgi_403(wsgi_req);
return UWSGI_OK;
}
// non lockables methods...
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "OPTIONS", 7)) {
return uwsgi_wevdav_manage_options(wsgi_req);
}
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3)) {
return uwsgi_wevdav_manage_get(wsgi_req, 1);
}
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
return uwsgi_wevdav_manage_get(wsgi_req, 0);
}
// lockable methods ...
// check for locking
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PUT", 3)) {
return uwsgi_wevdav_manage_put(wsgi_req);
}
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "DELETE", 6)) {
return uwsgi_wevdav_manage_delete(wsgi_req);
}
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MKCOL", 5)) {
return uwsgi_wevdav_manage_mkcol(wsgi_req);
}
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "COPY", 4)) {
return uwsgi_wevdav_manage_copy(wsgi_req);
}
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MOVE", 4)) {
return uwsgi_wevdav_manage_move(wsgi_req);
}
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "LOCK", 4)) {
if (wsgi_req->post_cl > 0) {
ssize_t body_len = 0;
char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len);
uwsgi_log("%.*s\n", body_len, body);
}
return uwsgi_wevdav_manage_lock(wsgi_req);
}
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) {
if (wsgi_req->post_cl == 0)
goto end;
ssize_t body_len = 0;
char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len);
#ifdef UWSGI_DEBUG
uwsgi_log("%.*s\n", body_len, body);
#endif
xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0);
if (!doc) goto end;
uwsgi_wevdav_manage_propfind(wsgi_req, doc);
xmlFreeDoc(doc);
}
end:
return UWSGI_OK;
}
static void uwsgi_webdav_mount() {
struct uwsgi_string_list *usl = udav.mountpoints;
while(usl) {
if (uwsgi_apps_cnt >= uwsgi.max_apps) {
uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps);
exit(1);
}
int id = uwsgi_apps_cnt;
char *mountpoint = "";
int mountpoint_len = 0;
char *docroot = usl->value;
char *equal = strchr(usl->value, '=');
if (equal) {
*equal = 0;
docroot = equal+1;
mountpoint = usl->value;
mountpoint_len = strlen(mountpoint);
}
char *wd_docroot = uwsgi_calloc(PATH_MAX);
if (!realpath(docroot, wd_docroot)) {
uwsgi_error("uwsgi_webdav_mount()/realpath()");
exit(1);
}
if (equal) {
*equal = '=';
}
struct uwsgi_app *ua = uwsgi_add_app(id, webdav_plugin.modifier1, mountpoint, mountpoint_len, wd_docroot, wd_docroot);
uwsgi_emulate_cow_for_apps(id);
uwsgi_log("WebDAV mountpoint \"%.*s\" (%d) added: docroot=%s\n", ua->mountpoint_len, ua->mountpoint, id, wd_docroot );
usl = usl->next;
}
}
static void uwsgi_webdav_after_request(struct wsgi_request *wsgi_req) {
if (!udav.mountpoints) return;
log_request(wsgi_req);
}
struct uwsgi_plugin webdav_plugin = {
.modifier1 = 35,
.name = "webdav",
.options = uwsgi_webdav_options,
.init_apps = uwsgi_webdav_mount,
.request = uwsgi_webdav_request,
.after_request = uwsgi_webdav_after_request,
};
+2 -2
View File
@@ -282,7 +282,7 @@ apply:
return UWSGI_OK;
}
output = uwsgi_xslt_apply(doc, stylesheet, params, &output_rlen);
xmlFree(doc);
xmlFreeDoc(doc);
if (params) free(params);
if (!output) {
uwsgi_500(wsgi_req);
@@ -413,7 +413,7 @@ static int uwsgi_routing_func_xslt(struct wsgi_request *wsgi_req, struct uwsgi_r
xmlDoc *doc = xmlParseFile(ub_doc->buf) ;
if (!doc) goto end;
char *output = uwsgi_xslt_apply(doc, ub_stylesheet->buf, ub_params ? ub_params->buf : NULL, &rlen);
xmlFree(doc);
xmlFreeDoc(doc);
if (!output) goto end;
if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end;