浏览代码

Check and simplify HTTP error code handling (Step 3/3)

Check all send_http_error calls.
Introduce a new function mg_get_response_code_text to get the textual
representation of the HTTP status response from the numeric response
code for C and Lua.
Do no longer pass the textual response code through send_http_error,
but take it from the mg_get_response_code_text function.
bel 10 年之前
父节点
当前提交
bf17634af9
共有 2 个文件被更改,包括 172 次插入101 次删除
  1. 156 79
      src/civetweb.c
  2. 16 22
      src/mod_lua.inl

+ 156 - 79
src/civetweb.c

@@ -2350,7 +2350,8 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog,
 
     if ((pid = fork()) == -1) {
         /* Parent */
-        send_http_error(conn, 500, NULL, "fork(): %s", strerror(ERRNO));
+        send_http_error(conn, 500, NULL,
+            "Error: Creating CGI process\nfork(): %s", strerror(ERRNO));
     } else if (pid == 0) {
         /* Child */
         if (chdir(dir) != 0) {
@@ -3933,8 +3934,9 @@ static void handle_directory_request(struct mg_connection *conn,
     time_t curtime = time(NULL);
 
     if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
-        send_http_error(conn, 500, "Cannot open directory",
-                        "Error: opendir(%s): %s", dir, strerror(ERRNO));
+        send_http_error(conn, 500, NULL,
+            "Error: Cannot open directory\nopendir(%s): %s",
+            dir, strerror(ERRNO));
         return;
     }
 
@@ -4080,7 +4082,8 @@ static void handle_static_file_request(struct mg_connection *conn, const char *p
 
     if (!mg_fopen(conn, path, "rb", filep)) {
         send_http_error(conn, 500, NULL,
-                        "fopen(%s): %s", path, strerror(ERRNO));
+            "Error: Cannot open file\nfopen(%s): %s",
+            path, strerror(ERRNO));
         return;
     }
 
@@ -4094,7 +4097,8 @@ static void handle_static_file_request(struct mg_connection *conn, const char *p
         /* actually, range requests don't play well with a pre-gzipped
            file (since the range is specified in the uncompressed space) */
         if (filep->gzipped) {
-            send_http_error(conn, 501, NULL, "range requests in gzipped files are not supported");
+            send_http_error(conn, 501, NULL, "%s",
+                "Error: Range requests in gzipped files are not supported");
             mg_fclose(filep);
             return;
         }
@@ -4155,14 +4159,15 @@ void mg_send_file2(struct mg_connection *conn, const char *path, int timeout)
             if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) {
                 handle_directory_request(conn, path);
             } else {
-                send_http_error(conn, 403, "Directory Listing Denied",
-                    "Directory listing denied");
+                send_http_error(conn, 403, NULL, "%s",
+                    "Error: Directory listing denied");
             }
         } else {
             handle_static_file_request(conn, path, &file);
         }
     } else {
-        send_http_error(conn, 404, NULL, "%s", "File not found");
+        send_http_error(conn, 404, NULL, "%s",
+            "Error: File not found");
     }
 }
 
@@ -4336,12 +4341,19 @@ static int forward_body_data(struct mg_connection *conn, FILE *fp,
     assert(fp != NULL);
 
     if (conn->content_len == -1) {
-        send_http_error(conn, 411, NULL, "%s", "");
-    } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
-        send_http_error(conn, 417, NULL, "%s", "");
+        /* Content length is not specified by the client. */
+        send_http_error(conn, 411, NULL, "%s",
+            "Error: Client did not specify content length");
+    } else if ((expect != NULL) && (mg_strcasecmp(expect, "100-continue") != 0)) {
+        /* Client sent an "Expect: xyz" header and xyz is not 100-continue. */
+        send_http_error(conn, 417, NULL,
+            "Error: Can not fulfill expectation %s", expect);
     } else {
         if (expect != NULL) {
             (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
+            conn->status_code = 100;
+        } else {
+            conn->status_code = 200;
         }
 
         buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len - conn->consumed_content;
@@ -4376,6 +4388,7 @@ static int forward_body_data(struct mg_connection *conn, FILE *fp,
 
         /* Each error code path in this function must send an error */
         if (!success) {
+            /* TODO: Maybe some data has already been sent. */
             send_http_error(conn, 500, NULL, "%s", "");
         }
     }
@@ -4589,14 +4602,14 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog)
 
     if (pipe(fdin) != 0 || pipe(fdout) != 0) {
         send_http_error(conn, 500, NULL,
-                        "Cannot create CGI pipe: %s", strerror(ERRNO));
+            "Error: Cannot create CGI pipe: %s", strerror(ERRNO));
         goto done;
     }
 
     pid = spawn_process(conn, p, blk.buf, blk.vars, fdin[0], fdout[1], dir);
     if (pid == (pid_t) -1) {
         send_http_error(conn, 500, NULL,
-                        "Cannot spawn CGI process [%s]: %s", prog, strerror(ERRNO));
+            "Error: Cannot spawn CGI process [%s]: %s", prog, strerror(ERRNO));
         goto done;
     }
 
@@ -4614,11 +4627,14 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog)
     (void) close(fdout[1]);
     fdin[0] = fdout[1] = -1;
 
-
-    if ((in = fdopen(fdin[1], "wb")) == NULL ||
-        (out = fdopen(fdout[0], "rb")) == NULL) {
+    if ((in = fdopen(fdin[1], "wb")) == NULL) {
+        send_http_error(conn, 500, NULL,
+            "Error: CGI can not open fdin\nfopen: %s", strerror(ERRNO));
+        goto done;
+    }
+    if ((out = fdopen(fdout[0], "rb")) == NULL) {
         send_http_error(conn, 500, NULL,
-                        "fopen: %s", strerror(ERRNO));
+            "Error: CGI can not open fdout\nfopen: %s", strerror(ERRNO));
         goto done;
     }
 
@@ -4645,16 +4661,15 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog)
     buf = (char *)mg_malloc(buflen);
     if (buf == NULL) {
         send_http_error(conn, 500, NULL,
-                        "Not enough memory for buffer (%u bytes)",
-                        (unsigned int) buflen);
+            "Error: Not enough memory for CGI buffer (%u bytes)",
+            (unsigned int) buflen);
         goto done;
     }
     headers_len = read_request(out, conn, buf, (int) buflen, &data_len);
     if (headers_len <= 0) {
         send_http_error(conn, 500, NULL,
-                        "CGI program sent malformed or too big (>%u bytes) "
-                        "HTTP headers: [%.*s]",
-                        (unsigned) buflen, data_len, buf);
+            "Error: CGI program sent malformed or too big (>%u bytes) HTTP headers: [%.*s]",
+            (unsigned) buflen, data_len, buf);
         goto done;
     }
     pbuf = buf;
@@ -4730,9 +4745,12 @@ done:
 }
 #endif /* !NO_CGI */
 
-/* For a given PUT path, create all intermediate subdirectories
-   for given path. Return 0 if the path itself is a directory,
-   or -1 on error, 1 if OK. */
+/* For a given PUT path, create all intermediate subdirectories.
+   Return  0  if the path itself is a directory.
+   Return  1  if the path leads to a file.
+   Return -1  for if the path is too long.
+   Return -2  if path can not be created.
+*/
 static int put_dir(struct mg_connection *conn, const char *path)
 {
     char buf[PATH_MAX];
@@ -4743,6 +4761,7 @@ static int put_dir(struct mg_connection *conn, const char *path)
     for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
         len = (int)(p - path);
         if (len >= (int) sizeof(buf)) {
+            /* path too long */
             res = -1;
             break;
         }
@@ -4752,7 +4771,8 @@ static int put_dir(struct mg_connection *conn, const char *path)
         /* Try to create intermediate directory */
         DEBUG_TRACE("mkdir(%s)", buf);
         if (!mg_stat(conn, buf, &file) && mg_mkdir(buf, 0755) != 0) {
-            res = -1;
+            /* path does not exixt and can not be created */
+            res = -2;
             break;
         }
 
@@ -4772,6 +4792,8 @@ static void mkcol(struct mg_connection *conn, const char *path)
     char date[64];
     time_t curtime = time(NULL);
 
+    /* TODO: Check the send_http_error situations in this function */
+
     memset(&de.file, 0, sizeof(de.file));
     if (!mg_stat(conn, path, &de.file)) {
         mg_cry(conn, "%s: mg_stat(%s) failed: %s",
@@ -4780,14 +4802,14 @@ static void mkcol(struct mg_connection *conn, const char *path)
 
     if (de.file.modification_time) {
         send_http_error(conn, 405, NULL,
-                        "mkcol(%s): %s", path, strerror(ERRNO));
+                        "Error: mkcol(%s): %s", path, strerror(ERRNO));
         return;
     }
 
     body_len = conn->data_len - conn->request_len;
     if (body_len > 0) {
         send_http_error(conn, 415, NULL,
-                        "mkcol(%s): %s", path, strerror(ERRNO));
+                        "Error: mkcol(%s): %s", path, strerror(ERRNO));
         return;
     }
 
@@ -4801,13 +4823,13 @@ static void mkcol(struct mg_connection *conn, const char *path)
     } else if (rc == -1) {
         if (errno == EEXIST)
             send_http_error(conn, 405, NULL,
-                            "mkcol(%s): %s", path, strerror(ERRNO));
+                            "Error:mkcol(%s): %s", path, strerror(ERRNO));
         else if (errno == EACCES)
             send_http_error(conn, 403, NULL,
-                            "mkcol(%s): %s", path, strerror(ERRNO));
+                            "Error: mkcol(%s): %s", path, strerror(ERRNO));
         else if(errno == ENOENT)
             send_http_error(conn, 409, NULL,
-                            "mkcol(%s): %s", path, strerror(ERRNO));
+                            "Error: mkcol(%s): %s", path, strerror(ERRNO));
         else
             send_http_error(conn, 500, NULL,
                             "fopen(%s): %s", path, strerror(ERRNO));
@@ -4824,58 +4846,101 @@ static void put_file(struct mg_connection *conn, const char *path)
     time_t curtime = time(NULL);
 
     conn->status_code = mg_stat(conn, path, &file) ? 200 : 201;
+    rc = put_dir(conn, path);
 
-    if ((rc = put_dir(conn, path)) == 0) {
+    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));
-    } else if (rc == -1) {
+
+        /* Request to create a directory has been fulfilled successfully.
+           No need to put a file. */
+        return;
+    }
+
+    if (rc == -1) {
+        /* put_dir returns -1 if the path is too long */
+        send_http_error(conn, 414, NULL,
+            "Error: Path too long\nput_dir(%s): %s", path, strerror(ERRNO));
+        return;
+    }
+
+    if (rc == -2) {
+        /* put_dir returns -2 if the directory can not be created */
         send_http_error(conn, 500, NULL,
-                        "put_dir(%s): %s", path, strerror(ERRNO));
-    } else if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
+            "Error: Can not create directory\nput_dir(%s): %s", path, strerror(ERRNO));
+        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);
         send_http_error(conn, 500, NULL,
-                        "fopen(%s): %s", path, strerror(ERRNO));
-    } else {
-        fclose_on_exec(&file, conn);
-        range = mg_get_header(conn, "Content-Range");
-        r1 = r2 = 0;
-        if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
-            conn->status_code = 206;
-            fseeko(file.fp, r1, SEEK_SET);
-        }
-        if (!forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) {
-            conn->status_code = 500;
-        }
-        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_fclose(&file);
+            "Error: Can not create file\nfopen(%s): %s", path, strerror(ERRNO));
+        return;
+    }
+
+    fclose_on_exec(&file, conn);
+    range = mg_get_header(conn, "Content-Range");
+    r1 = r2 = 0;
+    if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
+        conn->status_code = 206; /* Partial content */
+        fseeko(file.fp, r1, SEEK_SET);
     }
+
+    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. */
+        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)
+              );
+    mg_fclose(&file);
 }
 
 static void delete_file(struct mg_connection *conn, const char *path)
 {
     struct de de;
     memset(&de.file, 0, sizeof(de.file));
-    if(!mg_stat(conn, path, &de.file)) {
-        send_http_error(conn, 404, NULL, "%s", "File not found");
+    if (!mg_stat(conn, path, &de.file)) {
+        /* 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.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 {
-                send_http_error(conn, 423, NULL, "remove(%s): %s", path,
-                    strerror(ERRNO));
+                /* Delete not successful (file locked). */
+                send_http_error(conn, 423, NULL,
+                    "Error: Cannot delete file\nremove(%s): %s", path, strerror(ERRNO));
             }
         } else {
-            send_http_error(conn, 500, NULL, "remove(%s): %s", path,
-                strerror(ERRNO));
+            /* 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);
         }
     }
+
+    /* TODO: put and delete should value the read only flag of files and return 403 */
 }
 
 static void send_ssi_file(struct mg_connection *, const char *,
@@ -5027,9 +5092,8 @@ static void send_ssi_file(struct mg_connection *conn, const char *path,
 }
 
 static void handle_ssi_file_request(struct mg_connection *conn,
-                                    const char *path)
+                                    const char *path, struct file *filep)
 {
-    struct file file = STRUCT_FILE_INITIALIZER;
     char date[64];
     time_t curtime = time(NULL);
     const char *cors1, *cors2, *cors3;
@@ -5043,13 +5107,15 @@ static void handle_ssi_file_request(struct mg_connection *conn,
         cors1 = cors2 = cors3 = "";
     }
 
-    if (!mg_fopen(conn, path, "rb", &file)) {
-        send_http_error(conn, 500, NULL, "fopen(%s): %s", path,
-                        strerror(ERRNO));
+    if (!mg_fopen(conn, path, "rb", filep)) {
+        /* File exists (precondition for calling this function),
+           but can not be opened by the server. */
+        send_http_error(conn, 500, NULL,
+            "Error: Cannot read file\nfopen(%s): %s", path, strerror(ERRNO));
     } else {
         conn->must_close = 1;
         gmt_time_string(date, sizeof(date), &curtime);
-        fclose_on_exec(&file, conn);
+        fclose_on_exec(filep, conn);
         mg_printf(conn, "HTTP/1.1 200 OK\r\n"
                         "%s%s%s"
                         "Date: %s\r\n"
@@ -5057,8 +5123,8 @@ static void handle_ssi_file_request(struct mg_connection *conn,
                         "Connection: %s\r\n\r\n",
                         cors1, cors2, cors3,
                         date, suggest_connection_header(conn));
-        send_ssi_file(conn, path, &file, 0);
-        mg_fclose(&file);
+        send_ssi_file(conn, path, filep, 0);
+        mg_fclose(filep);
     }
 }
 
@@ -5596,7 +5662,7 @@ static void handle_websocket_request(struct mg_connection *conn, const char *pat
 #endif
 
     if (version == NULL || strcmp(version, "13") != 0) {
-        send_http_error(conn, 426, "Upgrade Required", "%s", "Upgrade Required");
+        send_http_error(conn, 426, NULL, "%s", "Protocol upgrade required");
     } else if (conn->ctx->callbacks.websocket_connect != NULL &&
                conn->ctx->callbacks.websocket_connect(conn) != 0) {
         /* C callback has returned non-zero, do not proceed with handshake. */
@@ -6036,7 +6102,10 @@ static void handle_request(struct mg_connection *conn)
         if (ssl_index >= 0) {
             redirect_to_https_port(conn, ssl_index);
         } else {
-            send_http_error(conn, 500, NULL, "%s", "SSL forward not configured properly");
+            /* A http to https forward port has been specified,
+               but no https port to forward to. */
+            send_http_error(conn, 503, NULL, "%s",
+                "Error: SSL forward not configured properly");
             mg_cry(conn, "Can not redirect to SSL, no SSL port available");
         }
         return;
@@ -6081,8 +6150,10 @@ static void handle_request(struct mg_connection *conn)
 #else
         if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
 #endif
-            /* no real files -> no PUT/DELETE */
-            send_http_error(conn, 405, NULL, "%s", "Method Not Allowed");
+            /* This server does not have any real files, thus the
+               PUT/DELETE methods are not valid. */
+            send_http_error(conn, 405, NULL,
+                "%s method not allowed", conn->request_info.request_method);
             return;
         }
 
@@ -6121,13 +6192,13 @@ static void handle_request(struct mg_connection *conn)
 #if defined(NO_FILES)
     /* 9a. In case the server uses only callbacks, this uri is unknown.
        Then, all request handling ends here. */
-    send_http_error(conn, 404, NULL, "Not Found");
+    send_http_error(conn, 404, NULL, "%s", "Not Found");
 
 #else
     /* 9b. This request is either for a static file or resource handled
        by a script file. Thus, a DOCUMENT_ROOT must exist. */
     if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
-        send_http_error(conn, 404, NULL, "Not Found");
+        send_http_error(conn, 404, NULL, "%s", "Not Found");
         return;
     }
 
@@ -6155,14 +6226,15 @@ static void handle_request(struct mg_connection *conn)
             return;
         }
         /* 11.4. should never reach this point */
-        send_http_error(conn, 405, NULL, "%s", "Method Not Allowed");
+        send_http_error(conn, 405, NULL,
+            "%s method not allowed", conn->request_info.request_method);
         return;
     }
 
     /* 11. File does not exist, or it was configured that it should be hidden */
     if (((file.membuf == NULL) && (file.modification_time == (time_t) 0)) ||
         (must_hide_file(conn, path))) {
-        send_http_error(conn, 404, NULL, "%s", "File not found");
+        send_http_error(conn, 404, NULL, "%s", "Not found");
         return;
     }
 
@@ -6195,7 +6267,8 @@ static void handle_request(struct mg_connection *conn)
     /* 13.3. everything but GET and HEAD (e.g. POST) */
     if (!strcmp(ri->request_method, "GET") &&
         !strcmp(ri->request_method, "HEAD")) {
-        send_http_error(conn, 405, NULL, "%s", "Method Not Allowed");
+        send_http_error(conn, 405, NULL,
+            "%s method not allowed", conn->request_info.request_method);
         return;
     }
 
@@ -6210,8 +6283,8 @@ static void handle_request(struct mg_connection *conn)
             if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) {
                 handle_directory_request(conn, path);
             } else {
-                send_http_error(conn, 403, "Directory Listing Denied",
-                                "%s", "Directory listing denied");
+                send_http_error(conn, 403, NULL, "%s",
+                    "Error: Directory listing denied");
             }
             return;
         }
@@ -6252,8 +6325,9 @@ static void handle_file_based_request(struct mg_connection *conn, const char *pa
     } else if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
                             (int)strlen(conn->ctx->config[SSI_EXTENSIONS]),
                             path) > 0) {
-        handle_ssi_file_request(conn, path);
+        handle_ssi_file_request(conn, path, file);
     } else if ((!conn->in_error_handler) && is_not_modified(conn, file)) {
+        /* Send 304 "Not Modified" - this must not send any body data */
         send_http_error(conn, 304, NULL, "%s", "");
     } else {
         handle_static_file_request(conn, path, file);
@@ -7085,7 +7159,10 @@ static void process_new_connection(struct mg_connection *conn)
     conn->data_len = 0;
     do {
         if (!getreq(conn, ebuf, sizeof(ebuf), TIMEOUT_INFINITE)) {
-            send_http_error(conn, 500, NULL, "%s", ebuf);
+            /* The request sent by the client could not be understood by the server,
+               or it was incomplete or a timeout. Send an error message and close
+               the connection. */
+            send_http_error(conn, 400, NULL, "%s", ebuf);
             conn->must_close = 1;
         } else if (!is_valid_uri(conn->request_info.uri)) {
             snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri);

+ 16 - 22
src/mod_lua.inl

@@ -1161,25 +1161,6 @@ void mg_exec_lua_script(struct mg_connection *conn, const char *path,
     }
 }
 
-static void lsp_send_err(struct mg_connection *conn, struct lua_State *L,
-    const char *fmt, ...)
-{
-    char buf[MG_BUF_LEN];
-    va_list ap;
-    int len;
-
-    va_start(ap, fmt);
-    len = vsnprintf(buf, sizeof(buf), fmt, ap);
-    va_end(ap);
-
-    if (L == NULL) {
-        send_http_error(conn, 500, NULL, "%s", buf);
-    } else {
-        lua_pushstring(L, buf);
-        lua_error(L);
-    }
-}
-
 static int handle_lsp_request(struct mg_connection *conn, const char *path, struct file *filep, struct lua_State *ls)
 {
     void *p = NULL;
@@ -1191,14 +1172,27 @@ static int handle_lsp_request(struct mg_connection *conn, const char *path, stru
 
     /* We need both mg_stat to get file size, and mg_fopen to get fd */
     if (!mg_stat(conn, path, filep) || !mg_fopen(conn, path, "r", filep)) {
-        lsp_send_err(conn, ls, "File [%s] not found", path);
+        /* File not found or not accessible */
+        if (ls == NULL) {
+            send_http_error(conn, 500, NULL,
+                "Error: Cannot open script\nFile %s can not be read", path);
+        } else {
+            luaL_error(ls, "File [%s] not found", path);
+        }
     } else if (filep->membuf == NULL &&
         (p = mmap(NULL, (size_t) filep->size, PROT_READ, MAP_PRIVATE,
         fileno(filep->fp), 0)) == MAP_FAILED) {
-            lsp_send_err(conn, ls, "mmap(%s, %zu, %d): %s", path, (size_t) filep->size,
+        /* mmap failed */
+        if (ls == NULL) {
+            send_http_error(conn, 500, NULL,
+                "Error: Cannot open script\nFile %s can not be mapped", path);
+        } else {
+            luaL_error(ls, "mmap(%s, %zu, %d): %s", path, (size_t) filep->size,
                 fileno(filep->fp), strerror(errno));
+        }
     } else if ((L = (ls != NULL ? ls : lua_newstate(lua_allocator, NULL))) == NULL) {
-        send_http_error(conn, 500, NULL, "%s", "luaL_newstate failed");
+        send_http_error(conn, 500, NULL, "%s",
+            "Error: Cannot execute script\nlua_newstate failed");
     } else {
         /* We're not sending HTTP headers here, Lua page must do it. */
         if (ls == NULL) {