add header parser and fix hash map

This commit is contained in:
2025-04-30 02:49:18 +02:00
parent dc39cf9d64
commit ad21ec0fa4
7 changed files with 66 additions and 23 deletions

View File

@@ -31,7 +31,6 @@ And then open the `docs/html/index.html`.
## Roadmap
- Request parser
- Implement Keep-Alive
- Support for virtual hosting
- HTTPS support with TLS

View File

@@ -1,13 +1,13 @@
#ifndef CWS_HTTP_H
#define CWS_HTTP_H
#include "utils/hashmap.h"
#define CWS_WWW "../www" /**< Directory used to get html files */
/** In the future I'll move conf stuff under a server struct, I can skip just because I want something that works */
#define CWS_HTTP_LOCATION_LEN 512
#define CWS_HTTP_LOCATION_PATH_LEN 1024
#define CWS_HTTP_VERSION_LEN 8
#define CWS_HTTP_USER_AGENT_LEN 1024
#define CWS_HTTP_HOST_LEN 1024
typedef enum cws_http_method_t {
CWS_HTTP_GET, /**< GET method */
@@ -27,8 +27,7 @@ typedef struct cws_http_t {
char location[CWS_HTTP_LOCATION_LEN]; /**< Resource requested */
char location_path[CWS_HTTP_LOCATION_PATH_LEN]; /**< Full resource path */
char http_version[CWS_HTTP_VERSION_LEN]; /**< HTTP version */
char user_agent[CWS_HTTP_USER_AGENT_LEN]; /**< User-Agent */
char host[CWS_HTTP_HOST_LEN]; /**< Host */
cws_hashmap *headers; /**< Headers hash map */
} cws_http;
/* Connection */
/* Accept-Encoding */

View File

@@ -25,9 +25,11 @@ void cws_utils_print_ips(const char *hostname, const char *port);
void cws_utils_get_client_ip(struct sockaddr_storage *sa, char *ip);
/* TODO: add docs */
char *cws_strip(char *str);
/* Functions used for hash maps */
int my_hash_fn(void *key);
bool my_equal_fn(void *a, void *b);
void my_free_value_fn(void *value);
int my_str_hash_fn(void *key);
bool my_str_equal_fn(void *a, void *b);
void my_str_free_fn(void *value);
#endif

View File

@@ -6,6 +6,7 @@
#include <sys/socket.h>
#include "utils/colors.h"
#include "utils/utils.h"
cws_http *cws_http_parse(char *request_str, int sockfd) {
cws_http *request = malloc(sizeof(cws_http));
@@ -22,7 +23,7 @@ cws_http *cws_http_parse(char *request_str, int sockfd) {
if (pch == NULL) {
return NULL;
}
CWS_LOG_DEBUG("[client::http] method: %s", pch);
CWS_LOG_DEBUG("[http] method: %s", pch);
cws_http_parse_method(request, pch);
/* Parse location */
@@ -30,29 +31,53 @@ cws_http *cws_http_parse(char *request_str, int sockfd) {
if (pch == NULL) {
return NULL;
}
CWS_LOG_DEBUG("[client::http] location: %s", pch);
CWS_LOG_DEBUG("[http] location: %s", pch);
strncpy(request->location, pch, CWS_HTTP_LOCATION_LEN);
/* Parse location path */
/* Adjust location path */
if (strcmp(request->location, "/") == 0) {
snprintf(request->location_path, CWS_HTTP_LOCATION_PATH_LEN, "%s/index.html", CWS_WWW);
} else {
snprintf(request->location_path, CWS_HTTP_LOCATION_PATH_LEN, "%s%s", CWS_WWW, request->location);
}
CWS_LOG_DEBUG("[client::http] location path: %s", request->location_path);
CWS_LOG_DEBUG("[http] location path: %s", request->location_path);
/* Parse HTTP version */
pch = strtok(NULL, " \r\n");
if (pch == NULL) {
return NULL;
}
CWS_LOG_DEBUG("[client::http] version: %s", pch);
CWS_LOG_DEBUG("[http] version: %s", pch);
strncpy(request->http_version, pch, CWS_HTTP_VERSION_LEN);
/* Parse other stuff... */
/* Parse until a \r\n and store the header with its value
* into a hashmap
*/
/* Parse headers until a \r\n */
request->headers = cws_hm_init(my_str_hash_fn, my_str_equal_fn, my_str_free_fn, my_str_free_fn);
char *header_colon;
while (pch) {
/* Get header line */
pch = strtok(NULL, "\r\n");
if (pch == NULL) {
break;
}
/* Find ":" */
header_colon = strchr(pch, ':');
if (header_colon != NULL) {
*header_colon = '\0';
} else {
break;
}
/* Header key */
char *hkey = pch;
char *hkey_dup = strdup(hkey);
/* Header value (starting from ": ") */
char *hvalue = header_colon + 2;
char *hvalue_dup = strdup(hvalue);
cws_hm_set(request->headers, hkey_dup, hvalue_dup);
}
/* Parse body */
return request;
}
@@ -178,4 +203,7 @@ void cws_http_send_not_found(cws_http *request) {
send(request->sockfd, response, response_len, 0);
}
void cws_http_free(cws_http *request) { free(request); }
void cws_http_free(cws_http *request) {
cws_hm_free(request->headers);
free(request);
}

View File

@@ -78,7 +78,7 @@ void cws_server_loop(int sockfd) {
struct sockaddr_storage their_sa;
socklen_t theirsa_size = sizeof their_sa;
cws_hashmap *clients = cws_hm_init(my_hash_fn, my_equal_fn, NULL, NULL);
cws_hashmap *clients = cws_hm_init(my_str_hash_fn, my_str_equal_fn, NULL, NULL);
int epfd = epoll_create1(0);
cws_fd_set_nonblocking(sockfd);

View File

@@ -58,7 +58,7 @@ void cws_hm_free(cws_hashmap *hashmap) {
bool cws_hm_set(cws_hashmap *hashmap, void *key, void *value) {
/* Get hash index */
int index = hashmap->hash_fn(key);
int index = hashmap->hash_fn(key) % CWS_HASHMAP_SIZE;
cws_bucket *bucket = &hashmap->map[index];
/* Check if the key at index is empty */

View File

@@ -1,5 +1,6 @@
#include "utils/utils.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -45,7 +46,21 @@ void cws_utils_get_client_ip(struct sockaddr_storage *sa, char *ip) {
inet_ntop(AF_INET, &sin->sin_addr, ip, INET_ADDRSTRLEN);
}
int my_hash_fn(void *key) {
char *cws_strip(char *str) {
char *end;
while (isspace((int)*str)) str++;
if (*str == 0) return str;
end = str + strlen(str) - 1;
while (end > str && isspace((int)*end)) end--;
*(end + 1) = '\0';
return str;
}
int my_str_hash_fn(void *key) {
char *key_str = (char *)key;
size_t key_len = strlen(key_str);
@@ -58,7 +73,7 @@ int my_hash_fn(void *key) {
return total % 2069;
}
bool my_equal_fn(void *a, void *b) {
bool my_str_equal_fn(void *a, void *b) {
if (strcmp((char *)a, (char *)b) == 0) {
return true;
}
@@ -66,4 +81,4 @@ bool my_equal_fn(void *a, void *b) {
return false;
}
void my_free_str_fn(void *value) { free(value); }
void my_str_free_fn(void *value) { free(value); }