feat: improve request header api functions

Jef Roosens 2024-02-12 13:32:14 +01:00
parent 854e8c3809
commit 321e9c0b80
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
4 changed files with 47 additions and 31 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;
}