diff --git a/include/lnm/common.h b/include/lnm/common.h index a21a439..6659af0 100644 --- a/include/lnm/common.h +++ b/include/lnm/common.h @@ -97,4 +97,16 @@ uint64_t lnm_digits(uint64_t num); */ bool lnm_is_ascii(const char *s); +/** + * Find the first case-insensitive occurence of s2 in s1. + * + * @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 pointer to start of matched string if found, or NULL otherwise + */ +const char *lnm_stristr(const char *s1, size_t s1_len, const char *s2, + size_t s2_len); + #endif diff --git a/include/lnm/http/req.h b/include/lnm/http/req.h index 885dead..c25cd0c 100644 --- a/include/lnm/http/req.h +++ b/include/lnm/http/req.h @@ -135,20 +135,6 @@ lnm_err lnm_http_req_header_get_s(lnm_http_req_hdr *out, lnm_http_req *req, size_t lnm_http_req_route_segment(const char **out, lnm_http_req *req, const char *key); -/** - * 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. * @@ -159,8 +145,8 @@ typedef struct lnm_http_req_hdr_param { * @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); +size_t lnm_http_req_header_param(const char **out, + const lnm_http_req_hdr *header, + const char *key); #endif diff --git a/src/lnm/http/lnm_http_req.c b/src/lnm/http/lnm_http_req.c index e05f810..e7de994 100644 --- a/src/lnm/http/lnm_http_req.c +++ b/src/lnm/http/lnm_http_req.c @@ -129,3 +129,50 @@ size_t lnm_http_req_route_segment(const char **out, lnm_http_req *req, return segment->len; } + +size_t lnm_http_req_header_param(const char **out, + const lnm_http_req_hdr *header, + const char *key) { + size_t key_len = strlen(key); + size_t remaining_len = header->value.len; + + // The -1 ensures there's still space for an equals sign after the match + const char *s = lnm_stristr(header->value.s, remaining_len - 1, key, key_len); + + // Skip any accidental matches of the key inside another part of the value + while (s != NULL && s[key_len] != '=') { + remaining_len -= key_len; + s = lnm_stristr(s + key_len, remaining_len - 1, key, key_len); + }; + + // Edge case where empty value is at the end of the string + if (s == NULL || s + 2 == header->value.s + header->value.len) { + return 0; + } + + *out = s + 2; + const char *value_end = s + 2; + + // Handle a quoted string + if (**out == '"') { + value_end++; + while (value_end < header->value.s + header->value.len && + (*value_end != '"')) { + value_end++; + } + + // If we found a matching quote we trim the quotes, otherwise the quote is + // part of the value + if (value_end < header->value.s + header->value.len) { + // We skip the initial quote + (*out)++; + } + } else { + while (value_end < header->value.s + header->value.len && + (*value_end != ',') && (*value_end != ';')) { + value_end++; + } + } + + return value_end - *out; +} diff --git a/src/lnm/lnm_utils.c b/src/lnm/lnm_utils.c index 47989bf..2999c3b 100644 --- a/src/lnm/lnm_utils.c +++ b/src/lnm/lnm_utils.c @@ -67,3 +67,17 @@ bool lnm_is_ascii(const char *s) { return valid; } + +const char *lnm_stristr(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)) { + return s1; + } + + s1_len--; + s1++; + } + + return NULL; +}