]> git.seodisparate.com - c_simple_http/commitdiff
Add option --enable-static-dir=<DIR>, use static
authorStephen Seo <seo.disparate@gmail.com>
Wed, 30 Oct 2024 05:17:49 +0000 (14:17 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Wed, 30 Oct 2024 05:17:49 +0000 (14:17 +0900)
example_config/example.config
example_config/silly.jpg [new file with mode: 0644]
src/arg_parse.c
src/arg_parse.h
src/http.c
src/http.h
src/main.c

index 768af8c58c0af9dad20c6cb045e9b1a4000b00de..27540950093168684b8abf177c6cdf2247cd3a3f 100644 (file)
@@ -69,6 +69,8 @@ HTML='''
   <h1>Nested inner: further<h1>
   {{{VAR}}}
   <br>
+  <img src="/silly.jpg" />
+  <br>
   <a href="/inner">back</a>
   </body>
   </html>
diff --git a/example_config/silly.jpg b/example_config/silly.jpg
new file mode 100644 (file)
index 0000000..d2c7371
Binary files /dev/null and b/example_config/silly.jpg differ
index 7801ca2032a7fef3e2663ea34db2a1f19a6ccd2a..5fea90a3538995cfa71650f0e496164b6319b3f7 100644 (file)
@@ -43,6 +43,7 @@ void print_usage(void) {
   puts("  --enable-reload-config-on-change");
   puts("  --enable-cache-dir=<DIR>");
   puts("  --cache-entry-lifetime-seconds=<SECONDS>");
+  puts("  --enable-static-dir=<DIR>");
 }
 
 Args parse_args(int32_t argc, char **argv) {
@@ -128,6 +129,29 @@ Args parse_args(int32_t argc, char **argv) {
           "NOTICE set cache-entry-lifetime to %lu\n",
           args.cache_lifespan_seconds);
       }
+    } else if (strncmp(argv[0], "--enable-static-dir=", 20) == 0) {
+      args.static_dir = argv[0] + 20;
+      // Check if it actually is an existing directory.
+      DIR *d = opendir(args.static_dir);
+      if (d == NULL) {
+        if (errno == ENOENT) {
+          fprintf(
+            stderr,
+            "ERROR Directory \"%s\" does not exist!\n",
+            args.static_dir);
+          exit(1);
+        } else {
+          fprintf(
+            stderr,
+            "ERROR Failed to open directory \"%s\" (errno %d)!\n",
+            args.static_dir,
+            errno);
+          exit(1);
+        }
+      } else {
+        printf("Directory \"%s\" exists.\n", args.static_dir);
+      }
+      closedir(d);
     } else {
       fprintf(stderr, "ERROR: Invalid args!\n");
       print_usage();
index 24ba5f7d7b7ce7caca31f1d38b944451841fdba3..7595f726f371e489c1b02fc637cd91f3e3277afd 100644 (file)
@@ -38,6 +38,9 @@ typedef struct Args {
   // Does not need to be free'd since it points to a string in argv.
   const char *cache_dir;
   size_t cache_lifespan_seconds;
+  // Non-NULL if static-dir is specified and files in the dir are to be served.
+  // Does not need to be free'd since it points to a string in argv.
+  const char *static_dir;
 } Args;
 
 void print_usage(void);
index 0e688aa143dce2ac4106b878a2f18bff6882b646..958b012f135f4eada380e738b4e07db81e52ab8e 100644 (file)
@@ -65,7 +65,8 @@ char *c_simple_http_request_response(
     C_SIMPLE_HTTP_HTTPTemplates *templates,
     size_t *out_size,
     enum C_SIMPLE_HTTP_ResponseCode *out_response_code,
-    const Args *args) {
+    const Args *args,
+    char **request_path_out) {
   if (out_size) {
     *out_size = 0;
   }
@@ -176,6 +177,11 @@ char *c_simple_http_request_response(
 
   char *generated_buf = NULL;
 
+  if (request_path_out) {
+    *request_path_out =
+      strdup(stripped_path ? stripped_path : request_path_unescaped);
+  }
+
   if (args->cache_dir) {
     int ret = c_simple_http_cache_path(
       stripped_path ? stripped_path : request_path_unescaped,
@@ -212,7 +218,8 @@ char *c_simple_http_request_response(
   }
 
   if (!generated_buf || generated_size == 0) {
-    fprintf(stderr, "ERROR Unable to generate response html for path \"%s\"!\n",
+    fprintf(stderr,
+            "WARNING Unable to generate response html for path \"%s\"!\n",
       request_path);
     if (out_response_code) {
       if (
index 7b7a52a9a57ca9be00f1047432865218ca070a66..018f065dbc48676a8671968c757618be080df06b 100644 (file)
@@ -50,7 +50,8 @@ char *c_simple_http_request_response(
   C_SIMPLE_HTTP_HTTPTemplates *templates,
   size_t *out_size,
   enum C_SIMPLE_HTTP_ResponseCode *out_response_code,
-  const Args *args
+  const Args *args,
+  char **request_path_out
 );
 
 /// Takes a PATH string and returns a "bare" path.
index 976f245ac06e314ed4306e298213b329853bed53..92b7b5b620fd69e746151e9952bba0964c77e9dc 100644 (file)
 #include "constants.h"
 #include "http.h"
 #include "helpers.h"
+#include "static.h"
 
 #define CHECK_ERROR_WRITE(write_expr) \
+  if (write_expr < 0) { \
+    close(connection_fd); \
+    fprintf(stderr, "ERROR Failed to write to connected peer, closing...\n"); \
+    return 1; \
+  }
+
+#define CHECK_ERROR_WRITE_CONTINUE(write_expr) \
   if (write_expr < 0) { \
     close(connection_fd); \
     fprintf(stderr, "ERROR Failed to write to connected peer, closing...\n"); \
@@ -74,6 +82,31 @@ void c_simple_http_inotify_fd_cleanup(int *fd) {
   }
 }
 
+int c_simple_http_on_error(
+    enum C_SIMPLE_HTTP_ResponseCode response_code,
+    int connection_fd
+) {
+  const char *response = c_simple_http_response_code_error_to_response(
+    response_code);
+  size_t response_size;
+  if (response) {
+    response_size = strlen(response);
+    CHECK_ERROR_WRITE(write(connection_fd, response, response_size));
+  } else {
+    CHECK_ERROR_WRITE(write(
+      connection_fd, "HTTP/1.1 500 Internal Server Error\n", 35));
+    CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11));
+    CHECK_ERROR_WRITE(write(connection_fd, "Connection: close\n", 18));
+    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));
+  }
+
+  return 0;
+}
+
 int main(int argc, char **argv) {
   __attribute__((cleanup(c_simple_http_free_args)))
   Args args = parse_args(argc, argv);
@@ -354,18 +387,23 @@ int main(int argc, char **argv) {
 
       size_t response_size = 0;
       enum C_SIMPLE_HTTP_ResponseCode response_code;
+      __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
+      char *request_path = NULL;
       const char *response = c_simple_http_request_response(
         (const char*)recv_buf,
         (uint32_t)read_ret,
         &parsed_config,
         &response_size,
         &response_code,
-        &args);
+        &args,
+        &request_path);
       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, "Connection: close\n", 18));
-        CHECK_ERROR_WRITE(write(
+        CHECK_ERROR_WRITE_CONTINUE(write(
+          connection_fd, "HTTP/1.1 200 OK\n", 16));
+        CHECK_ERROR_WRITE_CONTINUE(write(connection_fd, "Allow: GET\n", 11));
+        CHECK_ERROR_WRITE_CONTINUE(write(
+          connection_fd, "Connection: close\n", 18));
+        CHECK_ERROR_WRITE_CONTINUE(write(
           connection_fd, "Content-Type: text/html\n", 24));
         char content_length_buf[128];
         size_t content_length_buf_size = 0;
@@ -386,28 +424,83 @@ int main(int argc, char **argv) {
           continue;
         }
         content_length_buf_size += (size_t)written;
-        CHECK_ERROR_WRITE(write(
+        CHECK_ERROR_WRITE_CONTINUE(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));
+        CHECK_ERROR_WRITE_CONTINUE(write(connection_fd, "\n", 1));
+        CHECK_ERROR_WRITE_CONTINUE(write(
+          connection_fd, response, response_size));
 
         free((void*)response);
-      } else {
-        const char *response = c_simple_http_response_code_error_to_response(
-          response_code);
-        if (response) {
-          response_size = strlen(response);
-          CHECK_ERROR_WRITE(write(connection_fd, response, response_size));
+      } else if (
+          response_code == C_SIMPLE_HTTP_Response_404_Not_Found
+          && args.static_dir) {
+        __attribute__((cleanup(c_simple_http_cleanup_static_file_info)))
+        C_SIMPLE_HTTP_StaticFileInfo file_info =
+          c_simple_http_get_file(args.static_dir, request_path, 0);
+        if (file_info.result == STATIC_FILE_RESULT_NoXDGMimeAvailable) {
+          file_info = c_simple_http_get_file(args.static_dir, request_path, 1);
+        }
+
+        if (file_info.result != STATIC_FILE_RESULT_OK
+            || !file_info.buf
+            || file_info.buf_size == 0
+            || !file_info.mime_type) {
+          if (file_info.result == STATIC_FILE_RESULT_FileError
+              || file_info.result == STATIC_FILE_RESULT_InternalError) {
+            response_code = C_SIMPLE_HTTP_Response_500_Internal_Server_Error;
+          } else if (file_info.result == STATIC_FILE_RESULT_InvalidParameter) {
+            response_code = C_SIMPLE_HTTP_Response_400_Bad_Request;
+          } else {
+            response_code = C_SIMPLE_HTTP_Response_500_Internal_Server_Error;
+          }
+
+          if (c_simple_http_on_error(response_code, connection_fd)) {
+            continue;
+          }
         } else {
-          CHECK_ERROR_WRITE(write(
-            connection_fd, "HTTP/1.1 500 Internal Server Error\n", 35));
-          CHECK_ERROR_WRITE(write(connection_fd, "Allow: GET\n", 11));
-          CHECK_ERROR_WRITE(write(connection_fd, "Connection: close\n", 18));
-          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));
+          CHECK_ERROR_WRITE_CONTINUE(write(
+            connection_fd, "HTTP/1.1 200 OK\n", 16));
+          CHECK_ERROR_WRITE_CONTINUE(write(connection_fd, "Allow: GET\n", 11));
+          CHECK_ERROR_WRITE_CONTINUE(write(
+            connection_fd, "Connection: close\n", 18));
+          uint64_t mime_length = strlen(file_info.mime_type);
+          __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
+          char *mime_type_buf = malloc(mime_length + 1 + 14 + 1);
+          snprintf(
+            mime_type_buf,
+            mime_length + 1 + 14 + 1,
+            "Content-Type: %s\n",
+            file_info.mime_type);
+          CHECK_ERROR_WRITE_CONTINUE(write(
+            connection_fd, mime_type_buf, mime_length + 1 + 14));
+          uint64_t content_str_len = 0;
+          for(uint64_t buf_size_temp = file_info.buf_size;
+              buf_size_temp > 0;
+              buf_size_temp /= 10) {
+            ++content_str_len;
+          }
+          if (content_str_len == 0) {
+            content_str_len = 1;
+          }
+          __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
+          char *content_length_buf = malloc(content_str_len + 1 + 16 + 1);
+          snprintf(
+            content_length_buf,
+            content_str_len + 1 + 16 + 1,
+            "Content-Length: %lu\n",
+            file_info.buf_size);
+          CHECK_ERROR_WRITE_CONTINUE(write(
+            connection_fd, content_length_buf, content_str_len + 1 + 16));
+          CHECK_ERROR_WRITE_CONTINUE(write(connection_fd, "\n", 1));
+          CHECK_ERROR_WRITE_CONTINUE(write(
+            connection_fd, file_info.buf, file_info.buf_size));
+          fprintf(stderr,
+                  "NOTICE Found static file for path \"%s\"\n",
+                  request_path);
+        }
+      } else {
+        if (c_simple_http_on_error(response_code, connection_fd)) {
+          continue;
         }
       }
       close(connection_fd);