Commit 17ecb0a4 authored by Stefan Doehla's avatar Stefan Doehla

MKCOL and recursive DELETE

parent afd39abc
...@@ -2695,6 +2695,50 @@ static int scan_directory(struct mg_connection *conn, const char *dir, ...@@ -2695,6 +2695,50 @@ static int scan_directory(struct mg_connection *conn, const char *dir,
return 1; return 1;
} }
static int remove_directory(struct mg_connection *conn, const char *dir) {
char path[PATH_MAX];
struct dirent *dp;
DIR *dirp;
struct de de;
if ((dirp = opendir(dir)) == NULL) {
return 0;
} else {
de.conn = conn;
while ((dp = readdir(dirp)) != NULL) {
// Do not show current dir (but show hidden files as they will also be removed)
if (!strcmp(dp->d_name, ".") ||
!strcmp(dp->d_name, "..")) {
continue;
}
mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
// If we don't memset stat structure to zero, mtime will have
// garbage and strftime() will segfault later on in
// print_dir_entry(). memset is required only if mg_stat()
// fails. For more details, see
// http://code.google.com/p/mongoose/issues/detail?id=79
memset(&de.file, 0, sizeof(de.file));
mg_stat(conn, path, &de.file);
if(de.file.modification_time) {
if(de.file.is_directory) {
remove_directory(conn, path);
} else {
mg_remove(path);
}
}
}
(void) closedir(dirp);
rmdir(dir);
}
return 1;
}
struct dir_scan_data { struct dir_scan_data {
struct de *entries; struct de *entries;
int num_entries; int num_entries;
...@@ -2948,7 +2992,9 @@ static int is_valid_http_method(const char *method) { ...@@ -2948,7 +2992,9 @@ static int is_valid_http_method(const char *method) {
return !strcmp(method, "GET") || !strcmp(method, "POST") || return !strcmp(method, "GET") || !strcmp(method, "POST") ||
!strcmp(method, "HEAD") || !strcmp(method, "CONNECT") || !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
!strcmp(method, "PUT") || !strcmp(method, "DELETE") || !strcmp(method, "PUT") || !strcmp(method, "DELETE") ||
!strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND"); !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND")
|| !strcmp(method, "MKCOL")
;
} }
// Parse HTTP request, fill in mg_request_info structure. // Parse HTTP request, fill in mg_request_info structure.
...@@ -3466,6 +3512,46 @@ static int put_dir(struct mg_connection *conn, const char *path) { ...@@ -3466,6 +3512,46 @@ static int put_dir(struct mg_connection *conn, const char *path) {
return res; return res;
} }
static void mkcol(struct mg_connection *conn, const char *path) {
int rc, body_len;
struct de de;
memset(&de.file, 0, sizeof(de.file));
mg_stat(conn, path, &de.file);
if(de.file.modification_time) {
send_http_error(conn, 405, "Method Not Allowed",
"mkcol(%s): %s", path, strerror(ERRNO));
return;
}
body_len = conn->data_len - conn->request_len;
if(body_len > 0) {
send_http_error(conn, 415, "Unsupported media type",
"mkcol(%s): %s", path, strerror(ERRNO));
return;
}
rc = mg_mkdir(path, 0755);
if (rc == 0) {
conn->status_code = 201;
mg_printf(conn, "HTTP/1.1 %d Created\r\n\r\n", conn->status_code);
} else if (rc == -1) {
if(errno == EEXIST)
send_http_error(conn, 405, "Method Not Allowed",
"mkcol(%s): %s", path, strerror(ERRNO));
else if(errno == EACCES)
send_http_error(conn, 403, "Forbidden",
"mkcol(%s): %s", path, strerror(ERRNO));
else if(errno == ENOENT)
send_http_error(conn, 409, "Conflict",
"mkcol(%s): %s", path, strerror(ERRNO));
else
send_http_error(conn, 500, http_500_error,
"fopen(%s): %s", path, strerror(ERRNO));
}
}
static void put_file(struct mg_connection *conn, const char *path) { static void put_file(struct mg_connection *conn, const char *path) {
struct file file = STRUCT_FILE_INITIALIZER; struct file file = STRUCT_FILE_INITIALIZER;
const char *range; const char *range;
...@@ -3655,7 +3741,7 @@ static void send_options(struct mg_connection *conn) { ...@@ -3655,7 +3741,7 @@ static void send_options(struct mg_connection *conn) {
conn->status_code = 200; conn->status_code = 200;
mg_printf(conn, "%s", "HTTP/1.1 200 OK\r\n" mg_printf(conn, "%s", "HTTP/1.1 200 OK\r\n"
"Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS\r\n" "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, PROPFIND, MKCOL\r\n"
"DAV: 1\r\n\r\n"); "DAV: 1\r\n\r\n");
} }
...@@ -3684,10 +3770,12 @@ static void print_props(struct mg_connection *conn, const char* uri, ...@@ -3684,10 +3770,12 @@ static void print_props(struct mg_connection *conn, const char* uri,
static void print_dav_dir_entry(struct de *de, void *data) { static void print_dav_dir_entry(struct de *de, void *data) {
char href[PATH_MAX]; char href[PATH_MAX];
char href_encoded[PATH_MAX];
struct mg_connection *conn = (struct mg_connection *) data; struct mg_connection *conn = (struct mg_connection *) data;
mg_snprintf(conn, href, sizeof(href), "%s%s", mg_snprintf(conn, href, sizeof(href), "%s%s",
conn->request_info.uri, de->file_name); conn->request_info.uri, de->file_name);
print_props(conn, href, &de->file); mg_url_encode(href, href_encoded, PATH_MAX-1);
print_props(conn, href_encoded, &de->file);
} }
static void handle_propfind(struct mg_connection *conn, const char *path, static void handle_propfind(struct mg_connection *conn, const char *path,
...@@ -4182,7 +4270,7 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) { ...@@ -4182,7 +4270,7 @@ int mg_upload(struct mg_connection *conn, const char *destination_dir) {
static int is_put_or_delete_request(const struct mg_connection *conn) { static int is_put_or_delete_request(const struct mg_connection *conn) {
const char *s = conn->request_info.request_method; const char *s = conn->request_info.request_method;
return s != NULL && (!strcmp(s, "PUT") || !strcmp(s, "DELETE")); return s != NULL && (!strcmp(s, "PUT") || !strcmp(s, "DELETE") || !strcmp(s, "MKCOL"));
} }
static int get_first_ssl_listener_index(const struct mg_context *ctx) { static int get_first_ssl_listener_index(const struct mg_context *ctx) {
...@@ -4249,18 +4337,34 @@ static void handle_request(struct mg_connection *conn) { ...@@ -4249,18 +4337,34 @@ static void handle_request(struct mg_connection *conn) {
} else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) { } else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
send_http_error(conn, 404, "Not Found", "Not Found"); send_http_error(conn, 404, "Not Found", "Not Found");
} else if (is_put_or_delete_request(conn) && } else if (is_put_or_delete_request(conn) &&
(conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL || (is_authorized_for_put(conn) != 1)) {
is_authorized_for_put(conn) != 1)) {
send_authorization_request(conn); send_authorization_request(conn);
} else if (!strcmp(ri->request_method, "PUT")) { } else if (!strcmp(ri->request_method, "PUT")) {
put_file(conn, path); put_file(conn, path);
} else if (!strcmp(ri->request_method, "MKCOL")) {
mkcol(conn, path);
} else if (!strcmp(ri->request_method, "DELETE")) { } else if (!strcmp(ri->request_method, "DELETE")) {
if (mg_remove(path) == 0) { struct de de;
send_http_error(conn, 200, "OK", "%s", ""); memset(&de.file, 0, sizeof(de.file));
if(!mg_stat(conn, path, &de.file)) {
send_http_error(conn, 404, "Not Found", "%s", "File not found");
} else { } else {
if(de.file.modification_time) {
if(de.file.is_directory) {
remove_directory(conn, path);
send_http_error(conn, 204, "No Content", "%s", "");
} else if (mg_remove(path) == 0) {
send_http_error(conn, 204, "No Content", "%s", "");
} else {
send_http_error(conn, 423, "Locked", "remove(%s): %s", path,
strerror(ERRNO));
}
}
else {
send_http_error(conn, 500, http_500_error, "remove(%s): %s", path, send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
strerror(ERRNO)); strerror(ERRNO));
} }
}
} else if ((file.membuf == NULL && file.modification_time == (time_t) 0) || } else if ((file.membuf == NULL && file.modification_time == (time_t) 0) ||
must_hide_file(conn, path)) { must_hide_file(conn, path)) {
send_http_error(conn, 404, "Not Found", "%s", "File not found"); send_http_error(conn, 404, "Not Found", "%s", "File not found");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment