From 321e9c0b8091702f8ce359dec708c55ce0f9e4b0 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Mon, 12 Feb 2024 13:32:14 +0100 Subject: [PATCH 1/3] feat: improve request header api functions --- include/lnm/http/req.h | 40 ++++++++++++++++++++++---------- src/http/lnm_http_loop_process.c | 9 ++++--- src/http/lnm_http_loop_steps.c | 10 ++++---- src/http/lnm_http_req.c | 19 ++++++++------- 4 files changed, 47 insertions(+), 31 deletions(-) diff --git a/include/lnm/http/req.h b/include/lnm/http/req.h index 06f2743..a62365a 100644 --- a/include/lnm/http/req.h +++ b/include/lnm/http/req.h @@ -13,7 +13,11 @@ #define LNM_HTTP_MAX_REQ_HEADERS 32 #define LNM_HTTP_MAX_REGEX_GROUPS 4 -typedef struct lnm_http_req_header { +/** + * Internal representation of a header in a request, defined using offsets + * relative to the full buffer. + */ +typedef struct lnm_http_req_iheader { struct { size_t o; size_t len; @@ -22,6 +26,20 @@ typedef struct lnm_http_req_header { size_t o; size_t len; } value; +} lnm_http_req_iheader; + +/** + * Represents an actual header value, with offsets already resolved. + */ +typedef struct lnm_http_req_header { + struct { + const char *s; + size_t len; + } name; + struct { + const char *s; + size_t len; + } value; } lnm_http_req_header; /** @@ -45,7 +63,7 @@ typedef struct lnm_http_req { size_t len; } query; struct { - lnm_http_req_header arr[LNM_HTTP_MAX_REQ_HEADERS]; + lnm_http_req_iheader arr[LNM_HTTP_MAX_REQ_HEADERS]; size_t len; } headers; struct { @@ -81,31 +99,29 @@ 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. + * Retrieve a known type header from the request. * * Pointers retrieved from this function should never be used between step * functions; simply request the header again if you need to. * - * @param out where to write pointer to header value - * @param out_len where to store length of out value + * @param out where to store pointer to struct representing header * @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); +lnm_err lnm_http_req_header_get(lnm_http_req_header *out, lnm_http_req *req, + lnm_http_header type); /** - * Retrieve a specific header from the request by specifying its name. + * Retrieve a header from the request using a case-insensitive name. * * Pointers retrieved from this function should never be used between step * functions; simply request the header again if you need to. * - * @param out where to write pointer to header value - * @param out_len where to store length of out value + * @param out where to store pointer to struct representing header * @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); +lnm_err lnm_http_req_header_get_s(lnm_http_req_header *out, lnm_http_req *req, + const char *name); #endif diff --git a/src/http/lnm_http_loop_process.c b/src/http/lnm_http_loop_process.c index e16e18c..b7918a6 100644 --- a/src/http/lnm_http_loop_process.c +++ b/src/http/lnm_http_loop_process.c @@ -113,11 +113,10 @@ void lnm_http_loop_process_parse_headers(lnm_http_conn *conn) { lnm_http_loop_ctx *ctx = conn->ctx; lnm_http_req *req = &ctx->req; - 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->body.expected_len = lnm_atoi(value, value_len); + lnm_http_req_header header; + if (lnm_http_req_header_get(&header, req, lnm_http_header_content_length) == + lnm_err_ok) { + req->body.expected_len = lnm_atoi(header.value.s, header.value.len); } ctx->state = lnm_http_loop_state_steps; diff --git a/src/http/lnm_http_loop_steps.c b/src/http/lnm_http_loop_steps.c index 2552e09..6819986 100644 --- a/src/http/lnm_http_loop_steps.c +++ b/src/http/lnm_http_loop_steps.c @@ -30,13 +30,13 @@ lnm_http_step_err lnm_http_loop_step_auth(lnm_http_conn *conn) { // If there's no API key, requests are always authorized bool authorized = ctx->g->api_key == NULL; - const char *value; - size_t value_len; + lnm_http_req_header header; - if (!authorized && lnm_http_req_header_get_s(&value, &value_len, &ctx->req, + if (!authorized && lnm_http_req_header_get_s(&header, &ctx->req, "X-Api-Key") == lnm_err_ok) { - authorized = (value_len == strlen(ctx->g->api_key)) && - (memcmp(value, ctx->g->api_key, value_len) == 0); + authorized = + (header.value.len == strlen(ctx->g->api_key)) && + (memcmp(header.value.s, ctx->g->api_key, header.value.len) == 0); } ctx->res.status = authorized ? ctx->res.status : lnm_http_status_unauthorized; diff --git a/src/http/lnm_http_req.c b/src/http/lnm_http_req.c index 50be3af..4609ad3 100644 --- a/src/http/lnm_http_req.c +++ b/src/http/lnm_http_req.c @@ -88,23 +88,24 @@ 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(lnm_http_req_header *out, lnm_http_req *req, + lnm_http_header type) { + return lnm_http_req_header_get_s(out, 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) { +lnm_err lnm_http_req_header_get_s(lnm_http_req_header *out, lnm_http_req *req, + const char *name) { size_t name_len = strlen(name); for (size_t i = 0; i < req->headers.len; i++) { - const lnm_http_req_header *header = &req->headers.arr[i]; + const lnm_http_req_iheader *header = &req->headers.arr[i]; if (lnm_strnieq(req->buf.s + header->name.o, header->name.len, name, name_len)) { - *out = req->buf.s + header->value.o; - *out_len = header->value.len; + out->name.s = req->buf.s + header->name.o; + out->name.len = header->name.len; + out->value.s = req->buf.s + header->value.o; + out->value.len = header->value.len; return lnm_err_ok; } From 5b612127b2a196cc5707bf45ebddf7ba5613e814 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Mon, 12 Feb 2024 13:40:56 +0100 Subject: [PATCH 2/3] feat: rename some structs --- include/lnm/http/req.h | 66 +++++++++++++++++++++++--------- src/http/lnm_http_loop_process.c | 2 +- src/http/lnm_http_loop_steps.c | 2 +- src/http/lnm_http_req.c | 6 +-- 4 files changed, 52 insertions(+), 24 deletions(-) diff --git a/include/lnm/http/req.h b/include/lnm/http/req.h index a62365a..d2070b4 100644 --- a/include/lnm/http/req.h +++ b/include/lnm/http/req.h @@ -17,7 +17,7 @@ * Internal representation of a header in a request, defined using offsets * relative to the full buffer. */ -typedef struct lnm_http_req_iheader { +typedef struct lnm_http_req_ihdr { struct { size_t o; size_t len; @@ -26,21 +26,7 @@ typedef struct lnm_http_req_iheader { size_t o; size_t len; } value; -} lnm_http_req_iheader; - -/** - * Represents an actual header value, with offsets already resolved. - */ -typedef struct lnm_http_req_header { - struct { - const char *s; - size_t len; - } name; - struct { - const char *s; - size_t len; - } value; -} lnm_http_req_header; +} lnm_http_req_ihhr; /** * Represents the parsed HTTP request @@ -63,7 +49,7 @@ typedef struct lnm_http_req { size_t len; } query; struct { - lnm_http_req_iheader arr[LNM_HTTP_MAX_REQ_HEADERS]; + lnm_http_req_ihhr arr[LNM_HTTP_MAX_REQ_HEADERS]; size_t len; } headers; struct { @@ -98,6 +84,20 @@ 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); +/** + * Represents an actual header value, with offsets already resolved. + */ +typedef struct lnm_http_req_hdr { + struct { + const char *s; + size_t len; + } name; + struct { + const char *s; + size_t len; + } value; +} lnm_http_req_hdr; + /** * Retrieve a known type header from the request. * @@ -108,7 +108,7 @@ void lnm_http_req_reset(lnm_http_req *req); * @param req request to look for header in * @param type type of header to look for */ -lnm_err lnm_http_req_header_get(lnm_http_req_header *out, lnm_http_req *req, +lnm_err lnm_http_req_header_get(lnm_http_req_hdr *out, lnm_http_req *req, lnm_http_header type); /** @@ -121,7 +121,35 @@ lnm_err lnm_http_req_header_get(lnm_http_req_header *out, lnm_http_req *req, * @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(lnm_http_req_header *out, lnm_http_req *req, +lnm_err lnm_http_req_header_get_s(lnm_http_req_hdr *out, lnm_http_req *req, const char *name); +/** + * Represents a parameter in an HTTP header. + */ +typedef struct lnm_http_req_hdr_param { + struct { + const char *s; + size_t len; + } key; + struct { + const char *s; + size_t len; + } value; +} lnm_http_req_hdr_param; + +/** + * Retrieve a specific key-value parameter from a header. + * + * Pointers retrieved from this function should never be used between step + * functions; simply request the header again if you need to. + * + * @param out output struct + * @param header header to look in + * @param key name of the parameter to return from the header + */ +lnm_err lnm_http_req_header_param(lnm_http_req_hdr_param *param, + const lnm_http_req_hdr *header, + const char *key); + #endif diff --git a/src/http/lnm_http_loop_process.c b/src/http/lnm_http_loop_process.c index b7918a6..491be6c 100644 --- a/src/http/lnm_http_loop_process.c +++ b/src/http/lnm_http_loop_process.c @@ -113,7 +113,7 @@ void lnm_http_loop_process_parse_headers(lnm_http_conn *conn) { lnm_http_loop_ctx *ctx = conn->ctx; lnm_http_req *req = &ctx->req; - lnm_http_req_header header; + lnm_http_req_hdr header; if (lnm_http_req_header_get(&header, req, lnm_http_header_content_length) == lnm_err_ok) { req->body.expected_len = lnm_atoi(header.value.s, header.value.len); diff --git a/src/http/lnm_http_loop_steps.c b/src/http/lnm_http_loop_steps.c index 6819986..900422c 100644 --- a/src/http/lnm_http_loop_steps.c +++ b/src/http/lnm_http_loop_steps.c @@ -30,7 +30,7 @@ lnm_http_step_err lnm_http_loop_step_auth(lnm_http_conn *conn) { // If there's no API key, requests are always authorized bool authorized = ctx->g->api_key == NULL; - lnm_http_req_header header; + lnm_http_req_hdr header; if (!authorized && lnm_http_req_header_get_s(&header, &ctx->req, "X-Api-Key") == lnm_err_ok) { diff --git a/src/http/lnm_http_req.c b/src/http/lnm_http_req.c index 4609ad3..cc453b2 100644 --- a/src/http/lnm_http_req.c +++ b/src/http/lnm_http_req.c @@ -88,17 +88,17 @@ void lnm_http_req_reset(lnm_http_req *req) { memset(req, 0, sizeof(lnm_http_req)); } -lnm_err lnm_http_req_header_get(lnm_http_req_header *out, lnm_http_req *req, +lnm_err lnm_http_req_header_get(lnm_http_req_hdr *out, lnm_http_req *req, lnm_http_header type) { return lnm_http_req_header_get_s(out, req, lnm_http_header_names[type]); } -lnm_err lnm_http_req_header_get_s(lnm_http_req_header *out, lnm_http_req *req, +lnm_err lnm_http_req_header_get_s(lnm_http_req_hdr *out, lnm_http_req *req, const char *name) { size_t name_len = strlen(name); for (size_t i = 0; i < req->headers.len; i++) { - const lnm_http_req_iheader *header = &req->headers.arr[i]; + const lnm_http_req_ihhr *header = &req->headers.arr[i]; if (lnm_strnieq(req->buf.s + header->name.o, header->name.len, name, name_len)) { From 4a0df8db6bb78e6eb4885524c352184cc4ddf8c6 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Wed, 14 Feb 2024 10:35:17 +0100 Subject: [PATCH 3/3] wip --- include/lnm/common.h | 13 +++++++++++++ src/http/lnm_http_req.c | 12 ++++++++++++ src/lnm_utils.c | 16 ++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/include/lnm/common.h b/include/lnm/common.h index 8cc982e..95511cc 100644 --- a/include/lnm/common.h +++ b/include/lnm/common.h @@ -86,4 +86,17 @@ uint64_t lnm_atoi(const char *s, size_t len); */ uint64_t lnm_digits(uint64_t num); +/** + * Find the first case-insensitive occurence of s2 in s1. + * + * @param out pointer to store start of match in + * @param s1 pointer to string to look in + * @param s1_len length of s1 + * @param s2 string to search for in s1 + * @param s2_len length of s2 + * @return true if found, false otherwise + */ +bool lnm_stristr(const char **out, const char *s1, size_t s1_len, + const char *s2, size_t s2_len); + #endif diff --git a/src/http/lnm_http_req.c b/src/http/lnm_http_req.c index cc453b2..3d12fcb 100644 --- a/src/http/lnm_http_req.c +++ b/src/http/lnm_http_req.c @@ -113,3 +113,15 @@ lnm_err lnm_http_req_header_get_s(lnm_http_req_hdr *out, lnm_http_req *req, return lnm_err_not_found; } + +lnm_err lnm_http_req_header_param(lnm_http_req_hdr_param *param, + const lnm_http_req_hdr *header, + const char *key) { + size_t key_len = strlen(key); + + const char *s; + if (lnm_stristr(&s, header->name.s, header->name.len - 1, key, key_len) && (header->name.s[key_len] == '=')) { + // Value runs till end of header or next semi-colon + + } +} diff --git a/src/lnm_utils.c b/src/lnm_utils.c index 85094bd..b2c98ed 100644 --- a/src/lnm_utils.c +++ b/src/lnm_utils.c @@ -55,3 +55,19 @@ uint64_t lnm_digits(uint64_t num) { return digits; } + +bool lnm_stristr(const char **out, const char *s1, size_t s1_len, + const char *s2, size_t s2_len) { + while (s1_len >= s2_len) { + if (lnm_strnieq(s1, s1_len, s2, s2_len)) { + *out = s1; + + return true; + } + + s1_len--; + s1++; + } + + return false; +}