]> git.seodisparate.com - c_simple_http/commitdiff
Add support for different error responses
authorStephen Seo <seo.disparate@gmail.com>
Fri, 6 Sep 2024 06:55:21 +0000 (15:55 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Fri, 6 Sep 2024 06:55:21 +0000 (15:55 +0900)
example_config/example.config
src/http.c
src/http.h
src/main.c

index 61f1dd791738ced6f56d65a4e689e28f45f64078..77b8d1736b28e050c8f41d885698b6f9b535399c 100644 (file)
@@ -36,3 +36,5 @@ Var='''Test var value'''
 PATH=/inner
 HTML_FILE='''example_config/inner.html'''
 VAR_FILE='''example_config/var.html'''
+
+PATH=/error
index c2b3770afff80f14ce3ce5407533523dc5dae3ea..e2e39e42263e7e1327e8400ea1bcd6f4508585b6 100644 (file)
 #define REQUEST_PATH_BUFFER_SIZE 256
 #define REQUEST_PROTO_BUFFER_SIZE 16
 
+const char *c_simple_http_response_code_error_to_response(
+    enum C_SIMPLE_HTTP_ResponseCode response_code) {
+  switch (response_code) {
+    case C_SIMPLE_HTTP_Response_400_Bad_Request:
+      return "HTTP/1.1 400 Bad Request\nAllow: GET\nContent-Type: text/html\n"
+             "Content-Length: 25\n\n"
+             "<h1>400 Bad Request</h1>\n";
+    case C_SIMPLE_HTTP_Response_404_Not_Found:
+      return "HTTP/1.1 404 Not Found\nAllow: GET\nContent-Type: text/html\n"
+             "Content-Length: 23\n\n"
+             "<h1>404 Not Found</h1>\n";
+    case C_SIMPLE_HTTP_Response_500_Internal_Server_Error:
+    default:
+      return "HTTP/1.1 500 Internal Server Error\nAllow: GET\n"
+             "Content-Type: text/html\n"
+             "Content-Length: 35\n\n"
+             "<h1>500 Internal Server Error</h1>\n";
+  }
+}
+
 char *c_simple_http_request_response(
     const char *request,
     unsigned int size,
     const C_SIMPLE_HTTP_HTTPTemplates *templates,
-    size_t *out_size) {
+    size_t *out_size,
+    enum C_SIMPLE_HTTP_ResponseCode *out_response_code) {
   if (out_size) {
     *out_size = 0;
   }
@@ -54,6 +75,9 @@ char *c_simple_http_request_response(
     request_type[request_type_idx++] = request[idx];
   }
   if (request_type_idx == 0) {
+    if (out_response_code) {
+      *out_response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
+    }
     return NULL;
   }
 #ifndef NDEBUG
@@ -79,6 +103,9 @@ char *c_simple_http_request_response(
     request_path[request_path_idx++] = request[idx];
   }
   if (request_path_idx == 0) {
+    if (out_response_code) {
+      *out_response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
+    }
     return NULL;
   }
 #ifndef NDEBUG
@@ -104,6 +131,9 @@ char *c_simple_http_request_response(
     request_proto[request_proto_idx++] = request[idx];
   }
   if (request_proto_idx == 0) {
+    if (out_response_code) {
+      *out_response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
+    }
     return NULL;
   }
 #ifndef NDEBUG
@@ -112,10 +142,14 @@ char *c_simple_http_request_response(
 
   if (strcmp(request_type, "GET") != 0) {
     fprintf(stderr, "ERROR Only GET requests are allowed!\n");
+    if (out_response_code) {
+      *out_response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
+    }
     return NULL;
   }
 
   size_t generated_size = 0;
+  __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
   char *stripped_path = c_simple_http_strip_path(
     request_path, request_path_idx);
   char *generated_buf = c_simple_http_path_to_generated(
@@ -123,19 +157,30 @@ char *c_simple_http_request_response(
     templates,
     &generated_size);
 
-  if (stripped_path) {
-    free(stripped_path);
-  }
-
   if (!generated_buf || generated_size == 0) {
     fprintf(stderr, "ERROR Unable to generate response html for path \"%s\"!\n",
       request_path);
+    if (out_response_code) {
+      if (
+          simple_archiver_hash_map_get(
+            templates->hash_map,
+            stripped_path ? stripped_path : request_path,
+            stripped_path ? strlen(stripped_path) + 1 : request_path_idx + 1)
+          == NULL) {
+        *out_response_code = C_SIMPLE_HTTP_Response_404_Not_Found;
+      } else {
+        *out_response_code = C_SIMPLE_HTTP_Response_500_Internal_Server_Error;
+      }
+    }
     return NULL;
   }
 
   if (out_size) {
     *out_size = generated_size;
   }
+  if (out_response_code) {
+    *out_response_code = C_SIMPLE_HTTP_Response_200_OK;
+  }
   return generated_buf;
 }
 
index f1b7b0557910e116e52c9d88adb628e5d5e2c569..115e8e1aa75973a63fb488b6fbbad9d6624bf624 100644 (file)
 
 typedef C_SIMPLE_HTTP_ParsedConfig C_SIMPLE_HTTP_HTTPTemplates;
 
+enum C_SIMPLE_HTTP_ResponseCode {
+  C_SIMPLE_HTTP_Response_200_OK,
+  C_SIMPLE_HTTP_Response_400_Bad_Request,
+  C_SIMPLE_HTTP_Response_404_Not_Found,
+  C_SIMPLE_HTTP_Response_500_Internal_Server_Error,
+};
+
+// If the response code is an error, returns a full response string that doesn't
+// need to be free'd. Otherwise, returns as if error 500.
+const char *c_simple_http_response_code_error_to_response(
+  enum C_SIMPLE_HTTP_ResponseCode response_code);
+
 /// Returned buffer must be "free"d after use.
 /// If the request is not valid, or 404, then the buffer will be NULL.
 char *c_simple_http_request_response(
   const char *request,
   unsigned int size,
   const C_SIMPLE_HTTP_HTTPTemplates *templates,
-  size_t *out_size
+  size_t *out_size,
+  enum C_SIMPLE_HTTP_ResponseCode *out_response_code
 );
 
 /// Takes a PATH string and returns a "bare" path.
index 1fc4c17c73923ee35bb6f786cfb682db81a0bb6a..15fdb3c28c1c0006f2fa07511b970b5b92b48c04 100644 (file)
@@ -141,12 +141,18 @@ int main(int argc, char **argv) {
       puts("");
 
       size_t response_size = 0;
+      enum C_SIMPLE_HTTP_ResponseCode response_code;
       const char *response = c_simple_http_request_response(
-        (const char*)recv_buf, (unsigned int)read_ret, &parsed_config, &response_size);
-      if (response) {
+        (const char*)recv_buf,
+        (unsigned int)read_ret,
+        &parsed_config,
+        &response_size,
+        &response_code);
+      if (response && response_code == C_SIMPLE_HTTP_Response_200_OK) {
         CHECK_ERROR_WRITE(write(connection_fd, "HTTP/1.1 200 OK\n", 16));
         CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11));
-        CHECK_ERROR_WRITE(write(connection_fd, "Content-Type: text/html\n", 24));
+        CHECK_ERROR_WRITE(write(
+          connection_fd, "Content-Type: text/html\n", 24));
         char content_length_buf[128];
         size_t content_length_buf_size = 0;
         memcpy(content_length_buf, "Content-Length: ", 16);
@@ -166,18 +172,28 @@ int main(int argc, char **argv) {
           continue;
         }
         content_length_buf_size += (size_t)written;
-        CHECK_ERROR_WRITE(write(connection_fd, content_length_buf, content_length_buf_size));
+        CHECK_ERROR_WRITE(write(
+          connection_fd, content_length_buf, content_length_buf_size));
         CHECK_ERROR_WRITE(write(connection_fd, "\n", 1));
         CHECK_ERROR_WRITE(write(connection_fd, response, response_size));
 
         free((void*)response);
       } else {
-        // TODO handle internal errors also.
-        CHECK_ERROR_WRITE(write(connection_fd, "HTTP/1.1 404 Not Found\n", 23));
-        CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11));
-        CHECK_ERROR_WRITE(write(connection_fd, "Content-Type: text/html\n", 24));
-        CHECK_ERROR_WRITE(write(connection_fd, "Content-Length: 14\n", 19));
-        CHECK_ERROR_WRITE(write(connection_fd, "\n404 Not Found\n", 15));
+        const char *response = c_simple_http_response_code_error_to_response(
+          response_code);
+        size_t response_size = strlen(response);
+        if (response) {
+          CHECK_ERROR_WRITE(write(connection_fd, response, response_size));
+        } else {
+          CHECK_ERROR_WRITE(write(
+            connection_fd, "HTTP/1.1 404 Not Found\n", 23));
+          CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11));
+          CHECK_ERROR_WRITE(write(
+            connection_fd, "Content-Type: text/html\n", 24));
+          CHECK_ERROR_WRITE(write(connection_fd, "Content-Length: 35\n", 19));
+          CHECK_ERROR_WRITE(write(
+            connection_fd, "\n<h1>500 Internal Server Error</h1>\n", 36));
+        }
       }
       close(connection_fd);
     } else {