diff --git a/CMakeLists.txt b/CMakeLists.txt index c5c90da..ac17f65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,10 +22,13 @@ check_include_files(stdlib.h HAVE_STDLIB_H) check_include_files(string.h HAVE_STRING_H) check_include_files(stdint.h HAVE_STDINT_H) check_include_files(errno.h HAVE_ERRNO_H) +check_include_files(signal.h HAVE_SIGNAL_H) check_include_files(strings.h HAVE_STRINGS_H) check_include_files(inttypes.h HAVE_INTTYPES_H) +check_include_files(stdbool.h HAVE_STDBOOL_H) check_include_files(limits.h HAVE_LIMITS_H) - +check_include_files(stddef.h HAVE_STDDEF_H) +check_include_files(ctype.h HAVE_CTYPE_H) check_include_files(unistd.h HAVE_UNISTD_H) check_include_files(stdarg.h HAVE_STDARG_PROTOTYPES) check_include_files(sys/tree.h HAVE_SYS_TREE) @@ -48,17 +51,17 @@ set(LIBEVHTP_SOURCE_FILES evhtp.c numtoa.c parser.c - logutils.c) + log.c) find_package(LibEvent REQUIRED) list(APPEND LIBEVHTP_EXTERNAL_LIBS ${LIBEVENT_LIBRARIES}) list(APPEND LIBEVHTP_EXTERNAL_INCLUDES ${LIBEVENT_INCLUDE_DIRS}) - list(APPEND package_deps LibEvent) + set(evhtp_dir_headers "include/evhtp/evhtp.h" "include/evhtp/parser.h" - "include/evhtp/assert.h") + "include/evhtp/log.h") if(NOT EVHTP_DISABLE_SSL) find_package(OpenSSL) diff --git a/evhtp.c b/evhtp.c index 6150989..4ed0464 100644 --- a/evhtp.c +++ b/evhtp.c @@ -33,8 +33,6 @@ #include "numtoa.h" #include "evhtp/evhtp.h" -#include "log.h" - /** * @brief structure containing a single callback and configuration * diff --git a/examples/example_basic.c b/examples/example_basic.c index 20bdc5a..9948152 100644 --- a/examples/example_basic.c +++ b/examples/example_basic.c @@ -6,18 +6,17 @@ #include #include -#include "../log.h" #include "./eutils.h" #include "internal.h" #include "evhtp/evhtp.h" -#include "evhtp/logutils.h" +#include "evhtp/log.h" static void process_request_(evhtp_request_t * req, void * arg) { (void)arg; - htp_log_request(arg, stderr, req); + evhtp_log_request_f(arg, req, stderr); evhtp_send_reply(req, EVHTP_RES_OK); } @@ -32,7 +31,7 @@ main(int argc, char ** argv) evbase = event_base_new(); htp = evhtp_new(evbase, NULL); - log = htp_logutil_new("$rhost $host \"$ua\" [$ts] \"$meth $path HTTP/$proto\" $status"); + log = evhtp_log_new("$rhost $host '$ua' [$ts] '$meth $path HTTP/$proto' $status"); evhtp_set_cb(htp, "/", process_request_, log); evhtp_enable_flag(htp, EVHTP_FLAG_ENABLE_ALL); diff --git a/examples/example_chunked.c b/examples/example_chunked.c index 947fafd..c953f9e 100644 --- a/examples/example_chunked.c +++ b/examples/example_chunked.c @@ -4,7 +4,6 @@ #include #include -#include "../log.h" #include "./eutils.h" #include "internal.h" #include "evhtp/evhtp.h" diff --git a/examples/example_pause.c b/examples/example_pause.c index 882e507..0cccac2 100644 --- a/examples/example_pause.c +++ b/examples/example_pause.c @@ -11,7 +11,6 @@ #include #include -#include "../log.h" #include "internal.h" #include "evhtp/evhtp.h" #include "./eutils.h" diff --git a/examples/example_request_fini.c b/examples/example_request_fini.c index 68e4925..d4d6da6 100644 --- a/examples/example_request_fini.c +++ b/examples/example_request_fini.c @@ -7,7 +7,6 @@ #include #include -#include "../log.h" #include "./eutils.h" #include "internal.h" #include "evhtp/evhtp.h" diff --git a/examples/example_vhost.c b/examples/example_vhost.c index 9116b21..3b6881c 100644 --- a/examples/example_vhost.c +++ b/examples/example_vhost.c @@ -5,7 +5,6 @@ #include #include "internal.h" -#include "../log.h" #include "evhtp/evhtp.h" #include "./eutils.h" diff --git a/examples/https/example_https_client.c b/examples/https/example_https_client.c index 771d48c..ca66d5a 100644 --- a/examples/https/example_https_client.c +++ b/examples/https/example_https_client.c @@ -8,7 +8,6 @@ #include #include -#include "../log.h" #include "internal.h" #include "evhtp/evhtp.h" diff --git a/examples/https/example_https_server.c b/examples/https/example_https_server.c index 4d39f3e..3e020b2 100644 --- a/examples/https/example_https_server.c +++ b/examples/https/example_https_server.c @@ -8,7 +8,6 @@ #include #include -#include "../log.h" #include "internal.h" #include "evhtp/evhtp.h" diff --git a/include/evhtp/assert.h b/include/evhtp/assert.h deleted file mode 100644 index 3742c9e..0000000 --- a/include/evhtp/assert.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef __EVHTP_ASSERT_H__ -#define __EVHTP_ASSERT_H__ - -#define evhtp_assert(x) \ - do { \ - if (evhtp_unlikely(!(x))) { \ - fprintf(stderr, "Assertion failed: %s (%s:%s:%d)\n", # x, \ - __func__, __FILE__, __LINE__); \ - fflush(stderr); \ - abort(); \ - } \ - } while (0) - -#define evhtp_alloc_assert(x) \ - do { \ - if (evhtp_unlikely(!x)) { \ - fprintf(stderr, "Out of memory (%s:%s:%d)\n", \ - __func__, __FILE__, __LINE__); \ - fflush(stderr); \ - abort(); \ - } \ - } while (0) - -#define evhtp_assert_fmt(x, fmt, ...) \ - do { \ - if (evhtp_unlikely(!(x))) { \ - fprintf(stderr, "Assertion failed: %s (%s:%s:%d) " fmt "\n", \ - # x, __func__, __FILE__, __LINE__, __VA_ARGS__); \ - fflush(stderr); \ - abort(); \ - } \ - } while (0) - -#define evhtp_errno_assert(x) \ - do { \ - if (evhtp_unlikely(!(x))) { \ - fprintf(stderr, "%s [%d] (%s:%s:%d)\n", \ - strerror(errno), errno, \ - __func__, __FILE__, __LINE__); \ - fflush(stderr); \ - abort(); \ - } \ - } while (0) - - -#endif diff --git a/include/evhtp/evhtp.h b/include/evhtp/evhtp.h index 9a66755..29f909f 100644 --- a/include/evhtp/evhtp.h +++ b/include/evhtp/evhtp.h @@ -3,7 +3,6 @@ */ #include -#include #ifndef __EVHTP__H__ #define __EVHTP__H__ diff --git a/include/evhtp/log.h b/include/evhtp/log.h new file mode 100644 index 0000000..bf23970 --- /dev/null +++ b/include/evhtp/log.h @@ -0,0 +1,35 @@ +#ifndef __EVHTP_LOG_H__ +#define __EVHTP_LOG_H__ + + +/** + * @brief create a new request-logging context with the format string `format` + * @note The following variable definitions are treated as special in the + * format: + * $ua - the user-agent + * $path - the requested path + * $rhost - the IP address of the request + * $meth - the HTTP method + * $ts - timestamp + * $proto - HTTP proto version + * $status - the return status + * $ref - the HTTP referrer + * $host - either the vhost (if defined) or the value of the Host: header + * All other characters are treated as-is. + * + * @param format - format string (see above) + */ +EVHTP_EXPORT void * evhtp_log_new(const char * format); + + +/** + * @brief log a HTTP request to a FILE using a compiled format. + * + * @param log - The compiled format (see evhtp_log_new) + * @param request + * @param fp + */ +EVHTP_EXPORT void evhtp_log_request_f(void * log, evhtp_request_t * request, FILE * fp); + +#endif + diff --git a/include/evhtp/logutils.h b/include/evhtp/logutils.h deleted file mode 100644 index 77b99ca..0000000 --- a/include/evhtp/logutils.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __EVHTP_LOGUTILS_H__ -#define __EVHTP_LOGUTILS_H__ - -EVHTP_EXPORT void * htp_logutil_new(const char * format); -EVHTP_EXPORT void htp_log_request(void * logutil, FILE * fp, evhtp_request_t * request); - -#endif - diff --git a/include/internal.h b/include/internal.h index 8ca5627..9a72718 100644 --- a/include/internal.h +++ b/include/internal.h @@ -26,6 +26,103 @@ extern "C" { #endif +#define __FILENAME__ \ + (strrchr(__FILE__, '/') ? \ + strrchr(__FILE__, '/') + 1 : __FILE__) + +#define clean_errno() \ + (errno == 0 ? "None" : strerror(errno)) + +#define __log_debug_color(X) "[\x1b[1;36m" X "\x1b[0;39m]" +#define __log_error_color(X) "[\x1b[1;31m" X "\x1b[0;39m]" +#define __log_warn_color(X) "[\x1b[1;33m" X "\x1b[0;39m]" +#define __log_info_color(X) "[\x1b[32m" X "\x1b[0;39m]" +#define __log_func_color(X) "\x1b[33m" X "\x1b[39m" +#define __log_args_color(X) "\x1b[94m" X "\x1b[39m" +#define __log_errno_color(X) "\x1b[35m" X "\x1b[39m" + + +#if !defined(EVHTP_DEBUG) +/* compile with all debug messages removed */ +#define log_debug(M, ...) +#else +#define log_debug(M, ...) \ + fprintf(stderr, __log_debug_color("DEBUG") " " \ + __log_func_color("%s/%s:%-9d") \ + __log_args_color(M) \ + "\n", \ + __FILENAME__, __FUNCTION__, __LINE__, ## __VA_ARGS__) +#endif + +#define log_error(M, ...) \ + fprintf(stderr, __log_error_color("ERROR") " " \ + __log_func_color("%s:%-9d") \ + __log_args_color(M) \ + " :: " \ + __log_errno_color("(errno: %s)") \ + "\n", \ + __FILENAME__, __LINE__, ## __VA_ARGS__, clean_errno()) + + +#define log_warn(M, ...) \ + fprintf(stderr, __log_warn_color("WARN") " " \ + __log_func_color("%s:%-9d") \ + __log_args_color(M) \ + " :: " \ + __log_errno_color("(errno: %s)") \ + "\n", \ + __FILENAME__, __LINE__, ## __VA_ARGS__, clean_errno()) + +#define log_info(M, ...) \ + fprintf(stderr, __log_info_color("INFO") " " \ + __log_func_color("%4s:%-9d") \ + __log_args_color(M) "\n", \ + __FILENAME__, __LINE__, ## __VA_ARGS__) + +#define evhtp_assert(x) \ + do { \ + if (evhtp_unlikely(!(x))) { \ + fprintf(stderr, "Assertion failed: %s (%s:%s:%d)\n", # x, \ + __func__, __FILE__, __LINE__); \ + fflush(stderr); \ + abort(); \ + } \ + } while (0) + +#define evhtp_alloc_assert(x) \ + do { \ + if (evhtp_unlikely(!x)) { \ + fprintf(stderr, "Out of memory (%s:%s:%d)\n", \ + __func__, __FILE__, __LINE__); \ + fflush(stderr); \ + abort(); \ + } \ + } while (0) + +#define evhtp_assert_fmt(x, fmt, ...) \ + do { \ + if (evhtp_unlikely(!(x))) { \ + fprintf(stderr, "Assertion failed: %s (%s:%s:%d) " fmt "\n", \ + # x, __func__, __FILE__, __LINE__, __VA_ARGS__); \ + fflush(stderr); \ + abort(); \ + } \ + } while (0) + +#define evhtp_errno_assert(x) \ + do { \ + if (evhtp_unlikely(!(x))) { \ + fprintf(stderr, "%s [%d] (%s:%s:%d)\n", \ + strerror(errno), errno, \ + __func__, __FILE__, __LINE__); \ + fflush(stderr); \ + abort(); \ + } \ + } while (0) + + + + #ifdef __cplusplus } #endif diff --git a/log.c b/log.c new file mode 100644 index 0000000..0455283 --- /dev/null +++ b/log.c @@ -0,0 +1,300 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "evhtp/evhtp.h" +#include "evhtp/log.h" + +typedef enum { + HTP_LOG_OP_USERAGENT = 1, + HTP_LOG_OP_PATH, + HTP_LOG_OP_RHOST, + HTP_LOG_OP_METHOD, + HTP_LOG_OP_TIMESTAMP, + HTP_LOG_OP_PROTO, + HTP_LOG_OP_STATUS, + HTP_LOG_OP_REFERRER, + HTP_LOG_OP_HOST, + HTP_LOG_OP_HEADER, + HTP_LOG_OP_PRINTABLE +} htp_log_op_type; + + +struct { + char * fmt_; + htp_log_op_type type_; +} op_type_strmap_[] = { + { "$ua", HTP_LOG_OP_USERAGENT }, + { "$path", HTP_LOG_OP_PATH }, + { "$rhost", HTP_LOG_OP_RHOST }, + { "$meth", HTP_LOG_OP_METHOD }, + { "$ts", HTP_LOG_OP_TIMESTAMP }, + { "$proto", HTP_LOG_OP_PROTO }, + { "$status", HTP_LOG_OP_STATUS }, + { "$ref", HTP_LOG_OP_REFERRER }, + { "$host", HTP_LOG_OP_HOST }, + { "$hdr::", HTP_LOG_OP_HEADER }, + { NULL, HTP_LOG_OP_PRINTABLE } +}; + + +#define HTP_LOG_OP_TAGSZ 1024 + +struct htp_log_op { + htp_log_op_type type; + size_t len; + char tag[HTP_LOG_OP_TAGSZ]; + + TAILQ_ENTRY(htp_log_op) next; +}; + +TAILQ_HEAD(htp_log_format, htp_log_op); + +htp_log_op_type +htp_log_str_to_op_type_(const char * fmt, int * arglen) +{ + int i; + + for (i = 0; op_type_strmap_[i].fmt_; i++) { + const char * fmt_ = op_type_strmap_[i].fmt_; + htp_log_op_type type_ = op_type_strmap_[i].type_; + + if (!strncasecmp(fmt_, fmt, strlen(fmt_))) { + *arglen = strlen(fmt_); + + return type_; + } + } + + return 0; +} + +static struct htp_log_format * +htp_log_format_new_(void) +{ + struct htp_log_format * format; + + format = calloc(1, sizeof(*format)); + TAILQ_INIT(format); + + return format; +} + +static struct htp_log_op * +htp_log_op_new_(htp_log_op_type type) +{ + struct htp_log_op * op; + + op = calloc(1, sizeof(*op)); + op->type = type; + + return op; +} + +/** + * @brief [debug] print the psuedo-stack + * + * @param stack + */ +static void +dump_(struct htp_log_format * format) +{ + struct htp_log_op * op; + + TAILQ_FOREACH(op, format, next) { + switch (op->type) { + case HTP_LOG_OP_USERAGENT: + printf("$ua"); + break; + case HTP_LOG_OP_PATH: + printf("$path"); + break; + case HTP_LOG_OP_METHOD: + printf("$meth"); + break; + case HTP_LOG_OP_TIMESTAMP: + printf("$ts"); + break; + case HTP_LOG_OP_REFERRER: + printf("$ref"); + break; + case HTP_LOG_OP_RHOST: + printf("$rhost"); + break; + case HTP_LOG_OP_STATUS: + printf("$status"); + break; + case HTP_LOG_OP_HOST: + printf("$host"); + break; + case HTP_LOG_OP_HEADER: + printf("$hdr::"); + break; + case HTP_LOG_OP_PROTO: + printf("$proto"); + break; + case HTP_LOG_OP_PRINTABLE: + printf("%s", op->tag); + break; + } /* switch */ + } + + printf("\n"); +} /* log_format_dump_ */ + +static void +htp_log_format_addchar_(struct htp_log_format * format, const char c) +{ + struct htp_log_op * op; + + if (TAILQ_EMPTY(format)) { + /* the format op stack is empty, we want to allocate a new one */ + op = NULL; + } else { + /* reuse the last format op, appending the character */ + op = TAILQ_LAST(format, htp_log_format); + } + + if (op == NULL || op->type != HTP_LOG_OP_PRINTABLE) { + /* the last op in the format stack was not a type of PRINTABLE or + * NULL, so allocate a new one. + */ + op = htp_log_op_new_(HTP_LOG_OP_PRINTABLE); + + /* insert the newly allocated stack_ent into the stack */ + TAILQ_INSERT_TAIL(format, op, next); + } + + /* append the character to the stack_ent */ + op->tag[op->len++] = c; + op->tag[op->len] = '\0'; +} + +#define IS_FMTVAR(X) (*X == '$' && *(X + 1) != '$') + +/** + * @brief using an input string, create a stack of information that will be + * logged. + * + * @param fmt + * + * @return + */ +static struct htp_log_format * +htp_log_format_compile_(const char * strfmt) +{ + const char * strp; + struct htp_log_format * format; + + format = htp_log_format_new_(); + + for (strp = strfmt; *strp != '\0'; strp++) { + struct htp_log_op * op; + + /* if the character is a format variable ($var), + * then create a new stack entry, and insert it + * into the stack. Otherwise append the character + * to the last stack entry + */ + if (IS_FMTVAR(strp)) { + int arglen; + + op = htp_log_op_new_(htp_log_str_to_op_type_(strp, &arglen)); + strp += arglen - 1; + + TAILQ_INSERT_TAIL(format, op, next); + } else { + htp_log_format_addchar_(format, *strp); + } + } + + return format; +} + +void * +evhtp_log_new(const char * fmtstr) +{ + return htp_log_format_compile_(fmtstr); +} + +void +evhtp_log_request_f(void * format_p, evhtp_request_t * request, FILE * fp) +{ + struct htp_log_format * format = format_p; + struct htp_log_op * op; + struct timeval tv; + struct tm * tm; + struct sockaddr_in * sin; + char tmp[64]; + + TAILQ_FOREACH(op, format, next) { + const char * logstr = NULL; + + switch (op->type) { + case HTP_LOG_OP_USERAGENT: + logstr = evhtp_header_find(request->headers_in, "user-agent"); + + break; + case HTP_LOG_OP_PATH: + if (request->uri && request->uri->path && request->uri->path->full) { + logstr = request->uri->path->full; + } + + break; + case HTP_LOG_OP_METHOD: + if (request->conn->parser) { + logstr = htparser_get_methodstr(request->conn->parser); + } + + break; + case HTP_LOG_OP_TIMESTAMP: + event_base_gettimeofday_cached(request->conn->evbase, &tv); + + tm = localtime(&tv.tv_sec); + strftime(tmp, sizeof(tmp), "%d/%b/%Y:%X %z", tm); + logstr = tmp; + + break; + case HTP_LOG_OP_REFERRER: + logstr = evhtp_header_find(request->headers_in, "referer"); + + break; + case HTP_LOG_OP_RHOST: + sin = (struct sockaddr_in *)request->conn->saddr; + + evutil_inet_ntop(AF_INET, &sin->sin_addr, tmp, sizeof(tmp)); + logstr = tmp; + + break; + case HTP_LOG_OP_STATUS: + fprintf(fp, "%d", evhtp_request_status(request)); + + continue; + case HTP_LOG_OP_HOST: + logstr = + request->htp->server_name ? : evhtp_header_find(request->headers_in, "host"); + + break; + case HTP_LOG_OP_PROTO: + logstr = evhtp_request_get_proto(request) == EVHTP_PROTO_11 ? "1.1" : "1.0"; + + break; + case HTP_LOG_OP_HEADER: + /* not implemented yet - fallthrough */ + case HTP_LOG_OP_PRINTABLE: + logstr = op->tag; + + break; + } /* switch */ + + fputs(logstr ? : "-", fp); + } + + fputc('\n', fp); +} /* evhtp_log_request_f */ diff --git a/log.h b/log.h deleted file mode 100644 index 979c3b8..0000000 --- a/log.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include -#include -#include - -#define __FILENAME__ \ - (strrchr(__FILE__, '/') ? \ - strrchr(__FILE__, '/') + 1 : __FILE__) - -#define clean_errno() \ - (errno == 0 ? "None" : strerror(errno)) - -#define __log_debug_color(X) "[\x1b[1;36m" X "\x1b[0;39m]" -#define __log_error_color(X) "[\x1b[1;31m" X "\x1b[0;39m]" -#define __log_warn_color(X) "[\x1b[1;33m" X "\x1b[0;39m]" -#define __log_info_color(X) "[\x1b[32m" X "\x1b[0;39m]" -#define __log_func_color(X) "\x1b[33m" X "\x1b[39m" -#define __log_args_color(X) "\x1b[94m" X "\x1b[39m" -#define __log_errno_color(X) "\x1b[35m" X "\x1b[39m" - - -#if !defined(EVHTP_DEBUG) -/* compile with all debug messages removed */ -#define log_debug(M, ...) -#else -#define log_debug(M, ...) \ - fprintf(stderr, __log_debug_color("DEBUG") " " \ - __log_func_color("%s/%s:%-9d") \ - __log_args_color(M) \ - "\n", \ - __FILENAME__, __FUNCTION__, __LINE__, ## __VA_ARGS__) -#endif - -#define log_error(M, ...) \ - fprintf(stderr, __log_error_color("ERROR") " " \ - __log_func_color("%s:%-9d") \ - __log_args_color(M) \ - " :: " \ - __log_errno_color("(errno: %s)") \ - "\n", \ - __FILENAME__, __LINE__, ## __VA_ARGS__, clean_errno()) - - -#define log_warn(M, ...) \ - fprintf(stderr, __log_warn_color("WARN") " " \ - __log_func_color("%s:%-9d") \ - __log_args_color(M) \ - " :: " \ - __log_errno_color("(errno: %s)") \ - "\n", \ - __FILENAME__, __LINE__, ## __VA_ARGS__, clean_errno()) - -#define log_info(M, ...) \ - fprintf(stderr, __log_info_color("INFO") " " \ - __log_func_color("%4s:%-9d") \ - __log_args_color(M) "\n", \ - __FILENAME__, __LINE__, ## __VA_ARGS__) diff --git a/logutils.c b/logutils.c deleted file mode 100644 index c6b2205..0000000 --- a/logutils.c +++ /dev/null @@ -1,363 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "evhtp/evhtp.h" - -typedef enum { - vartype__USERAGENT = 1, - vartype__PATH, - vartype__RHOST, - vartype__METHOD, - vartype__TIMESTAMP, - vartype__PROTO, - vartype__STATUS, - vartype__REFERRER, - vartype__HOST, - vartype__HEADER, - vartype__PRINTABLE -} log_entry_type; - - -struct { - char * fmt_; - log_entry_type type_; -} var_type_map_[] = { - { "$ua", vartype__USERAGENT }, - { "$path", vartype__PATH }, - { "$rhost", vartype__RHOST }, - { "$meth", vartype__METHOD }, - { "$ts", vartype__TIMESTAMP }, - { "$proto", vartype__PROTO }, - { "$status", vartype__STATUS }, - { "$ref", vartype__REFERRER }, - { "$host", vartype__HOST }, - { "$hdr::", vartype__HEADER }, - { NULL, vartype__PRINTABLE } -}; - - -/** - * @brief an entry representing a single format type. - */ -struct log_stack_entry { - log_entry_type type; - size_t len; - char tag[1024]; - - TAILQ_ENTRY(log_stack_entry) next; -}; - - -struct log_stack; - -/** - * @brief the stack containing one or more log_stack_entry's - */ -TAILQ_HEAD(log_stack, log_stack_entry); - - -/** - * @brief convert the current $value to an internal type enum - * - * @param fmt - * @param arglen - * - * @return - */ -log_entry_type -str_to_entry_type_(const char * fmt, int * arglen) -{ - int i; - - for (i = 0; var_type_map_[i].fmt_; i++) { - const char * fmt_ = var_type_map_[i].fmt_; - log_entry_type type_ = var_type_map_[i].type_; - - if (!strncasecmp(fmt_, fmt, strlen(fmt_))) { - *arglen = strlen(fmt_); - - return type_; - } - } - - return 0; -} - -static struct log_stack * -log_stack__new_(void) -{ - struct log_stack * stack; - - stack = calloc(sizeof(struct log_stack), 1); - assert(stack != NULL); - - TAILQ_INIT(stack); - - return stack; -} - -static struct log_stack_entry * -log_stack_entry__new_(log_entry_type type) -{ - struct log_stack_entry * e; - - e = calloc(sizeof(*e), 1); - assert(e != NULL); - - e->type = type; - - return e; -} - -/** - * @brief [debug] print the psuedo-stack - * - * @param stack - */ -static void -log_stack__dump_(struct log_stack * stack) -{ - struct log_stack_entry * entry; - - TAILQ_FOREACH(entry, stack, next) { - switch (entry->type) { - case vartype__USERAGENT: - printf("$ua"); - break; - case vartype__PATH: - printf("$path"); - break; - case vartype__METHOD: - printf("$meth"); - break; - case vartype__TIMESTAMP: - printf("$ts"); - break; - case vartype__REFERRER: - printf("$ref"); - break; - case vartype__RHOST: - printf("$rhost"); - break; - case vartype__STATUS: - printf("$status"); - break; - case vartype__HOST: - printf("$host"); - break; - case vartype__HEADER: - printf("$hdr::"); - break; - case vartype__PROTO: - printf("$proto"); - break; - case vartype__PRINTABLE: - printf("%s", entry->tag); - break; - } /* switch */ - } - - printf("\n"); -} /* log_stack__dump_ */ - -/** - * @brief add raw strings to the compiled format stack - * if the tag-stack is empty, or if the type if printable, - * create a new stack entry, and insert it. Otherwise just - * append the data to the last stack entry. - * - * @param stack - * @param c - */ -static void -log_stack__addchar_(struct log_stack * stack, const char c) -{ - struct log_stack_entry * stack_ent; - - if (TAILQ_EMPTY(stack)) { - /* the stack is empty, we want to allocate a new one */ - stack_ent = NULL; - } else { - /* reuse the last stack entry, appending the character */ - stack_ent = TAILQ_LAST(stack, log_stack); - } - - /* if the last entry in the stack_ent was not a type of PRINTABLE, or - * the stack_ent is NULL, allocate a new one. - */ - if (stack_ent == NULL || stack_ent->type != vartype__PRINTABLE) { - stack_ent = log_stack_entry__new_(vartype__PRINTABLE); - assert(stack_ent != NULL); - - /* insert the newly allocated stack_ent into the stack */ - TAILQ_INSERT_TAIL(stack, stack_ent, next); - } - - /* append the character to the stack_ent */ - stack_ent->tag[stack_ent->len++] = c; - stack_ent->tag[stack_ent->len] = '\0'; -} - -#define IS_FMTVAR(X) (*X == '$' && *(X + 1) != '$') - -/** - * @brief using an input string, create a stack of information that will be - * logged. - * - * @param fmt - * - * @return - */ -static struct log_stack * -log_stack__compile_(const char * fmt) -{ - const char * strp; - struct log_stack * stack; - - stack = log_stack__new_(); - - for (strp = fmt; *strp != '\0'; strp++) { - struct log_stack_entry * stack_ent; - - /* if the character is a format variable ($var), - * then create a new stack entry, and insert it - * into the stack. Otherwise append the character - * to the last stack entry - */ - if (IS_FMTVAR(strp)) { - int arglen; - log_entry_type type; - - type = str_to_entry_type_(strp, &arglen); - assert(type != 0); - - stack_ent = log_stack_entry__new_(type); - assert(stack_ent != NULL); - - TAILQ_INSERT_TAIL(stack, stack_ent, next); - - strp += arglen - 1; - } else { - log_stack__addchar_(stack, *strp); - } - } - - return stack; -} - -void * -htp_logutil_new(const char * fmt) -{ - struct log_stack * stack; - - stack = log_stack__compile_(fmt); - assert(stack != NULL); - - return (void *)stack; -} - -void -htp_log_request(void * stack_p, FILE * fp, evhtp_request_t * request) -{ - struct log_stack * stack = stack_p; - struct log_stack_entry * ent; - const char * hdr; - - assert(stack != NULL); - assert(request != NULL); - - TAILQ_FOREACH(ent, stack, next) { - switch (ent->type) { - case vartype__USERAGENT: - hdr = evhtp_header_find(request->headers_in, "user-agent"); - - if (hdr == NULL) { - hdr = "-"; - } - - fprintf(fp, "%s", hdr); - break; - case vartype__PATH: - if (request->uri && request->uri->path && request->uri->path->full) { - fprintf(fp, "%s", request->uri->path->full); - } else { - fprintf(fp, "-"); - } - - break; - case vartype__METHOD: - fprintf(fp, "%s", htparser_get_methodstr(request->conn->parser)); - break; - case vartype__TIMESTAMP: - { - struct timeval tv; - struct tm * tm; - char fmt[64]; - - event_base_gettimeofday_cached(request->conn->evbase, &tv); - tm = localtime(&tv.tv_sec); - - strftime(fmt, sizeof(fmt), "%d/%b/%Y:%X %z", tm); - - fprintf(fp, "%s", fmt); - } - - break; - case vartype__REFERRER: - hdr = evhtp_header_find(request->headers_in, "referer"); - - if (hdr == NULL) { - hdr = "-"; - } - - - fprintf(fp, "%s", hdr); - break; - case vartype__RHOST: - { - char tmp[64]; - - struct sockaddr_in * sin = (struct sockaddr_in *)request->conn->saddr; - - evutil_inet_ntop(AF_INET, &sin->sin_addr, tmp, sizeof(tmp)); - - fprintf(fp, "%s", tmp); - } - break; - case vartype__STATUS: - fprintf(fp, "%d", evhtp_request_status(request)); - break; - case vartype__HOST: - if (request->htp->server_name) { - hdr = request->htp->server_name; - } else { - hdr = evhtp_header_find(request->headers_in, "host"); - - if (hdr == NULL) { - hdr = "-"; - } - } - - fprintf(fp, "%s", hdr); - - break; - case vartype__HEADER: - fprintf(fp, "$hdr::"); - break; - case vartype__PROTO: - fprintf(fp, "%s", - evhtp_request_get_proto(request) == EVHTP_PROTO_11 ? "1.1" : "1.0"); - break; - case vartype__PRINTABLE: - fprintf(fp, "%s", ent->tag); - break; - } /* switch */ - } - - fprintf(fp, "\n"); -} /* htp_log_request */ diff --git a/parser.c b/parser.c index f86bfc0..a4e3d78 100644 --- a/parser.c +++ b/parser.c @@ -1,11 +1,11 @@ #include #include #include +#include #include "internal.h" #include "evhtp/parser.h" #include "evhtp/config.h" -#include "log.h" #if '\n' != '\x0a' || 'A' != 65 #error "You have somehow found a non-ASCII host. We can't build here."