From 06394913f6bc167ca79f6a99fcc2db0afbfd8aa3 Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Fri, 26 Sep 2025 20:06:03 +0200 Subject: [PATCH] Add support for HTTPS --- .gitignore | 4 +++- Makefile | 1 + cweb.h | 49 +++++++++++++++++++++++++++++++++++++++---------- demo/main.c | 47 +++++++++++++++++++++++++++++++++++------------ src/main.c | 34 ++++++++++++++++++++++++++++++++-- src/main.h | 17 +++++++++++++++-- 6 files changed, 125 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index 4a97c9b..d0aed14 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.o *.out -*.exe \ No newline at end of file +*.exe +*.db +*.pem \ No newline at end of file diff --git a/Makefile b/Makefile index 7ef5237..0a52588 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ ifeq ($(OS),Windows_NT) FLAGS += -lws2_32 -lbcrypt else EXT = .out + FLAGS += -lssl -lcrypto -DHTTPS_ENABLED endif all: cweb.h cozisnews$(EXT) diff --git a/cweb.h b/cweb.h index d7b0891..11fccd8 100644 --- a/cweb.h +++ b/cweb.h @@ -248,8 +248,15 @@ typedef struct CWEB_Request CWEB_Request; int cweb_global_init(void); void cweb_global_free(void); -CWEB *cweb_init(CWEB_String addr, uint16_t port); -void cweb_free(CWEB *cweb); +CWEB *cweb_init(CWEB_String addr, uint16_t port, uint16_t secure_port, + CWEB_String cert_key, CWEB_String private_key); + +void cweb_free(CWEB *cweb); + +int cweb_add_website(CWEB *cweb, CWEB_String domain, CWEB_String cert_file, CWEB_String key_file); + +int cweb_create_test_certificate(CWEB_String C, CWEB_String O, + CWEB_String CN, CWEB_String cert_file, CWEB_String key_file); // Open an SQLite instance in file "database_file" and run the DDL script at "schema_file". // Note that "database_file" may be ":memory:". @@ -5797,12 +5804,12 @@ int http_server_wait(HTTP_Server *server, HTTP_Request **req, HTTP_ResponseBuild case SOCKET_EVENT_DIED: { Connection *conn = event.user_data; - HTTP_ASSERT(conn); - - http_engine_free(&conn->engine); - conn->used = false; - conn->gen++; - server->num_conns--; + if (conn) { + http_engine_free(&conn->engine); + conn->used = false; + conn->gen++; + server->num_conns--; + } } break; @@ -14326,7 +14333,8 @@ void cweb_global_free(void) http_global_free(); } -CWEB *cweb_init(CWEB_String addr, uint16_t port) +CWEB *cweb_init(CWEB_String addr, uint16_t port, uint16_t secure_port, + CWEB_String cert_key, CWEB_String private_key) { CWEB *cweb = malloc(sizeof(CWEB)); if (cweb == NULL) @@ -14359,7 +14367,7 @@ CWEB *cweb_init(CWEB_String addr, uint16_t port) return NULL; } - cweb->server = http_server_init((HTTP_String) { addr.ptr, addr.len }, port); + cweb->server = http_server_init_ex((HTTP_String) { addr.ptr, addr.len }, port, secure_port, (HTTP_String) { cert_key.ptr, cert_key.len }, (HTTP_String) { private_key.ptr, private_key.len }); if (cweb->server == NULL) { session_storage_free(cweb->session_storage); #ifdef CWEB_ENABLE_TEMPLATE @@ -14402,6 +14410,27 @@ void cweb_free(CWEB *cweb) free(cweb); } +int cweb_add_website(CWEB *cweb, CWEB_String domain, CWEB_String cert_file, CWEB_String key_file) +{ + return http_server_add_website(cweb->server, + (HTTP_String) { domain.ptr, domain.len }, + (HTTP_String) { cert_file.ptr, cert_file.len }, + (HTTP_String) { key_file.ptr, key_file.len } + ); +} + +int cweb_create_test_certificate(CWEB_String C, CWEB_String O, + CWEB_String CN, CWEB_String cert_file, CWEB_String key_file) +{ + return http_create_test_certificate( + (HTTP_String) { C.ptr, C.len }, + (HTTP_String) { O.ptr, O.len }, + (HTTP_String) { CN.ptr, CN.len }, + (HTTP_String) { cert_file.ptr, cert_file.len }, + (HTTP_String) { key_file.ptr, key_file.len } + ); +} + void cweb_version(void) { printf("%s\n", sqlite3_libversion()); diff --git a/demo/main.c b/demo/main.c index c9a5d03..134ce3c 100644 --- a/demo/main.c +++ b/demo/main.c @@ -250,7 +250,7 @@ static void endpoint_index(CWEB *cweb, CWEB_Request *req) { (void) cweb; - cweb_respond_template(req, 200, CWEB_STR("demo/pages/index.wl"), -1); + cweb_respond_template(req, 200, CWEB_STR("demo/pages/index.wl")); } static void endpoint_write(CWEB *cweb, CWEB_Request *req) @@ -262,7 +262,7 @@ static void endpoint_write(CWEB *cweb, CWEB_Request *req) return; } - cweb_respond_template(req, 200, CWEB_STR("demo/pages/write.wl"), -1); + cweb_respond_template(req, 200, CWEB_STR("demo/pages/write.wl")); } static void endpoint_login(CWEB *cweb, CWEB_Request *req) @@ -274,7 +274,7 @@ static void endpoint_login(CWEB *cweb, CWEB_Request *req) return; } - cweb_respond_template(req, 200, CWEB_STR("demo/pages/login.wl"), -1); + cweb_respond_template(req, 200, CWEB_STR("demo/pages/login.wl")); } static void endpoint_signup(CWEB *cweb, CWEB_Request *req) @@ -286,14 +286,14 @@ static void endpoint_signup(CWEB *cweb, CWEB_Request *req) return; } - cweb_respond_template(req, 200, CWEB_STR("demo/pages/signup.wl"), -1); + cweb_respond_template(req, 200, CWEB_STR("demo/pages/signup.wl")); } static void endpoint_post(CWEB *cweb, CWEB_Request *req) { int post_id = cweb_get_param_i(req, CWEB_STR("id")); if (post_id < 0) { - cweb_respond_template(req, 404, CWEB_STR("demo/pages/notfound.wl"), -1); + cweb_respond_template(req, 404, CWEB_STR("demo/pages/notfound.wl")); return; } @@ -313,7 +313,7 @@ static void endpoint_post(CWEB *cweb, CWEB_Request *req) } if (num == 0) { - cweb_respond_template(req, 404, CWEB_STR("demo/pages/notfound.wl"), -1); + cweb_respond_template(req, 404, CWEB_STR("demo/pages/notfound.wl")); return; } @@ -324,20 +324,40 @@ static void endpoint_fallback(CWEB *cweb, CWEB_Request *req) { (void) cweb; - cweb_respond_template(req, 404, CWEB_STR("demo/pages/notfound.wl"), -1); + cweb_respond_template(req, 404, CWEB_STR("demo/pages/notfound.wl")); } int main(void) { - CWEB_String addr = CWEB_STR("127.0.0.1"); - uint16_t port = 8080; - CWEB_String database_file = CWEB_STR(":memory:"); - CWEB_String schema_file = CWEB_STR("demo/schema.sql"); + CWEB_String addr = CWEB_STR("127.0.0.1"); + uint16_t port = 8080; + CWEB_String database_file = CWEB_STR("demo.db"); + CWEB_String schema_file = CWEB_STR("demo/schema.sql"); if (cweb_global_init() < 0) return -1; - CWEB *cweb = cweb_init(addr, port); + uint16_t secure_port = 0; + CWEB_String cert_key; + CWEB_String private_key; +#ifdef HTTPS_ENABLED + secure_port = 8443; + cert_key = CWEB_STR("test_cert_file.pem"); + private_key = CWEB_STR("test_private_key.pem"); + int ret = cweb_create_test_certificate( + CWEB_STR("C"), + CWEB_STR("O"), + CWEB_STR("CN"), + cert_key, + private_key + ); + if (ret < 0) { + // TODO + return -1; + } +#endif + + CWEB *cweb = cweb_init(addr, port, secure_port, cert_key, private_key); if (cweb == NULL) { cweb_global_free(); return -1; @@ -353,7 +373,10 @@ int main(void) cweb_enable_template_cache(cweb, false); for (;;) { + CWEB_Request *req = cweb_wait(cweb); + if (req == NULL) break; + if (0) {} else if (cweb_match_endpoint(req, CWEB_STR("/api/login"))) endpoint_api_login(cweb, req); else if (cweb_match_endpoint(req, CWEB_STR("/api/signup"))) endpoint_api_signup(cweb, req); diff --git a/src/main.c b/src/main.c index e1ca430..7d020e5 100644 --- a/src/main.c +++ b/src/main.c @@ -927,7 +927,8 @@ void cweb_global_free(void) http_global_free(); } -CWEB *cweb_init(CWEB_String addr, uint16_t port) +CWEB *cweb_init(CWEB_String addr, uint16_t port, uint16_t secure_port, + CWEB_String cert_key, CWEB_String private_key) { CWEB *cweb = malloc(sizeof(CWEB)); if (cweb == NULL) @@ -960,7 +961,7 @@ CWEB *cweb_init(CWEB_String addr, uint16_t port) return NULL; } - cweb->server = http_server_init((HTTP_String) { addr.ptr, addr.len }, port); + cweb->server = http_server_init_ex((HTTP_String) { addr.ptr, addr.len }, port, secure_port, (HTTP_String) { cert_key.ptr, cert_key.len }, (HTTP_String) { private_key.ptr, private_key.len }); if (cweb->server == NULL) { session_storage_free(cweb->session_storage); #ifdef CWEB_ENABLE_TEMPLATE @@ -1003,6 +1004,27 @@ void cweb_free(CWEB *cweb) free(cweb); } +int cweb_add_website(CWEB *cweb, CWEB_String domain, CWEB_String cert_file, CWEB_String key_file) +{ + return http_server_add_website(cweb->server, + (HTTP_String) { domain.ptr, domain.len }, + (HTTP_String) { cert_file.ptr, cert_file.len }, + (HTTP_String) { key_file.ptr, key_file.len } + ); +} + +int cweb_create_test_certificate(CWEB_String C, CWEB_String O, + CWEB_String CN, CWEB_String cert_file, CWEB_String key_file) +{ + return http_create_test_certificate( + (HTTP_String) { C.ptr, C.len }, + (HTTP_String) { O.ptr, O.len }, + (HTTP_String) { CN.ptr, CN.len }, + (HTTP_String) { cert_file.ptr, cert_file.len }, + (HTTP_String) { key_file.ptr, key_file.len } + ); +} + void cweb_version(void) { printf("%s\n", sqlite3_libversion()); @@ -1092,6 +1114,14 @@ CWEB_Request *cweb_wait(CWEB *cweb) return req; } +bool cweb_match_domain(CWEB_Request *req, CWEB_String str) +{ + int idx = http_find_header(req->req->headers, req->req->num_headers, HTTP_STR("host")); + if (idx < 0) return false; + + return http_streq((HTTP_String) { str.ptr, str.len }, req->req->headers[idx].value); +} + bool cweb_match_endpoint(CWEB_Request *req, CWEB_String str) { return http_streq(req->req->url.path, (HTTP_String) { str.ptr, str.len }); diff --git a/src/main.h b/src/main.h index e752880..e6420bf 100644 --- a/src/main.h +++ b/src/main.h @@ -219,8 +219,19 @@ typedef struct CWEB_Request CWEB_Request; int cweb_global_init(void); void cweb_global_free(void); -CWEB *cweb_init(CWEB_String addr, uint16_t port); -void cweb_free(CWEB *cweb); +// TODO: comment +CWEB *cweb_init(CWEB_String addr, uint16_t port, uint16_t secure_port, + CWEB_String cert_key, CWEB_String private_key); + +// TODO: comment +void cweb_free(CWEB *cweb); + +// TODO: comment +int cweb_add_website(CWEB *cweb, CWEB_String domain, CWEB_String cert_file, CWEB_String key_file); + +// TODO: comment +int cweb_create_test_certificate(CWEB_String C, CWEB_String O, + CWEB_String CN, CWEB_String cert_file, CWEB_String key_file); // Open an SQLite instance in file "database_file" and run the DDL script at "schema_file". // Note that "database_file" may be ":memory:". @@ -236,6 +247,8 @@ void cweb_enable_template_cache(CWEB *cweb, bool enable); // TODO: When does this function return NULL? CWEB_Request *cweb_wait(CWEB *cweb); +bool cweb_match_domain(CWEB_Request *req, CWEB_String str); + // Returns true iff the request matches the specified endpoint bool cweb_match_endpoint(CWEB_Request *req, CWEB_String str);