Prechádzať zdrojové kódy

Rewrite PUT and DELETE handlers for files

bel 10 rokov pred
rodič
commit
f3cdda5abf
1 zmenil súbory, kde vykonal 92 pridanie a 37 odobranie
  1. 92 37
      src/civetweb.c

+ 92 - 37
src/civetweb.c

@@ -151,6 +151,7 @@ typedef long off_t;
 #define SSL_LIB   "ssleay32.dll"
 #define CRYPTO_LIB  "libeay32.dll"
 #define O_NONBLOCK  0
+#define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */
 #if !defined(EWOULDBLOCK)
 #define EWOULDBLOCK  WSAEWOULDBLOCK
 #endif /* !EWOULDBLOCK */
@@ -161,6 +162,7 @@ typedef long off_t;
 #define SHUT_WR 1
 #define snprintf _snprintf
 #define vsnprintf _vsnprintf
+#define access _access
 #define mg_sleep(x) Sleep(x)
 
 #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];
     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) {
         /* put_dir returns 0 if path is a directory */
         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.
-           No need to put a file. */
+        No need to put a file. */
         return;
     }
 
@@ -4873,8 +4915,6 @@ static void put_file(struct mg_connection *conn, const char *path)
         return;
     }
 
-    /* TODO: If the file exists and is read only, return 403 or 405 */
-
     /* A file should be created or overwritten. */
     if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
         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)) {
         /* 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;
     }
 
     gmt_time_string(date, sizeof(date), &curtime);
     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);
 }
 
@@ -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 */
         send_http_error(conn, 404, NULL,
             "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 *,