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(" -p <port> | --port <port>");
|
||||||
puts(" --config=<config_file>");
|
puts(" --config=<config_file>");
|
||||||
puts(" --disable-peer-addr-print");
|
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) {
|
Args parse_args(int argc, char **argv) {
|
||||||
--argc;
|
--argc;
|
||||||
++argv;
|
++argv;
|
||||||
|
|
||||||
|
__attribute__((cleanup(c_simple_http_free_args)))
|
||||||
Args args;
|
Args args;
|
||||||
memset(&args, 0, sizeof(Args));
|
memset(&args, 0, sizeof(Args));
|
||||||
|
args.list_of_headers_to_log = simple_archiver_list_init();
|
||||||
|
|
||||||
while (argc > 0) {
|
while (argc > 0) {
|
||||||
if ((strcmp(argv[0], "-p") == 0 || strcmp(argv[0], "--port") == 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;
|
args.config_file = argv[0] + 9;
|
||||||
} else if (strcmp(argv[0], "--disable-peer-addr-print") == 0) {
|
} else if (strcmp(argv[0], "--disable-peer-addr-print") == 0) {
|
||||||
args.flags |= 1;
|
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 {
|
} else {
|
||||||
puts("ERROR: Invalid args!\n");
|
puts("ERROR: Invalid args!\n");
|
||||||
print_usage();
|
print_usage();
|
||||||
|
@ -58,7 +75,18 @@ Args parse_args(int argc, char **argv) {
|
||||||
++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
|
// vim: ts=2 sts=2 sw=2
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
#ifndef SEODISPARATE_COM_C_SIMPLE_HTTP_ARG_PARSE_H_
|
#ifndef SEODISPARATE_COM_C_SIMPLE_HTTP_ARG_PARSE_H_
|
||||||
#define 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 {
|
typedef struct Args {
|
||||||
// xxxx xxx0 - enable peer addr print.
|
// xxxx xxx0 - enable peer addr print.
|
||||||
// xxxx xxx1 - disable peer addr print.
|
// xxxx xxx1 - disable peer addr print.
|
||||||
|
@ -24,12 +27,16 @@ typedef struct Args {
|
||||||
unsigned short port;
|
unsigned short port;
|
||||||
// Does not need to be free'd, this should point to a string in argv.
|
// Does not need to be free'd, this should point to a string in argv.
|
||||||
const char *config_file;
|
const char *config_file;
|
||||||
|
// Needs to be free'd.
|
||||||
|
SDArchiverLinkedList *list_of_headers_to_log;
|
||||||
} Args;
|
} Args;
|
||||||
|
|
||||||
void print_usage(void);
|
void print_usage(void);
|
||||||
|
|
||||||
Args parse_args(int argc, char **argv);
|
Args parse_args(int argc, char **argv);
|
||||||
|
|
||||||
|
void c_simple_http_free_args(Args *args);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// vim: ts=2 sts=2 sw=2
|
// 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;
|
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
|
// 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.
|
/// Must be free'd if returns non-NULL.
|
||||||
char *c_simple_http_strip_path(const char *path, size_t path_size);
|
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
|
#endif
|
||||||
|
|
||||||
// vim: ts=2 sts=2 sw=2
|
// vim: ts=2 sts=2 sw=2
|
||||||
|
|
34
src/main.c
34
src/main.c
|
@ -39,6 +39,11 @@
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "http.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) \
|
#define CHECK_ERROR_WRITE(write_expr) \
|
||||||
if (write_expr < 0) { \
|
if (write_expr < 0) { \
|
||||||
close(connection_fd); \
|
close(connection_fd); \
|
||||||
|
@ -46,8 +51,24 @@
|
||||||
continue; \
|
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) {
|
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) {
|
if (!args.config_file) {
|
||||||
fprintf(stderr, "ERROR Config file not specified!\n");
|
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");
|
"WARNING Failed to read from new connection, closing...\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// DEBUG print received buf.
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
// DEBUG print received buf.
|
||||||
for (unsigned int idx = 0;
|
for (unsigned int idx = 0;
|
||||||
idx < C_SIMPLE_HTTP_RECV_BUF_SIZE && idx < read_ret;
|
idx < C_SIMPLE_HTTP_RECV_BUF_SIZE && idx < read_ret;
|
||||||
++idx) {
|
++idx) {
|
||||||
|
@ -145,6 +166,15 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
puts("");
|
puts("");
|
||||||
#endif
|
#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;
|
size_t response_size = 0;
|
||||||
enum C_SIMPLE_HTTP_ResponseCode response_code;
|
enum C_SIMPLE_HTTP_ResponseCode response_code;
|
||||||
|
|
20
src/test.c
20
src/test.c
|
@ -6,6 +6,7 @@
|
||||||
// Local includes.
|
// Local includes.
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "http_template.h"
|
#include "http_template.h"
|
||||||
|
#include "http.h"
|
||||||
|
|
||||||
// Third party includes.
|
// Third party includes.
|
||||||
#include <SimpleArchiver/src/helpers.h>
|
#include <SimpleArchiver/src/helpers.h>
|
||||||
|
@ -444,6 +445,25 @@ int main(void) {
|
||||||
simple_archiver_helper_cleanup_c_string(&buf);
|
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()
|
RETURN()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue