lander/lnm/src/http/lnm_http_req.c

97 lines
2.6 KiB
C

#include <stdbool.h>
#include <string.h>
#include "lnm/common.h"
#include "lnm/http/consts.h"
#include "lnm/http/loop.h"
#include "lnm/http/req.h"
lnm_http_parse_err lnm_http_req_parse(lnm_http_req *req, char *buf,
size_t len) {
const char *method;
char *path;
size_t method_len, path_len;
req->headers.len = LNM_HTTP_MAX_REQ_HEADERS;
int req_len = phr_parse_request(
buf, len, &method, &method_len, (const char **)&path, &path_len,
&req->minor_version, req->headers.arr, &req->headers.len, req->len);
if (req_len == -1) {
req->len = len;
return lnm_http_parse_err_invalid;
} else if (req_len == -2) {
return lnm_http_parse_err_incomplete;
}
bool known_method = false;
for (size_t i = 0; i < lnm_http_method_names_len && !known_method; i++) {
if (strncmp(method, lnm_http_method_names[i], method_len) == 0) {
req->method = i;
known_method = true;
}
}
if (!known_method) {
return lnm_http_parse_err_unknown_method;
}
// Path will always end with a newline, which we can safely set to nul
path[path_len] = '\0';
char *question_mark = strchr(path, '?');
// Only store query if the path doesn't simply end with a question mark
if ((question_mark != NULL) && (path_len - (question_mark + 1 - path) > 0)) {
req->query.s = question_mark + 1;
req->query.len = path_len - (question_mark + 1 - path);
path_len = question_mark - path;
// All parsed strings should be null-terminated. This character is either a
// newline (if at the end of the path), or a question mark (if a query is
// present).
path[path_len] = '\0';
}
req->path.len = path_len;
req->path.s = path;
req->len = req_len;
return lnm_http_parse_err_ok;
}
void lnm_http_req_reset(lnm_http_req *req) {
if (req->body.owned) {
free(req->body.buf);
}
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;
}