|
@@ -151,6 +151,7 @@ typedef long off_t;
|
|
#define SSL_LIB "ssleay32.dll"
|
|
#define SSL_LIB "ssleay32.dll"
|
|
#define CRYPTO_LIB "libeay32.dll"
|
|
#define CRYPTO_LIB "libeay32.dll"
|
|
#define O_NONBLOCK 0
|
|
#define O_NONBLOCK 0
|
|
|
|
+#define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */
|
|
#if !defined(EWOULDBLOCK)
|
|
#if !defined(EWOULDBLOCK)
|
|
#define EWOULDBLOCK WSAEWOULDBLOCK
|
|
#define EWOULDBLOCK WSAEWOULDBLOCK
|
|
#endif /* !EWOULDBLOCK */
|
|
#endif /* !EWOULDBLOCK */
|
|
@@ -161,6 +162,7 @@ typedef long off_t;
|
|
#define SHUT_WR 1
|
|
#define SHUT_WR 1
|
|
#define snprintf _snprintf
|
|
#define snprintf _snprintf
|
|
#define vsnprintf _vsnprintf
|
|
#define vsnprintf _vsnprintf
|
|
|
|
+#define access _access
|
|
#define mg_sleep(x) Sleep(x)
|
|
#define mg_sleep(x) Sleep(x)
|
|
|
|
|
|
#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
|
|
#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
|
|
@@ -4845,17 +4847,57 @@ static void put_file(struct mg_connection *conn, const char *path)
|
|
char date[64];
|
|
char date[64];
|
|
time_t curtime = time(NULL);
|
|
time_t curtime = time(NULL);
|
|
|
|
|
|
- conn->status_code = mg_stat(conn, path, &file) ? 200 : 201;
|
|
|
|
- rc = put_dir(conn, path);
|
|
|
|
|
|
+ if (mg_stat(conn, path, &file)) {
|
|
|
|
+ /* File already exists */
|
|
|
|
+ conn->status_code = 200;
|
|
|
|
+
|
|
|
|
+ if (file.is_directory) {
|
|
|
|
+ /* This is an already existing directory,
|
|
|
|
+ so there is nothing to do for the server. */
|
|
|
|
+ rc = 0;
|
|
|
|
+
|
|
|
|
+ } else {
|
|
|
|
+ /* File exists and is not a directory. */
|
|
|
|
+ /* Can it be replaced? */
|
|
|
|
+
|
|
|
|
+ if (file.modification_time == 0) {
|
|
|
|
+ /* This is an "in-memory" file, that can not be replaced */
|
|
|
|
+ send_http_error(conn, 405, NULL,
|
|
|
|
+ "Error: Put not possible\nReplacing %s is not supported", path);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Check if the server may write this file */
|
|
|
|
+ if (access(path, W_OK) == 0) {
|
|
|
|
+ /* Access granted */
|
|
|
|
+ conn->status_code = 200;
|
|
|
|
+ rc = 1;
|
|
|
|
+ } else {
|
|
|
|
+ send_http_error(conn, 403, NULL,
|
|
|
|
+ "Error: Put not possible\nReplacing %s is not allowed", path);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ /* File should be created */
|
|
|
|
+ conn->status_code = 201;
|
|
|
|
+ rc = put_dir(conn, path);
|
|
|
|
+ }
|
|
|
|
|
|
if (rc == 0) {
|
|
if (rc == 0) {
|
|
/* put_dir returns 0 if path is a directory */
|
|
/* put_dir returns 0 if path is a directory */
|
|
gmt_time_string(date, sizeof(date), &curtime);
|
|
gmt_time_string(date, sizeof(date), &curtime);
|
|
- mg_printf(conn, "HTTP/1.1 %d OK\r\nDate: %s\r\nContent-Length: 0\r\nConnection: %s\r\n\r\n",
|
|
|
|
- conn->status_code, date, suggest_connection_header(conn));
|
|
|
|
|
|
+ mg_printf(conn, "HTTP/1.1 %d %s\r\n"
|
|
|
|
+ "Date: %s\r\n"
|
|
|
|
+ "Content-Length: 0\r\n"
|
|
|
|
+ "Connection: %s\r\n\r\n",
|
|
|
|
+ conn->status_code, mg_get_response_code_text(conn->status_code, NULL),
|
|
|
|
+ date,
|
|
|
|
+ suggest_connection_header(conn)
|
|
|
|
+ );
|
|
|
|
|
|
/* Request to create a directory has been fulfilled successfully.
|
|
/* Request to create a directory has been fulfilled successfully.
|
|
- No need to put a file. */
|
|
|
|
|
|
+ No need to put a file. */
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -4873,8 +4915,6 @@ static void put_file(struct mg_connection *conn, const char *path)
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- /* TODO: If the file exists and is read only, return 403 or 405 */
|
|
|
|
-
|
|
|
|
/* A file should be created or overwritten. */
|
|
/* A file should be created or overwritten. */
|
|
if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
|
|
if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
|
|
mg_fclose(&file);
|
|
mg_fclose(&file);
|
|
@@ -4893,20 +4933,21 @@ static void put_file(struct mg_connection *conn, const char *path)
|
|
|
|
|
|
if (!forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) {
|
|
if (!forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) {
|
|
/* forward_body_data failed.
|
|
/* forward_body_data failed.
|
|
- The error code has already been sent to the client,
|
|
|
|
- and conn->status_code is already set. */
|
|
|
|
|
|
+ The error code has already been sent to the client,
|
|
|
|
+ and conn->status_code is already set. */
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
gmt_time_string(date, sizeof(date), &curtime);
|
|
gmt_time_string(date, sizeof(date), &curtime);
|
|
mg_printf(conn, "HTTP/1.1 %d %s\r\n"
|
|
mg_printf(conn, "HTTP/1.1 %d %s\r\n"
|
|
- "Date: %s\r\n"
|
|
|
|
- "Content-Length: 0\r\n"
|
|
|
|
- "Connection: %s\r\n\r\n",
|
|
|
|
- conn->status_code, mg_get_response_code_text(conn->status_code, NULL),
|
|
|
|
- date,
|
|
|
|
- suggest_connection_header(conn)
|
|
|
|
- );
|
|
|
|
|
|
+ "Date: %s\r\n"
|
|
|
|
+ "Content-Length: 0\r\n"
|
|
|
|
+ "Connection: %s\r\n\r\n",
|
|
|
|
+ conn->status_code, mg_get_response_code_text(conn->status_code, NULL),
|
|
|
|
+ date,
|
|
|
|
+ suggest_connection_header(conn)
|
|
|
|
+ );
|
|
|
|
+
|
|
mg_fclose(&file);
|
|
mg_fclose(&file);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -4918,29 +4959,43 @@ static void delete_file(struct mg_connection *conn, const char *path)
|
|
/* mg_stat returns 0 if the file does not exist */
|
|
/* mg_stat returns 0 if the file does not exist */
|
|
send_http_error(conn, 404, NULL,
|
|
send_http_error(conn, 404, NULL,
|
|
"Error: Cannot delete file\nFile %s not found", path);
|
|
"Error: Cannot delete file\nFile %s not found", path);
|
|
- } else {
|
|
|
|
- if (de.file.modification_time) {
|
|
|
|
- if(de.file.is_directory) {
|
|
|
|
- remove_directory(conn, path);
|
|
|
|
- /* Delete successful. (Do not send content for 204) */
|
|
|
|
- send_http_error(conn, 204, NULL, "%s", "");
|
|
|
|
- } else if (mg_remove(path) == 0) {
|
|
|
|
- /* Delete successful. (Do not send content for 204) */
|
|
|
|
- send_http_error(conn, 204, NULL, "%s", "");
|
|
|
|
- } else {
|
|
|
|
- /* Delete not successful (file locked). */
|
|
|
|
- send_http_error(conn, 423, NULL,
|
|
|
|
- "Error: Cannot delete file\nremove(%s): %s", path, strerror(ERRNO));
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- /* mg_stat returns != 0 and modification_time == 0
|
|
|
|
- if the file is in memory */
|
|
|
|
- send_http_error(conn, 405, NULL,
|
|
|
|
- "Error: Delete not possible\nDeleting %s is not supported", path);
|
|
|
|
- }
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
- /* TODO: put and delete should value the read only flag of files and return 403 */
|
|
|
|
|
|
+ if (file.modification_time == 0) {
|
|
|
|
+ /* mg_stat returns != 0 and modification_time == 0
|
|
|
|
+ if the file is cached in memory */
|
|
|
|
+ send_http_error(conn, 405, NULL,
|
|
|
|
+ "Error: Delete not possible\nDeleting %s is not supported", path);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (de.file.is_directory) {
|
|
|
|
+ remove_directory(conn, path);
|
|
|
|
+ /* TODO: remove_dir does not return success of the operation */
|
|
|
|
+ /* Assume delete is successful: Return 204 without content. */
|
|
|
|
+ send_http_error(conn, 204, NULL, "%s", "");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* This is an existing file (not a directory).
|
|
|
|
+ Check if write permission is given. */
|
|
|
|
+ if (access(path, W_OK) != 0) {
|
|
|
|
+ /* File is read only */
|
|
|
|
+ send_http_error(conn, 403, NULL,
|
|
|
|
+ "Error: Delete not possible\nDeleting %s is not allowed", path);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Try to delete it. */
|
|
|
|
+ if (mg_remove(path) == 0) {
|
|
|
|
+ /* Delete was successful: Return 204 without content. */
|
|
|
|
+ send_http_error(conn, 204, NULL, "%s", "");
|
|
|
|
+ } else {
|
|
|
|
+ /* Delete not successful (file locked). */
|
|
|
|
+ send_http_error(conn, 423, NULL,
|
|
|
|
+ "Error: Cannot delete file\nremove(%s): %s", path, strerror(ERRNO));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
static void send_ssi_file(struct mg_connection *, const char *,
|
|
static void send_ssi_file(struct mg_connection *, const char *,
|