completed virtual propfind support in rados

This commit is contained in:
Unbit
2014-06-28 09:40:05 +02:00
parent f8685eee3e
commit 37ccff581d
3 changed files with 123 additions and 7 deletions
+12 -7
View File
@@ -17,7 +17,7 @@ struct uwsgi_buffer *uwsgi_webdav_multistatus_new() {
struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
if (uwsgi_buffer_append(ub, "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n", 40)) goto error;
if (uwsgi_buffer_append(ub, "<D:multistatus xmlns:D=\"DAV:\">\n", 31)) goto error;
return ub;
error:
uwsgi_buffer_destroy(ub);
return NULL;
@@ -63,19 +63,25 @@ int uwsgi_webdav_propfind_item_add(struct uwsgi_buffer *ub, char *href, uint16_t
if (uwsgi_webdav_multistatus_response_new(ub)) return -1;
if (uwsgi_buffer_append(ub, "<D:href>", 8)) return -1;
if (uwsgi_buffer_append(ub, href, href_len)) return -1;
if (uwsgi_buffer_append(ub, "</D:href>\n", 10)) return -1;
if (uwsgi_webdav_multistatus_propstat_new(ub)) return -1;
if (uwsgi_webdav_multistatus_prop_new(ub)) return -1;
// getcontentlength
if (uwsgi_buffer_append(ub, "<D:getcontentlength>", 20)) return -1;
if (uwsgi_buffer_num64(ub, cl)) return -1;
if (uwsgi_buffer_append(ub, "</D:getcontentlength>", 21)) return -1;
if (href[href_len-1] == '/') {
if (uwsgi_buffer_append(ub, "<D:resourcetype><D:collection/></D:resourcetype>\n", 49)) return -1;
}
else {
// getcontentlength
if (uwsgi_buffer_append(ub, "<D:getcontentlength>", 20)) return -1;
if (uwsgi_buffer_num64(ub, cl)) return -1;
if (uwsgi_buffer_append(ub, "</D:getcontentlength>\n", 22)) return -1;
}
// getlastmodified
if (mtime > 0) {
if (uwsgi_buffer_append(ub, "<D:getlastmodified>", 19)) return -1;
if (uwsgi_buffer_httpdate(ub, mtime)) return -1;
if (uwsgi_buffer_append(ub, "</D:getlastmodified>", 20)) return -1;
if (uwsgi_buffer_append(ub, "</D:getlastmodified>\n", 21)) return -1;
}
// displayname
@@ -99,7 +105,6 @@ int uwsgi_webdav_propfind_item_add(struct uwsgi_buffer *ub, char *href, uint16_t
if (uwsgi_webdav_multistatus_prop_close(ub)) return -1;
if (uwsgi_webdav_multistatus_propstat_close(ub)) return -1;
if (uwsgi_buffer_append(ub, "</D:href>\n", 10)) return -1;
if (uwsgi_webdav_multistatus_response_close(ub)) return -1;
return 0;
}
+102
View File
@@ -46,6 +46,7 @@ struct uwsgi_rados_mountpoint {
char *allow_put;
char *allow_delete;
char *allow_mkcol;
char *allow_propfind;
};
static struct uwsgi_option uwsgi_rados_options[] = {
@@ -313,6 +314,77 @@ static int uwsgi_rados_read_async(struct wsgi_request *wsgi_req, rados_ioctx_t c
return ret;
}
static void uwsgi_rados_propfind(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, char *key, uint64_t size, time_t mtime, int timeout) {
if (uwsgi_response_prepare_headers(wsgi_req, "207 Multi-Status", 16)) return;
if (uwsgi_response_add_content_type(wsgi_req, "text/xml; charset=\"utf-8\"", 25)) return;
struct uwsgi_buffer *ub = uwsgi_webdav_multistatus_new();
if (!ub) return;
if (key) {
size_t mime_type_len = 0;
char *mime_type = uwsgi_get_mime_type(key, strlen(key), &mime_type_len);
char *slashed = uwsgi_concat2("/", key);
if (uwsgi_webdav_propfind_item_add(ub, slashed, strlen(key)+1, size, mtime, mime_type, mime_type_len, NULL, 0, NULL, 0)) {
free(slashed);
goto end;
}
free(slashed);
if (uwsgi_webdav_multistatus_close(ub)) goto end;
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
goto end;
}
// request for /
size_t 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);
}
if (depth == 0) {
if (uwsgi_webdav_propfind_item_add(ub, "/", 1, 0, 0, NULL, 0, NULL, 0, NULL, 0)) {
goto end;
}
if (uwsgi_webdav_multistatus_close(ub)) goto end;
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
goto end;
}
struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id];
rados_list_ctx_t ctx_list;
if (rados_objects_list_open(ctx, &ctx_list) < 0) {
goto end;
}
char *entry = NULL;
while(rados_objects_list_next(ctx_list, (const char **)&entry, NULL) == 0) {
uint64_t stat_size = 0;
time_t stat_mtime = 0;
if (uwsgi.async > 1) {
if (uwsgi_rados_async_stat(urio, ctx, entry, &stat_size, &stat_mtime, timeout) < 0) goto end;
}
else {
if (rados_stat(ctx, entry, &stat_size, &stat_mtime) < 0) goto end;
}
size_t mime_type_len = 0;
char *mime_type = uwsgi_get_mime_type(entry, strlen(entry), &mime_type_len);
char *slashed = uwsgi_concat2("/", entry);
if (uwsgi_webdav_propfind_item_add(ub, slashed, strlen(entry)+1, stat_size, stat_mtime, mime_type, mime_type_len, NULL, 0, NULL, 0)) {
free(slashed);
goto end;
}
free(slashed);
if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) goto end;
// reset buffer;
ub->pos = 0;
}
rados_objects_list_close(ctx_list);
if (uwsgi_webdav_multistatus_close(ub)) goto end;
uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
end:
uwsgi_buffer_destroy(ub);
}
static void uwsgi_rados_add_mountpoint(char *arg, size_t arg_len) {
struct uwsgi_rados_mountpoint *urmp = uwsgi_calloc(sizeof(struct uwsgi_rados_mountpoint));
@@ -324,6 +396,7 @@ static void uwsgi_rados_add_mountpoint(char *arg, size_t arg_len) {
"allow_put", &urmp->allow_put,
"allow_delete", &urmp->allow_delete,
"allow_mkcol", &urmp->allow_mkcol,
"allow_propfind", &urmp->allow_propfind,
NULL)) {
uwsgi_log("unable to parse rados mountpoint definition\n");
exit(1);
@@ -538,12 +611,32 @@ static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
goto end;
}
}
if (urmp->allow_propfind) {
if (uwsgi_buffer_append(ub_allow, ", PROPFIND", 10)) {
uwsgi_buffer_destroy(ub_allow);
goto end;
}
}
uwsgi_response_add_header(wsgi_req, "Allow", 5, ub_allow->buf, ub_allow->pos);
uwsgi_buffer_destroy(ub_allow);
goto end;
}
// empty paths are mapped to propfind
if (!wsgi_req->path_info_len == 0) {
if (!urmp->allow_propfind) {
goto nopropfind;
}
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3) || !uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) {
uwsgi_rados_propfind(wsgi_req, ctx, NULL, 0, 0, timeout);
goto end;
}
nopropfind:
uwsgi_405(wsgi_req);
goto end;
}
// MKCOL does not require stat
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MKCOL", 5)) {
if (!urmp->allow_mkcol) {
@@ -611,6 +704,15 @@ static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
goto end;
}
if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) {
if (!urmp->allow_propfind) {
uwsgi_405(wsgi_req);
goto end;
}
uwsgi_rados_propfind(wsgi_req, ctx, filename, stat_size, stat_mtime, timeout);
goto end;
}
if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4) && uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3)) {
uwsgi_405(wsgi_req);
goto end;
+9
View File
@@ -4821,6 +4821,15 @@ void uwsgi_emperor_ini_attrs(char *, char *, struct uwsgi_dyn_dict **);
int uwsgi_buffer_httpdate(struct uwsgi_buffer *, time_t);
int uwsgi_buffer_append_xml(struct uwsgi_buffer *, char *, size_t);
struct uwsgi_buffer *uwsgi_webdav_multistatus_new();
int uwsgi_webdav_propfind_item_add(struct uwsgi_buffer *, char *, uint16_t, uint64_t, time_t, char *, uint16_t, char *, uint16_t, char *, uint16_t);
int uwsgi_webdav_multistatus_close(struct uwsgi_buffer *);
int uwsgi_webdav_multistatus_response_new(struct uwsgi_buffer *);
int uwsgi_webdav_multistatus_response_close(struct uwsgi_buffer *);
int uwsgi_webdav_multistatus_propstat_new(struct uwsgi_buffer *);
int uwsgi_webdav_multistatus_propstat_close(struct uwsgi_buffer *);
int uwsgi_webdav_multistatus_prop_new(struct uwsgi_buffer *);
int uwsgi_webdav_multistatus_prop_close(struct uwsgi_buffer *);
#ifdef __cplusplus
}
#endif