aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorspl3g <spleefer6@yandex.ru>2025-03-22 21:41:16 +0300
committerspl3g <spleefer6@yandex.ru>2025-03-22 21:41:16 +0300
commit62454373db4cd2add82ded0cf7b21f7d69ade597 (patch)
tree1627133fe4567e9a3abb707af5e7289353410d5f /include
parentef5f52fb739c9f0d71c579f08363ef0dfd5c227d (diff)
Reorganize the lib
Diffstat (limited to 'include')
-rw-r--r--include/chttp/arena.h65
-rw-r--r--include/chttp/arena_strings.h36
-rw-r--r--include/chttp/const_strings.h28
-rw-r--r--include/chttp/hashmap.h27
-rw-r--r--include/chttp/http.h177
5 files changed, 333 insertions, 0 deletions
diff --git a/include/chttp/arena.h b/include/chttp/arena.h
new file mode 100644
index 0000000..1f53355
--- /dev/null
+++ b/include/chttp/arena.h
@@ -0,0 +1,65 @@
+// Most of the code is from https://github.com/tsoding/arena
+
+#ifndef ARENA_H_
+#define ARENA_H_
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+
+typedef struct region region;
+
+struct region {
+ region *next;
+ size_t cap;
+ size_t len;
+ uintptr_t data[];
+};
+
+typedef struct {
+ region *beg;
+ region *end;
+ size_t region_cap;
+} arena;
+
+arena arena_init_cap(size_t cap);
+void *arena_alloc(arena *a, size_t size);
+void arena_free(arena *a);
+void *arena_realloc(arena *a, void *oldptr, size_t oldsz, size_t newsz);
+
+#define new(a, t, c) (t *)arena_alloc(a, sizeof(t)*c)
+
+#define ARENA_REGION_DEFAULT_CAPACITY (8*1024)
+#define ARENA_DA_INIT_CAP (2)
+
+#define arena_da_reserve(a, da, expected_size) \
+ do { \
+ if ((expected_size) >= (da)->cap) { \
+ size_t new_cap = (da)->cap == 0 ? ARENA_DA_INIT_CAP : (da)->cap*2; \
+ while (new_cap < expected_size) { \
+ new_cap *= 2; \
+ } \
+ (da)->data = arena_realloc( \
+ (a), (da)->data, \
+ (da)->cap*sizeof(*(da)->data), \
+ new_cap*sizeof(*(da)->data)); \
+ (da)->cap = new_cap; \
+ } \
+ } while (0)
+
+#define arena_da_append(a, da, item) \
+ do { \
+ arena_da_reserve((a), (da), (da)->len + 1); \
+ (da)->data[(da)->len++] = (item); \
+ } while (0)
+
+#define arena_da_append_many(a, da, items, items_len) \
+ do { \
+ arena_da_reserve((a), (da), (da)->len+len); \
+ memcpy((da)->data+(da)->len, (items), sizeof(*(da)->data)*items_len); \
+ (da)->len += len; \
+ } while (0)
+
+#endif //ARENA_H_
diff --git a/include/chttp/arena_strings.h b/include/chttp/arena_strings.h
new file mode 100644
index 0000000..b25435d
--- /dev/null
+++ b/include/chttp/arena_strings.h
@@ -0,0 +1,36 @@
+#ifndef ARENA_STRINGS_H_
+#define ARENA_STRINGS_H_
+
+#include "arena.h"
+#include "const_strings.h"
+
+typedef struct {
+ const_string *data;
+ size_t len;
+ size_t cap;
+} const_string_da;
+
+typedef struct {
+ char* data;
+ size_t len;
+ size_t cap;
+} string_builder;
+
+const_string arena_cs_append(arena *a, const_string dst, const_string src);
+const_string arena_cs_init(arena *a, int len);
+const_string arena_cs_concat(arena *a, const_string_da strings, const_string sep);
+
+#define arena_sb_append_buf(a, sb, buf, len) arena_da_append_many((a), (sb), (buf), (len))
+
+#define arena_sb_append_cstr(a, sb, cstr) \
+ do { \
+ const char * str = (cstr); \
+ size_t len = strlen((cstr)); \
+ arena_da_append_many((a), (sb), (str), len); \
+ } while (0)
+
+#define arena_sb_append_null(a, sb) arena_da_append_many((a), (sb), "", 1)
+
+#define arena_sb_to_cs(sb) cs_from_parts((sb).data, (sb).len)
+
+#endif // ARENA_STRINGS_H_
diff --git a/include/chttp/const_strings.h b/include/chttp/const_strings.h
new file mode 100644
index 0000000..cb92442
--- /dev/null
+++ b/include/chttp/const_strings.h
@@ -0,0 +1,28 @@
+#ifndef CONST_STRINGS_H_
+#define CONST_STRINGS_H_
+
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+typedef struct {
+ const char* data;
+ int len;
+} const_string;
+
+const_string cs_from_parts(const char* data, int len);
+const_string cs_from_cstr(const char* cstr);
+const_string cs_slice(const_string src, int from, int to);
+const_string cs_chop_delim(const_string *src, char delim);
+bool cs_try_chop_delim(const_string *str, char delim, const_string *dst);
+int cs_find_delim(const_string str, char delim);
+bool cs_eq(const_string str1, const_string str2);
+void cs_print(char *format, const_string str);
+
+#define CS(cstr) cs_from_parts(cstr, sizeof(cstr) - 1)
+#define CS_STATIC(cstr) {.data = cstr, .len = sizeof(cstr) - 1}
+
+#define CS_FMT "%.*s"
+#define CS_ARG(cs) (int) (cs).len, (cs).data
+
+#endif // STRINGS_H_
diff --git a/include/chttp/hashmap.h b/include/chttp/hashmap.h
new file mode 100644
index 0000000..eefb5ee
--- /dev/null
+++ b/include/chttp/hashmap.h
@@ -0,0 +1,27 @@
+#ifndef HASHMAP_H_
+#define HASHMAP_H_
+
+#include <stddef.h>
+#include "const_strings.h"
+#include "arena.h"
+
+#define HASHMAP_DEFAULT_R 31
+
+typedef struct hashitem hashitem;
+struct hashitem {
+ hashitem *next;
+ const_string key;
+ void* val;
+};
+
+typedef struct {
+ size_t cap;
+ hashitem data[];
+} hashmap;
+
+size_t hash_str(const_string str, size_t cap);
+hashmap *hashmap_init(arena *a, size_t cap);
+size_t hashmap_kstr_insert(arena *a, hashmap* map, const_string key, void* val);
+void *hashmap_kstr_get(hashmap *map, const_string key);
+
+#endif // HASHMAP_H_
diff --git a/include/chttp/http.h b/include/chttp/http.h
new file mode 100644
index 0000000..4fcc418
--- /dev/null
+++ b/include/chttp/http.h
@@ -0,0 +1,177 @@
+#ifndef HTTP_H_
+#define HTTP_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <pthread.h>
+
+#include "const_strings.h"
+#include "arena_strings.h"
+#include "arena.h"
+
+typedef struct {
+ const_string key;
+ const_string value;
+} KV;
+
+typedef struct {
+ KV *data;
+ size_t len;
+ size_t cap;
+} header_da;
+
+typedef struct {
+ const_string key;
+ const_string val;
+} http_query;
+
+typedef struct {
+ KV *data;
+ size_t len;
+ size_t cap;
+} http_query_da;
+
+typedef struct {
+ const_string key;
+ void *val;
+} http_context_value;
+
+typedef struct {
+ http_context_value *data;
+ size_t len;
+ size_t cap;
+} http_context;
+
+typedef struct {
+ size_t code;
+ header_da headers;
+ const_string body;
+ bool sent;
+} http_response;
+
+typedef struct {
+ size_t inc_fd;
+ const_string method;
+ const_string path;
+ http_query_da query;
+ header_da headers;
+ const_string body;
+
+ arena *arena;
+ http_response* resp;
+ http_context *ctx;
+} http_request;
+
+typedef void (*http_handler_func)(http_request);
+
+typedef struct http_handler_da http_handler_da;
+typedef struct http_middleware http_middleware;
+typedef struct http_handler http_handler;
+
+typedef void (*http_middleware_func)(http_middleware *, http_request);
+
+struct http_middleware {
+ http_middleware_func func;
+ http_middleware *next;
+ http_handler_func handler;
+};
+
+struct http_handler {
+ const_string method;
+ const_string path;
+ http_middleware *middleware;
+ http_handler_func func;
+};
+
+struct http_handler_da {
+ http_handler *data;
+ size_t len;
+ size_t cap;
+};
+
+typedef struct {
+ http_middleware *start;
+ http_middleware *end;
+} http_global_middleware;
+
+typedef struct {
+ size_t sockfd;
+ struct sockaddr *addr;
+ arena *arena;
+ http_handler_da handlers;
+ http_context global_ctx;
+ http_global_middleware *global_middleware;
+} http_server;
+
+typedef enum {
+ HTTP_INFO = 0,
+ HTTP_WARNING,
+ HTTP_ERROR,
+} http_log_level;
+
+typedef enum {
+ CONTINUE = 100,
+ SWITCHING_PROTOCOLS = 101,
+ PROCESSING = 102,
+ EARLY_HINTS = 103,
+ OK = 200,
+ CREATED = 201,
+ ACCEPTED = 202,
+ NO_CONTENT = 204,
+ MULTIPLE_CHOICES = 300,
+ MOVED_PERMANENTLY = 301,
+ FOUND = 302,
+ SEE_OTHER = 303,
+ NOT_MODIFIED = 304,
+ TEMPORARY_REDIRECT = 307,
+ PERMANENT_REDIRECT = 308,
+ BAD_REQUEST = 400,
+ UNAUTHORIZED = 401,
+ PAYMENT_REQUIRED = 402,
+ FORBIDDEN = 403,
+ NOT_FOUND = 404,
+ METHOD_NOT_ALLOWED = 405,
+ NOT_ACCEPTABLE = 406,
+ REQUEST_TIMEOUT = 408,
+ IM_A_TEEPOT = 418,
+ INTERNAL_SERVER_ERROR = 500,
+ NOT_IMPLEMENTED = 501,
+ BAD_GATEWAY = 502,
+ SERVICE_UNAVAILABLE = 503,
+ HTTP_VERSION_NOT_SUPPPORTED = 505,
+} http_response_code;
+
+const_string get_response_string(http_response_code code);
+void *get_in_addr(struct sockaddr *sa);
+int get_in_port(struct sockaddr *sa);
+void http_log(http_log_level log, char *fmt, ...);
+
+void set_context_value(arena *arena, http_context *ctx, http_context_value kv);
+void *get_context_value(http_context *ctx, char* key);
+
+void http_send(http_request req);
+void http_send_json(http_request req, const_string json);
+void http_send_body(http_request req, const_string body);
+
+int init_server(arena *arena, http_server *serv, char *addr, char *port);
+int listen_and_serve(http_server *serv);
+
+http_handler *http_handle_path(http_server *serv, char *method, char *path, http_handler_func handler);
+
+void http_run_next(http_middleware *self, http_request req);
+void http_register_global_middleware(http_server *hand, http_middleware_func func);
+void http_register_handler_middleware(arena *arena, http_handler *hand, http_middleware_func func);
+
+#endif // HTTP_H_