refactor(http): improve http parse method

This commit is contained in:
2025-10-26 18:44:25 +01:00
parent 564b2befc5
commit 216fc0f62d
2 changed files with 94 additions and 84 deletions

View File

@@ -1,5 +1,6 @@
#include "http/request.h" #include "http/request.h"
#include <myclib/mystring.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -33,109 +34,73 @@ static cws_http_method_e http_parse_method(const char *method) {
return HTTP_UNKNOWN; return HTTP_UNKNOWN;
} }
cws_http_s *cws_http_parse(string_s *request_str) { static bool parse_method(cws_http_s *req, char **cursor) {
if (!request_str || !request_str->data) { char *s = *cursor + strspn(*cursor, " ");
return NULL; size_t len = strcspn(s, " ");
if (len == 0 || s[len] == '\0') {
return false;
} }
cws_http_s *request = http_new(); s[len] = '\0';
if (request == NULL) { CWS_LOG_DEBUG("method: %s", s);
return NULL; req->method = http_parse_method(s);
*cursor = s + len + 1;
return true;
} }
char *str = strdup(request_str->data); static bool parse_location(cws_http_s *req, char **cursor) {
if (!str) { char *s = *cursor + strspn(*cursor, " ");
cws_http_free(request); size_t len = strcspn(s, " ");
return NULL; if (len == 0 || s[len] == '\0') {
return false;
} }
char *str_free = str;
/* Parse HTTP method */ s[len] = '\0';
str += strspn(str, " "); CWS_LOG_DEBUG("location: %s", s);
if (*str == '\0') { string_append(req->location, s);
free(str_free); *cursor = s + len + 1;
cws_http_free(request);
return NULL;
}
size_t len = strcspn(str, " ");
if (str[len] == '\0') {
free(str_free);
cws_http_free(request);
return NULL;
}
str[len] = '\0';
CWS_LOG_DEBUG("method: %s", str);
request->method = http_parse_method(str);
str += len + 1;
/* Parse location */ return true;
str += strspn(str, " ");
if (*str == '\0') {
free(str_free);
cws_http_free(request);
return NULL;
} }
len = strcspn(str, " ");
if (str[len] == '\0') {
free(str_free);
cws_http_free(request);
return NULL;
}
str[len] = '\0';
string_append(request->location, str);
str += len + 1;
/* Adjust location path */ static bool parse_version(cws_http_s *req, char **cursor) {
/* @TODO: fix path traversal */ char *s = *cursor + strspn(*cursor, " \t");
string_append(request->location_path, "www"); size_t len = strcspn(s, "\r\n");
if (strcmp(request->location->data, "/") == 0) { if (len == 0 || s[len] == '\0') {
string_append(request->location_path, "/index.html"); return false;
} else {
string_append(request->location_path, request->location->data);
} }
CWS_LOG_DEBUG("location path: %s", request->location_path->data);
/* Parse HTTP version */ s[len] = '\0';
str += strspn(str, " \t"); CWS_LOG_DEBUG("version: %s", s);
if (*str == '\0') { string_append(req->http_version, s);
free(str_free); *cursor = s + len + 1;
cws_http_free(request);
return NULL;
}
len = strcspn(str, "\r\n");
if (len == 0) {
free(str_free);
cws_http_free(request);
return NULL;
}
str[len] = '\0';
CWS_LOG_DEBUG("version: %s", str);
string_append(request->http_version, str);
str += len;
/* Parse headers until a blank line (\r\n\r\n) */ return true;
request->headers = }
static bool parse_headers(cws_http_s *req, char **cursor) {
req->headers =
hm_new(my_str_hash_fn, my_str_equal_fn, my_str_free_fn, my_str_free_fn, hm_new(my_str_hash_fn, my_str_equal_fn, my_str_free_fn, my_str_free_fn,
sizeof(char) * CWS_HTTP_HEADER_MAX, sizeof(char) * CWS_HTTP_HEADER_CONTENT_MAX); sizeof(char) * CWS_HTTP_HEADER_MAX, sizeof(char) * CWS_HTTP_HEADER_CONTENT_MAX);
str += strspn(str, "\r\n"); char *s = *cursor + strspn(*cursor, "\r\n");
while (*s != '\0' && *s != '\r') {
while (*str != '\0' && *str != '\r') { char *line_end = strstr(s, "\r\n");
char *line_end = strstr(str, "\r\n");
if (!line_end) { if (!line_end) {
break; break;
} }
*line_end = '\0'; *line_end = '\0';
char *colon = strchr(str, ':'); char *colon = strchr(s, ':');
if (!colon) { if (!colon) {
str = line_end + 2; s = line_end + 2;
continue; continue;
} }
*colon = '\0'; *colon = '\0';
char *header_key = str; char *header_key = s;
char *header_value = colon + 1; char *header_value = colon + 1;
header_value += strspn(header_value, " \t"); header_value += strspn(header_value, " \t");
@@ -148,16 +113,62 @@ cws_http_s *cws_http_parse(string_s *request_str) {
strncpy(hv, header_value, sizeof(hv) - 1); strncpy(hv, header_value, sizeof(hv) - 1);
hv[sizeof(hv) - 1] = '\0'; hv[sizeof(hv) - 1] = '\0';
hm_set(request->headers, hk, hv); // CWS_LOG_DEBUG("%s:%s", hk, hv);
hm_set(req->headers, hk, hv);
/* Move to the next line */ /* Move to the next line */
str = line_end + 2; s = line_end + 2;
} }
free(str_free); *cursor = s;
return true;
}
cws_http_s *cws_http_parse(string_s *request_str) {
if (!request_str || !request_str->data) {
return NULL;
}
cws_http_s *request = http_new();
if (!request) {
return NULL;
}
char *str = strdup(request_str->data);
if (!str) {
cws_http_free(request);
return NULL;
}
char *orig = str;
/* Parse HTTP method */
parse_method(request, &str);
/* Parse location */
parse_location(request, &str);
/* Adjust location path */
/* @TODO: fix path traversal */
string_append(request->location_path, "www");
if (strcmp(request->location->data, "/") == 0) {
string_append(request->location_path, "/index.html");
} else {
string_append(request->location_path, request->location->data);
}
CWS_LOG_DEBUG("location path: %s", request->location_path->data);
/* Parse HTTP version */
parse_version(request, &str);
/* Parse headers */
parse_headers(request, &str);
/* TODO: Parse body */ /* TODO: Parse body */
/* str is at the beginning of the body */ /* orig is at the beginning of the body */
/* Free the original string */
free(orig);
return request; return request;
} }

View File

@@ -103,7 +103,6 @@ static void http_send_resource(cws_http_s *request) {
/* Retrieve correct Content-Type */ /* Retrieve correct Content-Type */
char content_type[CWS_HTTP_CONTENT_TYPE]; char content_type[CWS_HTTP_CONTENT_TYPE];
http_get_content_type(request->location_path->data, content_type); http_get_content_type(request->location_path->data, content_type);
CWS_LOG_DEBUG("content-type: %s", content_type);
/* TODO: Check for keep-alive */ /* TODO: Check for keep-alive */