Impl. print of specific headers arg/option
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 2s

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.
This commit is contained in:
Stephen Seo 2024-09-06 17:30:37 +09:00
parent fcad980593
commit 9294108f13
6 changed files with 164 additions and 3 deletions

View 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

View 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

View 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

View 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

View file

@ -39,6 +39,11 @@
#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); \
@ -46,8 +51,24 @@
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;

View 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()
}