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)
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();
++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
#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.
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
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
/// 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
#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");
"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) {
}
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;
// Local includes.
#include "config.h"
#include "http_template.h"
+#include "http.h"
// Third party includes.
#include <SimpleArchiver/src/helpers.h>
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()
}