diff --git a/lnm/include/lnm/common.h b/lnm/include/lnm/common.h index 4dc789d..9c95d52 100644 --- a/lnm/include/lnm/common.h +++ b/lnm/include/lnm/common.h @@ -1,6 +1,10 @@ #ifndef LNM_COMMON #define LNM_COMMON +#include +#include +#include + #define LNM_RES(x) \ { \ lnm_err res = x; \ @@ -20,13 +24,14 @@ #define LNM_MIN(x, y) ((x) < (y) ? (x) : (y)) #define LNM_MAX(x, y) ((x) > (y) ? (x) : (y)) -typedef enum { +typedef enum lnm_err { lnm_err_ok = 0, lnm_err_failed_alloc, lnm_err_failed_network, lnm_err_failed_poll, lnm_err_not_setup, - lnm_err_bad_regex + lnm_err_bad_regex, + lnm_err_not_found, } lnm_err; typedef struct lnm_loop lnm_http_loop; @@ -37,4 +42,41 @@ typedef struct lnm_http_step lnm_http_step; typedef struct lnm_http_route lnm_http_route; +/** + * Returns whether the two strings are equal. + * + * @param s1 first string to compare + * @param s1_len length of `s1` + * @param s2 second string to compare + * @param s2_len length of `s2` + */ +bool lnm_strneq(const char *s1, size_t s1_len, const char *s2, size_t s2_len); + +/** + * Returns whether the two strings are equal, ignoring capitalisation. + * + * @param s1 first string to compare + * @param s1_len length of `s1` + * @param s2 second string to compare + * @param s2_len length of `s2` + */ +bool lnm_strnieq(const char *s1, size_t s1_len, const char *s2, size_t s2_len); + +/** + * Calculate integer exponentation. + * + * @param base + * @param power + */ +uint64_t lnm_ipow(uint64_t base, uint64_t power); + +/** + * Parse the given string into a number. + * + * @param s string to parse + * @param len length of s + * @return the parsed number, or 0 if the number is invalid + */ +uint64_t lnm_atoi(const char *s, size_t len); + #endif diff --git a/lnm/include/lnm/http/req.h b/lnm/include/lnm/http/req.h index 1eddb26..e43063c 100644 --- a/lnm/include/lnm/http/req.h +++ b/lnm/include/lnm/http/req.h @@ -2,10 +2,12 @@ #define LNM_HTTP_REQ #include +#include #include #include "picohttpparser.h" +#include "lnm/common.h" #include "lnm/http/consts.h" #define LNM_HTTP_MAX_REQ_HEADERS 32 @@ -31,6 +33,7 @@ typedef struct lnm_http_req { struct phr_header arr[LNM_HTTP_MAX_REQ_HEADERS]; size_t len; } headers; + uint64_t content_length; } lnm_http_req; typedef enum lnm_http_parse_err { @@ -57,4 +60,26 @@ lnm_http_parse_err lnm_http_req_parse(lnm_http_req *req, char *buf, size_t len); */ void lnm_http_req_reset(lnm_http_req *req); +/** + * Retrieve a specific header from the request. + * + * @param out where to write pointer to header value + * @param out_len where to store length of out value + * @param req request to look for header in + * @param type type of header to look for + */ +lnm_err lnm_http_req_header_get(const char **out, size_t *out_len, + lnm_http_req *req, lnm_http_header type); + +/** + * Retrieve a specific header from the request by specifying its name. + * + * @param out where to write pointer to header value + * @param out_len where to store length of out value + * @param req request to look for header in + * @param name name of the header; matches case-insensitive + */ +lnm_err lnm_http_req_header_get_s(const char **out, size_t *out_len, + lnm_http_req *req, const char *name); + #endif diff --git a/lnm/src/http/lnm_http_loop_process.c b/lnm/src/http/lnm_http_loop_process.c index 5952538..9090df2 100644 --- a/lnm/src/http/lnm_http_loop_process.c +++ b/lnm/src/http/lnm_http_loop_process.c @@ -91,8 +91,14 @@ void lnm_http_loop_process_route(lnm_http_conn *conn) { void lnm_http_loop_process_parse_headers(lnm_http_conn *conn) { lnm_http_loop_ctx *ctx = conn->ctx; + lnm_http_req *req = &ctx->req; - // TODO + const char *value; + size_t value_len; + if (lnm_http_req_header_get(&value, &value_len, req, + lnm_http_header_content_length) == lnm_err_ok) { + req->content_length = lnm_atoi(value, value_len); + } ctx->state = lnm_http_loop_state_steps; } @@ -134,6 +140,10 @@ void lnm_http_loop_process_write_status_line(lnm_http_conn *conn) { lnm_http_loop_ctx *ctx = conn->ctx; lnm_http_res *res = &ctx->res; + if (res->status == 0) { + res->status = lnm_http_status_ok; + } + const char *response_type_name = lnm_http_status_names[res->status / 100 - 1][res->status % 100]; diff --git a/lnm/src/http/lnm_http_req.c b/lnm/src/http/lnm_http_req.c index 33c522c..1588bcd 100644 --- a/lnm/src/http/lnm_http_req.c +++ b/lnm/src/http/lnm_http_req.c @@ -1,6 +1,7 @@ #include #include +#include "lnm/common.h" #include "lnm/http/consts.h" #include "lnm/http/loop.h" #include "lnm/http/req.h" @@ -60,3 +61,27 @@ lnm_http_parse_err lnm_http_req_parse(lnm_http_req *req, char *buf, void lnm_http_req_reset(lnm_http_req *req) { memset(req, 0, sizeof(lnm_http_req)); } + +lnm_err lnm_http_req_header_get(const char **out, size_t *out_len, + lnm_http_req *req, lnm_http_header type) { + return lnm_http_req_header_get_s(out, out_len, req, + lnm_http_header_names[type]); +} + +lnm_err lnm_http_req_header_get_s(const char **out, size_t *out_len, + lnm_http_req *req, const char *name) { + size_t name_len = strlen(name); + + for (size_t i = 0; i < req->headers.len; i++) { + const struct phr_header *header = &req->headers.arr[i]; + + if (lnm_strnieq(header->name, header->name_len, name, name_len)) { + *out = header->value; + *out_len = header->value_len; + + return lnm_err_ok; + } + } + + return lnm_err_not_found; +} diff --git a/lnm/src/lnm_utils.c b/lnm/src/lnm_utils.c new file mode 100644 index 0000000..ce60803 --- /dev/null +++ b/lnm/src/lnm_utils.c @@ -0,0 +1,45 @@ +#include +#include + +#include "lnm/common.h" + +bool lnm_strneq(const char *s1, size_t s1_len, const char *s2, size_t s2_len) { + return (s1_len == s2_len) && (memcmp(s1, s2, s1_len) == 0); +} + +bool lnm_strnieq(const char *s1, size_t s1_len, const char *s2, size_t s2_len) { + bool equal = s1_len == s2_len; + + for (size_t i = 0; i < s1_len && equal; i++) { + equal = s1[i] == s2[i] || + (('a' <= s1[i]) && (s1[i] <= 'z') && (s1[i] - 32 == s2[i])); + } + + return equal; +} + +uint64_t lnm_ipow(uint64_t base, uint64_t power) { + uint64_t res = 1; + + while (power > 0) { + res *= base; + power--; + } + + return res; +} + +uint64_t lnm_atoi(const char *s, size_t len) { + uint64_t res = 0; + + for (size_t i = 0; i < len; i++) { + if (s[i] < '0' || '9' < s[i]) { + return 0; + } + + uint64_t val = s[i] - '0'; + res += val * lnm_ipow(10, (len - 1) - i); + } + + return res; +}