Impl. print of specific headers arg/option
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 2s
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:
parent
fcad980593
commit
9294108f13
6 changed files with 164 additions and 3 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
71
src/http.c
71
src/http.c
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
34
src/main.c
34
src/main.c
|
@ -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;
|
||||
|
|
20
src/test.c
20
src/test.c
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue