feat(lnm): implement content-length header parsing
ci/woodpecker/push/build Pipeline was successful
Details
ci/woodpecker/push/build Pipeline was successful
Details
parent
3c1e62330c
commit
13ccfef94d
|
@ -1,6 +1,10 @@
|
||||||
#ifndef LNM_COMMON
|
#ifndef LNM_COMMON
|
||||||
#define LNM_COMMON
|
#define LNM_COMMON
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#define LNM_RES(x) \
|
#define LNM_RES(x) \
|
||||||
{ \
|
{ \
|
||||||
lnm_err res = x; \
|
lnm_err res = x; \
|
||||||
|
@ -20,13 +24,14 @@
|
||||||
#define LNM_MIN(x, y) ((x) < (y) ? (x) : (y))
|
#define LNM_MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||||
#define LNM_MAX(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_ok = 0,
|
||||||
lnm_err_failed_alloc,
|
lnm_err_failed_alloc,
|
||||||
lnm_err_failed_network,
|
lnm_err_failed_network,
|
||||||
lnm_err_failed_poll,
|
lnm_err_failed_poll,
|
||||||
lnm_err_not_setup,
|
lnm_err_not_setup,
|
||||||
lnm_err_bad_regex
|
lnm_err_bad_regex,
|
||||||
|
lnm_err_not_found,
|
||||||
} lnm_err;
|
} lnm_err;
|
||||||
|
|
||||||
typedef struct lnm_loop lnm_http_loop;
|
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;
|
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
|
#endif
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
#define LNM_HTTP_REQ
|
#define LNM_HTTP_REQ
|
||||||
|
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "picohttpparser.h"
|
#include "picohttpparser.h"
|
||||||
|
|
||||||
|
#include "lnm/common.h"
|
||||||
#include "lnm/http/consts.h"
|
#include "lnm/http/consts.h"
|
||||||
|
|
||||||
#define LNM_HTTP_MAX_REQ_HEADERS 32
|
#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];
|
struct phr_header arr[LNM_HTTP_MAX_REQ_HEADERS];
|
||||||
size_t len;
|
size_t len;
|
||||||
} headers;
|
} headers;
|
||||||
|
uint64_t content_length;
|
||||||
} lnm_http_req;
|
} lnm_http_req;
|
||||||
|
|
||||||
typedef enum lnm_http_parse_err {
|
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);
|
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
|
#endif
|
||||||
|
|
|
@ -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) {
|
void lnm_http_loop_process_parse_headers(lnm_http_conn *conn) {
|
||||||
lnm_http_loop_ctx *ctx = conn->ctx;
|
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;
|
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_loop_ctx *ctx = conn->ctx;
|
||||||
lnm_http_res *res = &ctx->res;
|
lnm_http_res *res = &ctx->res;
|
||||||
|
|
||||||
|
if (res->status == 0) {
|
||||||
|
res->status = lnm_http_status_ok;
|
||||||
|
}
|
||||||
|
|
||||||
const char *response_type_name =
|
const char *response_type_name =
|
||||||
lnm_http_status_names[res->status / 100 - 1][res->status % 100];
|
lnm_http_status_names[res->status / 100 - 1][res->status % 100];
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "lnm/common.h"
|
||||||
#include "lnm/http/consts.h"
|
#include "lnm/http/consts.h"
|
||||||
#include "lnm/http/loop.h"
|
#include "lnm/http/loop.h"
|
||||||
#include "lnm/http/req.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) {
|
void lnm_http_req_reset(lnm_http_req *req) {
|
||||||
memset(req, 0, sizeof(lnm_http_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;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in New Issue