diff --git a/lnm/Makefile b/lnm/Makefile index 78e1e0e..7371c9f 100644 --- a/lnm/Makefile +++ b/lnm/Makefile @@ -6,7 +6,7 @@ LIB := $(BUILD_DIR)/$(LIB_FILENAME) SRCS != find '$(SRC_DIR)' -iname '*.c' -SRCS_H != find $(INC_DIRS) -iname '*.h' +SRCS_H != find include -iname '*.h' SRCS_H_INTERNAL != find $(SRC_DIR) -iname '*.h' SRCS_TEST != find '$(TEST_DIR)' -iname '*.c' SRCS_THIRDPARTY != find '$(THIRDPARTY_DIR)/src' -iname '*.c' @@ -91,11 +91,11 @@ $(BUILD_DIR)/$(EXAMPLE_DIR)/%.c.o: $(EXAMPLE_DIR)/%.c # =====MAINTENANCE===== .PHONY: lint lint: - clang-format -n --Werror $(SRCS) $(SRCS_H) $(SRCS_H_INTERNAL) $(SRCS_EXAMPLE) + clang-format -n --Werror $(SRCS) $(SRCS_H) $(SRCS_H_INTERNAL) .PHONY: fmt fmt: - clang-format -i $(SRCS) $(SRCS_H) $(SRCS_H_INTERNAL) $(SRCS_EXAMPLE) + clang-format -i $(SRCS) $(SRCS_H) $(SRCS_H_INTERNAL) .PHONY: check check: diff --git a/lnm/include/lnm/common.h b/lnm/include/lnm/common.h index 1500d73..381b4c9 100644 --- a/lnm/include/lnm/common.h +++ b/lnm/include/lnm/common.h @@ -23,6 +23,7 @@ typedef enum { lnm_err_failed_network, lnm_err_failed_poll, lnm_err_not_setup, + lnm_err_bad_regex } lnm_err; #endif diff --git a/lnm/include/lnm/http/loop.h b/lnm/include/lnm/http/loop.h new file mode 100644 index 0000000..9b6f0d3 --- /dev/null +++ b/lnm/include/lnm/http/loop.h @@ -0,0 +1,70 @@ +#ifndef LNM_HTTP_LOOP +#define LNM_HTTP_LOOP + +#include "lnm/common.h" + +typedef struct lnm_loop lnm_http_loop; + +typedef struct lnm_http_conn lnm_http_conn; + +typedef struct lnm_http_step lnm_http_step; + +typedef struct lnm_http_route lnm_http_route; + +typedef lnm_err (*lnm_http_step_fn)(lnm_http_conn *conn); + +/** + * Initialize a new `lnm_http_loop`. + * + * @param out where to store pointer to new `lnm_http_loop` + */ +lnm_err lnm_http_loop_init(lnm_http_loop **out); + +/** + * Initialize a first step + * + * @param out where to store pointer to new `lnm_http_step` + * @param fn step function associated with the step + */ +lnm_err lnm_http_step_init(lnm_http_step **out, lnm_http_step_fn fn); + +/** + * Append the given step fn to the step. + * + * @param out where to store pointer to new `lnm_http_step` + * @param step step to append new step to + * @param fn step funcitonn + */ +lnm_err lnm_http_step_append(lnm_http_step **out, lnm_http_step *step, + lnm_http_step_fn fn); + +/** + * Initialize a new route of type literal. + * + * @param out where to store pointer to new `lnm_http_route` + * @param path literal path to match + * @param step step to process request with + */ +lnm_err lnm_http_route_init_literal(lnm_http_route **out, const char *path, + lnm_http_step *step); + +/** + * Initialize a new route of type regex. + * + * @param out where to store pointer to new `lnm_http_route` + * @param pattern regex pattern + * @param regex_group_count how many regex groups are contained in the pattern + * @param step step to process request with + */ +lnm_err lnm_http_route_init_regex(lnm_http_route **out, const char *pattern, + int regex_group_count, lnm_http_step *step); + +/** + * Add a new route to the HTTP route. + * + * @param hl HTTP loop to modify + * @param route route to add + */ +void lnm_http_loop_route_add(lnm_http_loop *hl, lnm_http_route *route); + +#endif diff --git a/lnm/include/lnm/loop.h b/lnm/include/lnm/loop.h index a3625c6..a84055a 100644 --- a/lnm/include/lnm/loop.h +++ b/lnm/include/lnm/loop.h @@ -30,7 +30,7 @@ typedef struct { } w; } lnm_loop_conn; -typedef struct { +typedef struct lnm_loop { int listen_fd; struct { lnm_loop_conn **arr; diff --git a/lnm/src/_include/lnm/http/loop_internal.h b/lnm/src/_include/lnm/http/loop_internal.h new file mode 100644 index 0000000..5d86a03 --- /dev/null +++ b/lnm/src/_include/lnm/http/loop_internal.h @@ -0,0 +1,34 @@ +#ifndef LNM_HTTP_LOOP_INTERNAL +#define LNM_HTTP_LOOP_INTERNAL + +#include + +#include "lnm/http/loop.h" + +typedef struct lnm_http_conn { + +} lnm_http_conn; + +typedef struct lnm_http_step { + lnm_http_step_fn fn; + struct lnm_http_step *next; +} lnm_http_step; + +typedef enum lnm_http_route_type { + lnm_http_route_type_literal = 0, + lnm_http_route_type_regex, +} lnm_http_route_type; + +typedef struct lnm_http_route { + union { + regex_t *regex; + const char *s; + } route; + lnm_http_route_type type; + int regex_group_count; + lnm_http_step *step; +} lnm_http_route; + +lnm_err lnm_http_route_init(lnm_http_route **out); + +#endif diff --git a/lnm/src/http/lnm_http_loop.c b/lnm/src/http/lnm_http_loop.c new file mode 100644 index 0000000..f082fe7 --- /dev/null +++ b/lnm/src/http/lnm_http_loop.c @@ -0,0 +1,86 @@ +#include + +#include "lnm/common.h" +#include "lnm/http/loop.h" +#include "lnm/http/loop_internal.h" +#include "lnm/loop_internal.h" + +lnm_err lnm_http_loop_init(lnm_http_loop **out) { + lnm_http_loop *hl = calloc(1, sizeof(lnm_http_loop)); + + if (hl == NULL) { + return lnm_err_failed_alloc; + } + + *out = hl; + + return lnm_err_ok; +} + +lnm_err lnm_http_step_init(lnm_http_step **out, lnm_http_step_fn fn) { + lnm_http_step *step = calloc(1, sizeof(lnm_http_step)); + + if (step == NULL) { + return lnm_err_failed_alloc; + } + + step->fn = fn; + *out = step; + + return lnm_err_ok; +} + +lnm_err lnm_http_step_append(lnm_http_step **out, lnm_http_step *step, + lnm_http_step_fn fn) { + LNM_RES(lnm_http_step_init(out, fn)); + + step->next = *out; + + return lnm_err_ok; +} + +lnm_err lnm_http_route_init(lnm_http_route **out) { + lnm_http_route *route = calloc(1, sizeof(lnm_http_route)); + + if (route == NULL) { + return lnm_err_failed_alloc; + } + + *out = route; + + return lnm_err_ok; +} + +lnm_err lnm_http_route_init_literal(lnm_http_route **out, const char *path, + lnm_http_step *step) { + LNM_RES(lnm_http_route_init(out)); + + (*out)->type = lnm_http_route_type_literal; + (*out)->route.s = path; + (*out)->step = step; + + return lnm_err_ok; +} + +lnm_err lnm_http_route_init_regex(lnm_http_route **out, const char *pattern, + int regex_group_count, lnm_http_step *step) { + regex_t *regex = calloc(1, sizeof(regex_t)); + + if (regex == NULL) { + return lnm_err_failed_alloc; + } + + if (regcomp(regex, pattern, REG_EXTENDED) != 0) { + free(regex); + return lnm_err_bad_regex; + } + + LNM_RES2(lnm_http_route_init(out), free(regex)); + + (*out)->type = lnm_http_route_type_regex; + (*out)->route.regex = regex; + (*out)->regex_group_count = regex_group_count; + (*out)->step = step; + + return lnm_err_ok; +}