]> git.seodisparate.com - c_simple_http/commitdiff
Impl. print of specific headers arg/option
authorStephen Seo <seo.disparate@gmail.com>
Fri, 6 Sep 2024 08:30:37 +0000 (17:30 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Fri, 6 Sep 2024 08:30:37 +0000 (17:30 +0900)
TODO: Maybe refactor this to use a hash-map or something similar to
speed up the process. If N = number-of-headers-to-print and M =
size-of-request-buffer, then currrently this will take O(N*M) time.

src/arg_parse.c
src/arg_parse.h
src/http.c
src/http.h
src/main.c
src/test.c

index 4bc3e3b7a3593d281eeab93f28c31bc21d9d0e32..4e07d3375fa29cc044fd13aadfab6ab95c170a3b 100644 (file)
@@ -26,14 +26,18 @@ void print_usage(void) {
   puts("  -p <port> | --port <port>");
   puts("  --config=<config_file>");
   puts("  --disable-peer-addr-print");
+  puts("  --req-header-to-print=<header> (can be used multiple times)");
+  puts("    For example: --req-header-to-print=User-Agent");
 }
 
 Args parse_args(int argc, char **argv) {
   --argc;
   ++argv;
 
+  __attribute__((cleanup(c_simple_http_free_args)))
   Args args;
   memset(&args, 0, sizeof(Args));
+  args.list_of_headers_to_log = simple_archiver_list_init();
 
   while (argc > 0) {
     if ((strcmp(argv[0], "-p") == 0 || strcmp(argv[0], "--port") == 0)
@@ -48,6 +52,19 @@ Args parse_args(int argc, char **argv) {
       args.config_file = argv[0] + 9;
     } else if (strcmp(argv[0], "--disable-peer-addr-print") == 0) {
       args.flags |= 1;
+    } else if (strncmp(argv[0], "--req-header-to-print=", 22) == 0
+        && strlen(argv[0]) > 22) {
+      size_t arg_size = strlen(argv[0]) + 1 - 22;
+      char *header_buf = malloc(arg_size);
+      memcpy(header_buf, argv[0] + 22, arg_size);
+      if (simple_archiver_list_add(
+            args.list_of_headers_to_log, header_buf, NULL)
+          != 0) {
+        fprintf(
+          stderr, "ERROR Failed to parse \"--req-header-to-print=...\" !\n");
+        free(header_buf);
+        exit(1);
+      }
     } else {
       puts("ERROR: Invalid args!\n");
       print_usage();
@@ -58,7 +75,18 @@ Args parse_args(int argc, char **argv) {
     ++argv;
   }
 
-  return args;
+  // Prevent freeing of Args due to successful parsing.
+  Args to_return = args;
+  args.list_of_headers_to_log = NULL;
+  return to_return;
+}
+
+void c_simple_http_free_args(Args *args) {
+  if (args) {
+    if (args->list_of_headers_to_log) {
+      simple_archiver_list_free(&args->list_of_headers_to_log);
+    }
+  }
 }
 
 // vim: ts=2 sts=2 sw=2
index 641c29bb0713d1160b743abefb5a9170859f48d2..f9b2d17cb43e352c4cc10368cf3547b41bc8de05 100644 (file)
@@ -17,6 +17,9 @@
 #ifndef SEODISPARATE_COM_C_SIMPLE_HTTP_ARG_PARSE_H_
 #define SEODISPARATE_COM_C_SIMPLE_HTTP_ARG_PARSE_H_
 
+// Third party includes.
+#include <SimpleArchiver/src/data_structures/linked_list.h>
+
 typedef struct Args {
   // xxxx xxx0 - enable peer addr print.
   // xxxx xxx1 - disable peer addr print.
@@ -24,12 +27,16 @@ typedef struct Args {
   unsigned short port;
   // Does not need to be free'd, this should point to a string in argv.
   const char *config_file;
+  // Needs to be free'd.
+  SDArchiverLinkedList *list_of_headers_to_log;
 } Args;
 
 void print_usage(void);
 
 Args parse_args(int argc, char **argv);
 
+void c_simple_http_free_args(Args *args);
+
 #endif
 
 // vim: ts=2 sts=2 sw=2
index b448f93a0720dda34a89e1abf43faf0f8f610bf2..d9cb3fd445af889194933073907b95bb62cd05b3 100644 (file)
@@ -209,4 +209,75 @@ char *c_simple_http_strip_path(const char *path, size_t path_size) {
   return stripped_path;
 }
 
+char *c_simple_http_filter_request_header(
+    const char *request, size_t request_size, const char *header) {
+  if (!request) {
+    fprintf(stderr, "ERROR filter_request_header: request is NULL!\n");
+    return NULL;
+  } else if (request_size == 0) {
+    fprintf(stderr, "ERROR filter_request_header: request_size is zero!\n");
+    return NULL;
+  } else if (!header) {
+    fprintf(stderr, "ERROR filter_request_header: header is NULL!\n");
+    return NULL;
+  }
+
+  // xxxx xxx0 - Start of line.
+  // xxxx xxx1 - In middle of line.
+  // xxxx xx0x - Header NOT found.
+  // xxxx xx1x - Header was found.
+  unsigned int flags = 0;
+  size_t idx = 0;
+  size_t line_start_idx = 0;
+  size_t header_idx = 0;
+  for(; idx < request_size && request[idx] != 0; ++idx) {
+    if ((flags & 1) == 0) {
+      if (request[idx] == '\n') {
+        continue;
+      }
+      line_start_idx = idx;
+      flags |= 1;
+      if (request[idx] == header[header_idx]) {
+        ++header_idx;
+        if (header[header_idx] == 0) {
+          flags |= 2;
+          break;
+        }
+      } else {
+        header_idx = 0;
+      }
+    } else {
+      if (header_idx != 0) {
+        if (request[idx] == header[header_idx]) {
+          ++header_idx;
+          if (header[header_idx] == 0) {
+            flags |= 2;
+            break;
+          }
+        } else {
+          header_idx = 0;
+        }
+      }
+
+      if (request[idx] == '\n') {
+        flags &= 0xFFFFFFFE;
+      }
+    }
+  }
+
+  if ((flags & 2) != 0) {
+    // Get line end starting from line_start_idx.
+    for (
+      idx = line_start_idx;
+      idx < request_size && request[idx] != 0 && request[idx] != '\n';
+      ++idx);
+    char *line_buf = malloc(idx - line_start_idx + 1);
+    memcpy(line_buf, request + line_start_idx, idx - line_start_idx);
+    line_buf[idx - line_start_idx] = 0;
+    return line_buf;
+  }
+
+  return NULL;
+}
+
 // vim: ts=2 sts=2 sw=2
index 115e8e1aa75973a63fb488b6fbbad9d6624bf624..0c6eebebef4598daf07e2562b99080f7d2f4343c 100644 (file)
@@ -56,6 +56,11 @@ char *c_simple_http_request_response(
 /// Must be free'd if returns non-NULL.
 char *c_simple_http_strip_path(const char *path, size_t path_size);
 
+/// Returns a line from the request that starts with the "header" C-string.
+/// If returns non-NULL, must be free'd.
+char *c_simple_http_filter_request_header(
+  const char *request, size_t request_size, const char *header);
+
 #endif
 
 // vim: ts=2 sts=2 sw=2
index bac21d6eaa4cc6235a9ecc45a8d8a4a57e7f77ec..4c84bc6ce3a6dc197407b30901f1abc349fef151 100644 (file)
 #include "constants.h"
 #include "http.h"
 
+typedef struct C_SIMPLE_HTTP_INTERNAL_Header_Check_Ctx {
+  const unsigned char *recv_buf;
+  ssize_t recv_buf_size;
+} C_SIMPLE_HTTP_INTERNAL_Header_Check_Ctx;
+
 #define CHECK_ERROR_WRITE(write_expr) \
   if (write_expr < 0) { \
     close(connection_fd); \
     continue; \
   }
 
+int c_simple_http_headers_check_print(void *data, void *ud) {
+  C_SIMPLE_HTTP_INTERNAL_Header_Check_Ctx *ctx = ud;
+  const char *header_c_str = data;
+
+  __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
+  char *matching_line = c_simple_http_filter_request_header(
+    (const char*)ctx->recv_buf,
+    (size_t)ctx->recv_buf_size,
+    header_c_str);
+  if (matching_line) {
+    printf("Printing header line: %s\n", matching_line);
+  }
+  return 0;
+}
+
 int main(int argc, char **argv) {
-  const Args args = parse_args(argc, argv);
+  __attribute__((cleanup(c_simple_http_free_args)))
+  Args args = parse_args(argc, argv);
 
   if (!args.config_file) {
     fprintf(stderr, "ERROR Config file not specified!\n");
@@ -131,8 +152,8 @@ int main(int argc, char **argv) {
           "WARNING Failed to read from new connection, closing...\n");
         continue;
       }
-      // DEBUG print received buf.
 #ifndef NDEBUG
+      // DEBUG print received buf.
       for (unsigned int idx = 0;
           idx < C_SIMPLE_HTTP_RECV_BUF_SIZE && idx < read_ret;
           ++idx) {
@@ -145,6 +166,15 @@ int main(int argc, char **argv) {
       }
       puts("");
 #endif
+      {
+        C_SIMPLE_HTTP_INTERNAL_Header_Check_Ctx ctx;
+        ctx.recv_buf = recv_buf;
+        ctx.recv_buf_size = read_ret;
+        simple_archiver_list_get(
+          args.list_of_headers_to_log,
+          c_simple_http_headers_check_print,
+          &ctx);
+      }
 
       size_t response_size = 0;
       enum C_SIMPLE_HTTP_ResponseCode response_code;
index 8aab8d8cbb7238316a939b52015e962cd6ec5463..2cb3e8f908d091d0d2b72368d42cdcd2e6003fd4 100644 (file)
@@ -6,6 +6,7 @@
 // Local includes.
 #include "config.h"
 #include "http_template.h"
+#include "http.h"
 
 // Third party includes.
 #include <SimpleArchiver/src/helpers.h>
@@ -444,6 +445,25 @@ int main(void) {
     simple_archiver_helper_cleanup_c_string(&buf);
   }
 
+  // Test http.
+  {
+    const char *request =
+      "GET /path HTTP/1.1\nA-Header: Something\nAnother-Header: Other\n"
+      "Different-Header: Different\n";
+    size_t request_size = 92;
+
+    __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
+    char *header_line_buf = c_simple_http_filter_request_header(
+      request, request_size, "Another-Header");
+    ASSERT_TRUE(header_line_buf);
+    ASSERT_STREQ(header_line_buf, "Another-Header: Other");
+
+    simple_archiver_helper_cleanup_c_string(&header_line_buf);
+    header_line_buf = c_simple_http_filter_request_header(
+      request, request_size, "Non-Existant-Header");
+    ASSERT_FALSE(header_line_buf);
+  }
+
   RETURN()
 }