Browse Source

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

bel 10 years ago
parent
commit
f59d79598f
2 changed files with 129 additions and 41 deletions
  1. 127 39
      src/civetweb.c
  2. 2 2
      src/mod_lua.inl

+ 127 - 39
src/civetweb.c

@@ -551,8 +551,6 @@ typedef int socklen_t;
 #define MGSQLEN 20
 #endif
 
-static const char *http_500_error = "Internal Server Error";
-
 #if defined(NO_SSL_DL)
 #include <openssl/ssl.h>
 #include <openssl/err.h>
@@ -1449,6 +1447,92 @@ static const char *suggest_connection_header(const struct mg_connection *conn)
 static void handle_file_based_request(struct mg_connection *conn, const char *path, struct file *filep);
 static int mg_stat(struct mg_connection *conn, const char *path, struct file *filep);
 
+static const char *mg_get_response_code_text(int response_code)
+{
+    switch (response_code)
+    {
+    case 100: return "Continue"; // RFC2616 Section 10.1.1
+    case 101: return "Switching Protocols"; // RFC2616 Section 10.1.2
+    case 102: return "Processing"; // RFC2518 Section 10.1
+    case 200: return "OK"; // RFC2616 Section 10.2.1
+    case 201: return "Created"; // RFC2616 Section 10.2.2
+    case 202: return "Accepted"; // RFC2616 Section 10.2.3
+    case 203: return "Non-Authoritative Information"; // RFC2616 Section 10.2.4
+    case 204: return "No Content"; // RFC2616 Section 10.2.5
+    case 205: return "Reset Content"; // RFC2616 Section 10.2.6
+    case 206: return "Partial Content"; // RFC2616 Section 10.2.7
+    case 207: return "Multi-Status"; // RFC2518 Section 10.2, RFC4918 Section 11.1
+    case 208: return "Already Reported"; // RFC5842 Section 7.1
+    case 300: return "Multiple Choices"; // RFC2616 Section 10.3.1
+    case 301: return "Moved Permanently"; // RFC2616 Section 10.3.2
+    case 302: return "Found"; // RFC2616 Section 10.3.3
+    case 303: return "See Other"; // RFC2616 Section 10.3.4
+    case 304: return "Not Modified"; // RFC2616 Section 10.3.5
+    case 305: return "Use Proxy"; // RFC2616 Section 10.3.6
+    case 307: return "Temporary Redirect"; // RFC2616 Section 10.3.8
+    case 400: return "Bad Request"; // RFC2616 Section 10.4.1
+    case 401: return "Unauthorized"; // RFC2616 Section 10.4.2
+    case 402: return "Payment Required"; // RFC2616 Section 10.4.3
+    case 403: return "Forbidden"; // RFC2616 Section 10.4.4
+    case 404: return "Not Found"; // RFC2616 Section 10.4.5
+    case 405: return "Method Not Allowed"; // RFC2616 Section 10.4.6
+    case 406: return "Not Acceptable"; // RFC2616 Section 10.4.7
+    case 407: return "Proxy Authentication Required"; // RFC2616 Section 10.4.8
+    case 408: return "Request Time-out"; // RFC2616 Section 10.4.9
+    case 409: return "Conflict"; // RFC2616 Section 10.4.10
+    case 410: return "Gone"; // RFC2616 Section 10.4.11
+    case 411: return "Length Required"; // RFC2616 Section 10.4.12
+    case 412: return "Precondition Failed"; // RFC2616 Section 10.4.13
+    case 413: return "Request Entity Too Large"; // RFC2616 Section 10.4.14
+    case 414: return "Request-URI Too Large"; // RFC2616 Section 10.4.15
+    case 415: return "Unsupported Media Type"; // RFC2616 Section 10.4.16
+    case 416: return "Requested range not satisfiable"; // RFC2616 Section 10.4.17
+    case 417: return "Expectation Failed"; // RFC2616 Section 10.4.18
+    case 422: return "Unproccessable entity"; // RFC2518 Section 10.3, RFC4918 Section 11.2
+    case 423: return "Locked"; // RFC2518 Section 10.4, RFC4918 Section 11.3
+    case 424: return "Failed Dependency"; // RFC2518 Section 10.5, RFC4918 Section 11.4
+    case 500: return "Internal Server Error"; // RFC2616 Section 10.5.1
+    case 501: return "Not Implemented"; // RFC2616 Section 10.5.2
+    case 502: return "Bad Gateway"; // RFC2616 Section 10.5.3
+    case 503: return "Service Unavailable"; // RFC2616 Section 10.5.4
+    case 504: return "Gateway Time-out"; // RFC2616 Section 10.5.5
+    case 505: return "HTTP Version not supported"; // RFC2616 Section 10.5.6
+    case 507: return "Insufficient Storage"; // RFC2518 Section 10.6, , RFC4918 Section 11.5
+
+    /*
+    case 226: return "IM used"; // RFC3229 Section 10.4.1
+    case 308: return "Permanent Redirect"; // RFC7238 Section 3
+    case 418: return "I am a teapot"; // RFC2324 Section 2.3.2
+
+    case 419: return "Authentication Timeout"; // common use, no RFC
+
+    case 420: return "Method Failure"; // ??
+    case 425: return "Node code"; // ??
+    case 426: return "Upgrade Required"; // ??
+
+    case 428: return "Precondition Required"; // RFC 6585 ??
+    case 429: return "Too Many Requests"; // RFC 6585 ??
+    case 431: return "Request Header Fields Too Large"; // RFC 6585 ??
+
+    case 440: return "Login Timeout"; // ??
+    case 444: return "No Response"; // ??
+    case 449: return "Retry With"; // ??
+    case 450: return "Blocked by Windows Parental Controls"; // ??
+
+    case 451: return "Unavailable For Legal Reasons"; // Internet draft ??
+
+    case 506: return "Variant Also Negotiates"; // RFC 2295
+    case 508: return "Loop Detected"; // RFC 5842
+
+    case 510: return "Not Extended"; // RFC 2774
+    case 511: return "Network Authentication Required"; // RFC 6585
+    */
+
+    default: return "";
+    }
+}
+
+
 static void send_http_error(struct mg_connection *, int, const char *,
                             PRINTF_FORMAT_STRING(const char *fmt), ...)
 PRINTF_ARGS(4, 5);
@@ -1466,6 +1550,10 @@ static void send_http_error(struct mg_connection *conn, int status,
     struct file error_page_file = STRUCT_FILE_INITIALIZER;
     const char *error_page_file_ext, *tstr;
 
+    if (!reason) {
+        reason = mg_get_response_code_text(status);
+    }
+
     conn->status_code = status;
     if (conn->in_error_handler ||
         conn->ctx->callbacks.http_error == NULL ||
@@ -2229,7 +2317,7 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog,
 
     if ((pid = fork()) == -1) {
         /* Parent */
-        send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO));
+        send_http_error(conn, 500, NULL, "fork(): %s", strerror(ERRNO));
     } else if (pid == 0) {
         /* Child */
         if (chdir(dir) != 0) {
@@ -3958,7 +4046,7 @@ 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, http_500_error,
+        send_http_error(conn, 500, NULL,
                         "fopen(%s): %s", path, strerror(ERRNO));
         return;
     }
@@ -3973,7 +4061,7 @@ 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, "Not Implemented", "range requests in gzipped files are not supported");
+            send_http_error(conn, 501, NULL, "range requests in gzipped files are not supported");
             mg_fclose(filep);
             return;
         }
@@ -4041,7 +4129,7 @@ void mg_send_file2(struct mg_connection *conn, const char *path, int timeout)
             handle_static_file_request(conn, path, &file);
         }
     } else {
-        send_http_error(conn, 404, "Not Found", "%s", "File not found");
+        send_http_error(conn, 404, NULL, "%s", "File not found");
     }
 }
 
@@ -4215,9 +4303,9 @@ static int forward_body_data(struct mg_connection *conn, FILE *fp,
     assert(fp != NULL);
 
     if (conn->content_len == -1) {
-        send_http_error(conn, 411, "Length Required", "%s", "");
+        send_http_error(conn, 411, NULL, "%s", "");
     } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
-        send_http_error(conn, 417, "Expectation Failed", "%s", "");
+        send_http_error(conn, 417, NULL, "%s", "");
     } else {
         if (expect != NULL) {
             (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
@@ -4255,7 +4343,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) {
-            send_http_error(conn, 577, http_500_error, "%s", "");
+            send_http_error(conn, 500, NULL, "%s", "");
         }
     }
 
@@ -4467,14 +4555,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, http_500_error,
+        send_http_error(conn, 500, NULL,
                         "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, http_500_error,
+        send_http_error(conn, 500, NULL,
                         "Cannot spawn CGI process [%s]: %s", prog, strerror(ERRNO));
         goto done;
     }
@@ -4496,7 +4584,7 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog)
 
     if ((in = fdopen(fdin[1], "wb")) == NULL ||
         (out = fdopen(fdout[0], "rb")) == NULL) {
-        send_http_error(conn, 500, http_500_error,
+        send_http_error(conn, 500, NULL,
                         "fopen: %s", strerror(ERRNO));
         goto done;
     }
@@ -4523,14 +4611,14 @@ static void handle_cgi_request(struct mg_connection *conn, const char *prog)
     data_len = 0;
     buf = (char *)mg_malloc(buflen);
     if (buf == NULL) {
-        send_http_error(conn, 500, http_500_error,
+        send_http_error(conn, 500, NULL,
                         "Not enough memory for 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, http_500_error,
+        send_http_error(conn, 500, NULL,
                         "CGI program sent malformed or too big (>%u bytes) "
                         "HTTP headers: [%.*s]",
                         (unsigned) buflen, data_len, buf);
@@ -4658,14 +4746,14 @@ static void mkcol(struct mg_connection *conn, const char *path)
     }
 
     if (de.file.modification_time) {
-        send_http_error(conn, 405, "Method Not Allowed",
+        send_http_error(conn, 405, NULL,
                         "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",
+        send_http_error(conn, 415, NULL,
                         "mkcol(%s): %s", path, strerror(ERRNO));
         return;
     }
@@ -4679,16 +4767,16 @@ static void mkcol(struct mg_connection *conn, const char *path)
                   conn->status_code, date, suggest_connection_header(conn));
     } else if (rc == -1) {
         if (errno == EEXIST)
-            send_http_error(conn, 405, "Method Not Allowed",
+            send_http_error(conn, 405, NULL,
                             "mkcol(%s): %s", path, strerror(ERRNO));
         else if (errno == EACCES)
-            send_http_error(conn, 403, "Forbidden",
+            send_http_error(conn, 403, NULL,
                             "mkcol(%s): %s", path, strerror(ERRNO));
         else if(errno == ENOENT)
-            send_http_error(conn, 409, "Conflict",
+            send_http_error(conn, 409, NULL,
                             "mkcol(%s): %s", path, strerror(ERRNO));
         else
-            send_http_error(conn, 500, http_500_error,
+            send_http_error(conn, 500, NULL,
                             "fopen(%s): %s", path, strerror(ERRNO));
     }
 }
@@ -4709,11 +4797,11 @@ static void put_file(struct mg_connection *conn, const char *path)
         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) {
-        send_http_error(conn, 500, http_500_error,
+        send_http_error(conn, 500, NULL,
                         "put_dir(%s): %s", path, strerror(ERRNO));
     } else if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
         mg_fclose(&file);
-        send_http_error(conn, 500, http_500_error,
+        send_http_error(conn, 500, NULL,
                         "fopen(%s): %s", path, strerror(ERRNO));
     } else {
         fclose_on_exec(&file, conn);
@@ -4738,20 +4826,20 @@ 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, "Not Found", "%s", "File not found");
+        send_http_error(conn, 404, NULL, "%s", "File not found");
     } else {
         if(de.file.modification_time) {
             if(de.file.is_directory) {
                 remove_directory(conn, path);
-                send_http_error(conn, 204, "No Content", "%s", "");
+                send_http_error(conn, 204, NULL, "%s", "");
             } else if (mg_remove(path) == 0) {
-                send_http_error(conn, 204, "No Content", "%s", "");
+                send_http_error(conn, 204, NULL, "%s", "");
             } else {
-                send_http_error(conn, 423, "Locked", "remove(%s): %s", path,
+                send_http_error(conn, 423, NULL, "remove(%s): %s", path,
                     strerror(ERRNO));
             }
         } else {
-            send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
+            send_http_error(conn, 500, NULL, "remove(%s): %s", path,
                 strerror(ERRNO));
         }
     }
@@ -4923,7 +5011,7 @@ static void handle_ssi_file_request(struct mg_connection *conn,
     }
 
     if (!mg_fopen(conn, path, "rb", &file)) {
-        send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path,
+        send_http_error(conn, 500, NULL, "fopen(%s): %s", path,
                         strerror(ERRNO));
     } else {
         conn->must_close = 1;
@@ -5915,7 +6003,7 @@ 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, "Internal Server Error", "%s", "SSL forward not configured properly");
+            send_http_error(conn, 500, NULL, "%s", "SSL forward not configured properly");
             mg_cry(conn, "Can not redirect to SSL, no SSL port available");
         }
         return;
@@ -5961,7 +6049,7 @@ static void handle_request(struct mg_connection *conn)
         if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
 #endif
             /* no real files -> no PUT/DELETE */
-            send_http_error(conn, 405, "Method Not Allowed", "%s", "Method Not Allowed");
+            send_http_error(conn, 405, NULL, "%s", "Method Not Allowed");
             return;
         }
 
@@ -6000,13 +6088,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, "Not Found", "Not Found");
+    send_http_error(conn, 404, NULL, "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, "Not Found", "Not Found");
+        send_http_error(conn, 404, NULL, "Not Found");
         return;
     }
 
@@ -6034,14 +6122,14 @@ static void handle_request(struct mg_connection *conn)
             return;
         }
         /* 11.4. should never reach this point */
-        send_http_error(conn, 405, "Method Not Allowed", "%s", "Method Not Allowed");
+        send_http_error(conn, 405, NULL, "%s", "Method Not Allowed");
         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, "Not Found", "%s", "File not found");
+        send_http_error(conn, 404, NULL, "%s", "File not found");
         return;
     }
 
@@ -6074,7 +6162,7 @@ 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, "Method Not Allowed", "%s", "Method Not Allowed");
+        send_http_error(conn, 405, NULL, "%s", "Method Not Allowed");
         return;
     }
 
@@ -6133,7 +6221,7 @@ static void handle_file_based_request(struct mg_connection *conn, const char *pa
                             path) > 0) {
         handle_ssi_file_request(conn, path);
     } else if ((!conn->in_error_handler) && is_not_modified(conn, file)) {
-        send_http_error(conn, 304, "Not Modified", "%s", "");
+        send_http_error(conn, 304, NULL, "%s", "");
     } else {
         handle_static_file_request(conn, path, file);
     }
@@ -6964,15 +7052,15 @@ 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, "Server Error", "%s", ebuf);
+            send_http_error(conn, 500, 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);
-            send_http_error(conn, 400, "Bad Request", "%s", ebuf);
+            send_http_error(conn, 400, NULL, "%s", ebuf);
         } else if (strcmp(ri->http_version, "1.0") &&
                    strcmp(ri->http_version, "1.1")) {
             snprintf(ebuf, sizeof(ebuf), "Bad HTTP version: [%s]", ri->http_version);
-            send_http_error(conn, 505, "Bad HTTP version", "%s", ebuf);
+            send_http_error(conn, 505, NULL, "%s", ebuf);
         }
 
         if (ebuf[0] == '\0') {

+ 2 - 2
src/mod_lua.inl

@@ -1149,7 +1149,7 @@ static void lsp_send_err(struct mg_connection *conn, struct lua_State *L,
     va_end(ap);
 
     if (L == NULL) {
-        send_http_error(conn, 500, http_500_error, "%s", buf);
+        send_http_error(conn, 500, NULL, "%s", buf);
     } else {
         lua_pushstring(L, buf);
         lua_error(L);
@@ -1174,7 +1174,7 @@ static int handle_lsp_request(struct mg_connection *conn, const char *path, stru
             lsp_send_err(conn, 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, http_500_error, "%s", "luaL_newstate failed");
+        send_http_error(conn, 500, NULL, "%s", "luaL_newstate failed");
     } else {
         /* We're not sending HTTP headers here, Lua page must do it. */
         if (ls == NULL) {