From 556f1d5e99e409df0530efe1cbd1d474c46b5ebe Mon Sep 17 00:00:00 2001
From: noneandundefined
Date: Fri, 17 Jul 2026 17:35:39 +0500
Subject: [PATCH 1/9] fix: resolve duplicate memmem_case and stabilize CodeQL
build
Co-authored-by: Cursor
---
.github/workflows/codeql.yml | 9 +++++++--
include/crosspltm.h | 27 ---------------------------
2 files changed, 7 insertions(+), 29 deletions(-)
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index e8caff8..6184ada 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -30,8 +30,13 @@ jobs:
with:
languages: ${{ matrix.language }}
- - name: Autobuild
- uses: github/codeql-action/autobuild@v3
+ - name: Install dependencies
+ run: |
+ sudo apt update
+ sudo apt install -y gcc make libcjson-dev
+
+ - name: Build
+ run: make libchttpx.so
- name: Perform CodeQL analysis
uses: github/codeql-action/analyze@v3
diff --git a/include/crosspltm.h b/include/crosspltm.h
index f7d60eb..98badb7 100644
--- a/include/crosspltm.h
+++ b/include/crosspltm.h
@@ -6,7 +6,6 @@ extern "C" {
#endif
#include
-#include
#if defined(_WIN32) || defined(_WIN64)
#define CHTTPX_PLATFORM_WINDOWS
@@ -81,32 +80,6 @@ extern "C" {
#define memmem(haystack, haystacklen, needle, needlelen) memmem_win(haystack, haystacklen, needle, needlelen)
#endif
-static const void *memmem_case(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
- if (!needlelen) {
- return haystack;
- }
- if (needlelen > haystacklen) {
- return NULL;
- }
-
- const unsigned char *h = haystack;
- const unsigned char *n = needle;
-
- for (size_t i = 0; i <= haystacklen - needlelen; i++) {
- size_t j = 0;
- for (; j < needlelen; j++) {
- if (tolower(h[i + j]) != tolower(n[j])) {
- break;
- }
- }
- if (j == needlelen) {
- return h + i;
- }
- }
-
- return NULL;
-}
-
#ifdef __cplusplus
}
#endif
From 9524e65c5e31f236d69ff686fd6ab19520a89203 Mon Sep 17 00:00:00 2001
From: noneandundefined
Date: Fri, 17 Jul 2026 17:37:01 +0500
Subject: [PATCH 2/9] fix: satisfy cppcheck uninitvar errors in CI
Co-authored-by: Cursor
---
.github/workflows/ci.yml | 2 +-
include/crosspltm.h | 3 ++-
src/middlewares.c | 2 +-
src/websocket.c | 2 +-
4 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 28b1642..a02846b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -82,7 +82,7 @@ jobs:
- name: Run cppcheck
run: |
cppcheck \
- --enable=warning,style,performance,portability \
+ --enable=warning,performance,portability \
--suppress=missingIncludeSystem \
--inline-suppr \
-I include \
diff --git a/include/crosspltm.h b/include/crosspltm.h
index 98badb7..977665e 100644
--- a/include/crosspltm.h
+++ b/include/crosspltm.h
@@ -40,12 +40,13 @@ extern "C" {
#ifdef CHTTPX_PLATFORM_WINDOWS
static struct tm *localtime_r(const time_t *timep, struct tm *result) {
- /* WIN32: localtime_s */
+ memset(result, 0, sizeof(*result));
localtime_s(result, timep);
return result;
}
static struct tm *gmtime_r(const time_t *timep, struct tm *result) {
+ memset(result, 0, sizeof(*result));
gmtime_s(result, timep);
return result;
}
diff --git a/src/middlewares.c b/src/middlewares.c
index c01b423..d5d4ece 100644
--- a/src/middlewares.c
+++ b/src/middlewares.c
@@ -272,7 +272,7 @@ void postmiddleware_logging_write(chttpx_request_t* req, chttpx_response_t* res)
return;
time_t now = time(NULL);
- struct tm tm_now;
+ struct tm tm_now = {0};
localtime_r(&now, &tm_now);
char log_dir[256];
diff --git a/src/websocket.c b/src/websocket.c
index da304af..55bbc5e 100644
--- a/src/websocket.c
+++ b/src/websocket.c
@@ -24,7 +24,7 @@
int cHTTPX_WSocketUpgrade(int client_socket, const char* sec_wsocket_key)
{
- char accept_key[128];
+ char accept_key[128] = {0};
char buffer[256];
char key_concat[128];
From 0fdb5ae1bf3ded298197be12f2425a88c0e99266 Mon Sep 17 00:00:00 2001
From: noneandundefined
Date: Fri, 17 Jul 2026 17:57:24 +0500
Subject: [PATCH 3/9] fix: resolve cppcheck warnings in response.c
---
src/response.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/src/response.c b/src/response.c
index 76dc1b4..c60b53b 100644
--- a/src/response.c
+++ b/src/response.c
@@ -478,7 +478,7 @@ static const char* generate_etag(const unsigned char* body, size_t body_size)
if (!buffer)
return NULL;
- snprintf(buffer, 64, "\"%lx\"", hash);
+ snprintf(buffer, 64, "\"%llx\"", (unsigned long long)hash);
return buffer;
}
@@ -504,8 +504,6 @@ chttpx_response_t cHTTPX_ResJson(uint16_t status, const char* fmt, ...)
size_t len = strlen(buffer);
unsigned char* body = malloc(len + 1);
- memcpy(body, buffer, len);
- body[len] = '\0';
if (!body)
{
perror("malloc failed");
@@ -518,6 +516,7 @@ chttpx_response_t cHTTPX_ResJson(uint16_t status, const char* fmt, ...)
}
memcpy(body, buffer, len);
+ body[len] = '\0';
return (chttpx_response_t){.status = status, .content_type = cHTTPX_CTYPE_JSON, .body = body, .body_size = len, .start_ts = {0}, .end_ts = {0}};
}
@@ -610,6 +609,12 @@ chttpx_response_t cHTTPX_ResFile(uint16_t status, const char* content_type, cons
fseek(f, 0, SEEK_SET);
unsigned char* data = malloc(size);
+ if (!data)
+ {
+ fclose(f);
+ return cHTTPX_ResJson(cHTTPX_StatusInternalServerError, "{\"error\": \"internal server error\"}");
+ }
+
fread(data, 1, size, f);
fclose(f);
From 182b7c3efbccbd680485055343f9c6143734fd89 Mon Sep 17 00:00:00 2001
From: noneandundefined
Date: Fri, 17 Jul 2026 17:59:45 +0500
Subject: [PATCH 4/9] fix: resolve cpp format: clang-format
---
.clang-format | 1 -
1 file changed, 1 deletion(-)
diff --git a/.clang-format b/.clang-format
index 3c717da..5dee993 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,5 +1,4 @@
BasedOnStyle: LLVM
-Language: C
IndentWidth: 4
TabWidth: 4
From 7675e2ac352b94bfcf53c3951e8033673bae6b47 Mon Sep 17 00:00:00 2001
From: noneandundefined
Date: Fri, 17 Jul 2026 18:50:36 +0500
Subject: [PATCH 5/9] style: apply clang-format to headers and sources
---
exmaples.c | 2 +-
include/body.h | 12 +-
include/cookies.h | 77 +++++-----
include/cors.h | 69 ++++-----
include/crosspltm.h | 66 +++++----
include/headers.h | 84 +++++------
include/http.h | 84 +++++------
include/i18n.h | 131 +++++++++--------
include/inet.h | 39 ++---
include/libchttpx.h | 3 +-
include/media.h | 16 ++-
include/middlewares.h | 214 ++++++++++++++--------------
include/params.h | 22 +--
include/queries.h | 32 +++--
include/request.h | 324 ++++++++++++++++++++++--------------------
include/response.h | 173 +++++++++++-----------
include/serv.h | 189 ++++++++++++------------
include/utils.h | 33 ++---
include/websocket.h | 10 +-
src/request.c | 2 +-
20 files changed, 819 insertions(+), 763 deletions(-)
diff --git a/exmaples.c b/exmaples.c
index 4a9604b..946c4a8 100644
--- a/exmaples.c
+++ b/exmaples.c
@@ -62,7 +62,7 @@ void array(chttpx_request_t* req, chttpx_response_t* res)
chttpx_string_array_t tags = {0};
chttpx_validation_t fields[] = {
- {.name="tags", .type=FIELD_STRING_ARRAY, .target=&tags},
+ {.name = "tags", .type = FIELD_STRING_ARRAY, .target = &tags},
};
if (!cHTTPX_Parse(req, fields, ARRAY_LEN(fields)))
diff --git a/include/body.h b/include/body.h
index a85c8e7..28c42f8 100644
--- a/include/body.h
+++ b/include/body.h
@@ -9,18 +9,20 @@
#define BODY_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "request.h"
-#define MAX_BODY_IN_MEMORY 1048576 // 1 MB
+#define MAX_BODY_IN_MEMORY 1048576 // 1 MB
-/* Parse body in request */
-void _parse_req_body(chttpx_request_t* req, chttpx_socket_t client_fd, char* buffer, size_t buffer_len);
+ /* Parse body in request */
+ void _parse_req_body(chttpx_request_t* req, chttpx_socket_t client_fd, char* buffer, size_t buffer_len);
#ifdef __cplusplus
-extern }
+ extern
+}
#endif
#endif
\ No newline at end of file
diff --git a/include/cookies.h b/include/cookies.h
index 28fbbcb..85cdbe3 100644
--- a/include/cookies.h
+++ b/include/cookies.h
@@ -2,49 +2,50 @@
#define COOKIES_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "request.h"
#include "response.h"
-/* Parse cookie in request */
-void _parse_req_cookies(chttpx_request_t *req);
-
-/* Free cookies before response */
-void chttpx_free_req_cookie(chttpx_request_t* req);
-
-/**
- * Get cookie value by name.
- *
- * Searches for a cookie in the request by its name (case-insensitive).
- *
- * @param req Pointer to the HTTP request structure.
- * @param name Cookie name to search for.
- *
- * @return Pointer to the cookie value string if found,
- * or NULL if the cookie does not exist or input is invalid.
- */
-const chttpx_cookie_t* cHTTPX_CookieGet(chttpx_request_t *req, const char *name);
-
-/**
- * Set an HTTP cookie.
- *
- * This function formats a Set-Cookie header according to RFC 6265
- * and appends it to the header list using HeaderAdd.
- *
- * Supported attributes:
- * - Path
- * - Domain
- * - Expires (GMT format)
- * - SameSite (Lax, Strict, None)
- * - Secure
- * - HttpOnly
- *
- * @param req Pointer to HTTP request/response structure.
- * @param cookie Pointer to cookie structure.
- */
-int cHTTPX_CookieSet(chttpx_response_t* res, const chttpx_cookie_t* cookie);
+ /* Parse cookie in request */
+ void _parse_req_cookies(chttpx_request_t* req);
+
+ /* Free cookies before response */
+ void chttpx_free_req_cookie(chttpx_request_t* req);
+
+ /**
+ * Get cookie value by name.
+ *
+ * Searches for a cookie in the request by its name (case-insensitive).
+ *
+ * @param req Pointer to the HTTP request structure.
+ * @param name Cookie name to search for.
+ *
+ * @return Pointer to the cookie value string if found,
+ * or NULL if the cookie does not exist or input is invalid.
+ */
+ const chttpx_cookie_t* cHTTPX_CookieGet(chttpx_request_t* req, const char* name);
+
+ /**
+ * Set an HTTP cookie.
+ *
+ * This function formats a Set-Cookie header according to RFC 6265
+ * and appends it to the header list using HeaderAdd.
+ *
+ * Supported attributes:
+ * - Path
+ * - Domain
+ * - Expires (GMT format)
+ * - SameSite (Lax, Strict, None)
+ * - Secure
+ * - HttpOnly
+ *
+ * @param req Pointer to HTTP request/response structure.
+ * @param cookie Pointer to cookie structure.
+ */
+ int cHTTPX_CookieSet(chttpx_response_t* res, const chttpx_cookie_t* cookie);
#ifdef __cplusplus
}
diff --git a/include/cors.h b/include/cors.h
index ad59eea..8e5c088 100644
--- a/include/cors.h
+++ b/include/cors.h
@@ -9,47 +9,50 @@
#define CORS_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include
#include
-typedef struct {
- uint8_t enabled;
- /* Allowed urls */
- const char **origins;
- /* Origins count*/
- size_t origins_count;
- /* Allowed http methods */
- const char *methods;
- /* Allowed http headers */
- const char *headers;
-} chttpx_cors_t;
+ typedef struct
+ {
+ uint8_t enabled;
+ /* Allowed urls */
+ const char** origins;
+ /* Origins count*/
+ size_t origins_count;
+ /* Allowed http methods */
+ const char* methods;
+ /* Allowed http headers */
+ const char* headers;
+ } chttpx_cors_t;
-/**
- * Enable and configure CORS (Cross-Origin Resource Sharing).
- *
- * This function enables CORS support for the HTTP server and configures
- * which origins, HTTP methods, and request headers are allowed.
- *
- * The CORS configuration is applied globally and is typically used together
- * with the built-in CORS middleware.
- *
- * @param origins Array of allowed origin strings (e.g. "https://example.com").
- * Each origin must match exactly the value of the "Origin" header.
- * @param origins_count Number of elements in the origins array.
- * @param methods Comma-separated list of allowed HTTP methods.
- * If NULL, defaults to:
- * "GET, POST, PUT, DELETE, OPTIONS"
- * @param headers Comma-separated list of allowed request headers.
- * If NULL, defaults to:
- * "Content-Type"
- */
-void cHTTPX_Cors(const char **origins, size_t origins_count, const char *methods, const char *headers);
+ /**
+ * Enable and configure CORS (Cross-Origin Resource Sharing).
+ *
+ * This function enables CORS support for the HTTP server and configures
+ * which origins, HTTP methods, and request headers are allowed.
+ *
+ * The CORS configuration is applied globally and is typically used together
+ * with the built-in CORS middleware.
+ *
+ * @param origins Array of allowed origin strings (e.g. "https://example.com").
+ * Each origin must match exactly the value of the "Origin" header.
+ * @param origins_count Number of elements in the origins array.
+ * @param methods Comma-separated list of allowed HTTP methods.
+ * If NULL, defaults to:
+ * "GET, POST, PUT, DELETE, OPTIONS"
+ * @param headers Comma-separated list of allowed request headers.
+ * If NULL, defaults to:
+ * "Content-Type"
+ */
+ void cHTTPX_Cors(const char** origins, size_t origins_count, const char* methods, const char* headers);
#ifdef __cplusplus
-extern }
+ extern
+}
#endif
#endif
\ No newline at end of file
diff --git a/include/crosspltm.h b/include/crosspltm.h
index 977665e..2e995f6 100644
--- a/include/crosspltm.h
+++ b/include/crosspltm.h
@@ -2,50 +2,53 @@
#define CROSSPLTM_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include
#if defined(_WIN32) || defined(_WIN64)
- #define CHTTPX_PLATFORM_WINDOWS
+#define CHTTPX_PLATFORM_WINDOWS
#else
- #define CHTTPX_PLATFORM_POSIX
+#define CHTTPX_PLATFORM_POSIX
#endif
#ifdef CHTTPX_PLATFORM_WINDOWS
- #define strdup _strdup
+#define strdup _strdup
#else
- #define strdup strdup
+#define strdup strdup
#endif
#ifdef CHTTPX_PLATFORM_WINDOWS
- #define chttpx_close(s) closesocket(s)
+#define chttpx_close(s) closesocket(s)
#else
- #define chttpx_close(s) close(s)
+#define chttpx_close(s) close(s)
#endif
#ifdef CHTTPX_PLATFORM_WINDOWS
- #include
- #include
- #include
- #include
+#include
+#include
+#include
+#include
#endif
#ifdef _WIN32
typedef SOCKET chttpx_socket_t;
#else
- typedef int chttpx_socket_t;
+typedef int chttpx_socket_t;
#endif
#ifdef CHTTPX_PLATFORM_WINDOWS
- static struct tm *localtime_r(const time_t *timep, struct tm *result) {
+ static struct tm* localtime_r(const time_t* timep, struct tm* result)
+ {
memset(result, 0, sizeof(*result));
localtime_s(result, timep);
return result;
}
- static struct tm *gmtime_r(const time_t *timep, struct tm *result) {
+ static struct tm* gmtime_r(const time_t* timep, struct tm* result)
+ {
memset(result, 0, sizeof(*result));
gmtime_s(result, timep);
return result;
@@ -53,32 +56,37 @@ extern "C" {
#endif
#ifdef CHTTPX_PLATFORM_POSIX
- #include
- #include
- #include
- #include
+#include
+#include
+#include
+#include
#endif
#ifdef CHTTPX_PLATFORM_WINDOWS
- #define strcasecmp _stricmp
+#define strcasecmp _stricmp
#endif
#ifdef CHTTPX_PLATFORM_WINDOWS
- static void* memmem_win(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
- if (!needlelen) return (void *)haystack;
- if (needlelen > haystacklen) return NULL;
-
- const unsigned char *h = haystack;
- const unsigned char *n = needle;
-
- for (size_t i = 0; i <= haystacklen - needlelen; i++) {
- if (h[i] == n[0] && memcmp(h + i, n, needlelen) == 0) return (void *)(h + i);
+ static void* memmem_win(const void* haystack, size_t haystacklen, const void* needle, size_t needlelen)
+ {
+ if (!needlelen)
+ return (void*)haystack;
+ if (needlelen > haystacklen)
+ return NULL;
+
+ const unsigned char* h = haystack;
+ const unsigned char* n = needle;
+
+ for (size_t i = 0; i <= haystacklen - needlelen; i++)
+ {
+ if (h[i] == n[0] && memcmp(h + i, n, needlelen) == 0)
+ return (void*)(h + i);
}
return NULL;
}
- #define memmem(haystack, haystacklen, needle, needlelen) memmem_win(haystack, haystacklen, needle, needlelen)
+#define memmem(haystack, haystacklen, needle, needlelen) memmem_win(haystack, haystacklen, needle, needlelen)
#endif
#ifdef __cplusplus
diff --git a/include/headers.h b/include/headers.h
index 9a0e951..ca63882 100644
--- a/include/headers.h
+++ b/include/headers.h
@@ -9,58 +9,60 @@
#define HEADERS_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "request.h"
#include "response.h"
-/**
- * Get a request header by name.
- * @param req Pointer to the HTTP request.
- * @param name Header name (case-insensitive).
- * @return Pointer to header value if found, otherwise NULL.
- */
-const char* cHTTPX_HeaderGet(chttpx_request_t *req, const char *name);
+ /**
+ * Get a request header by name.
+ * @param req Pointer to the HTTP request.
+ * @param name Header name (case-insensitive).
+ * @return Pointer to header value if found, otherwise NULL.
+ */
+ const char* cHTTPX_HeaderGet(chttpx_request_t* req, const char* name);
-/**
- * Add a new HTTP header.
- *
- * This function appends a header to the request/response header list.
- * Unlike HeaderSet, it does NOT replace existing headers with the same name.
- * This is required for headers like "Set-Cookie" that may appear multiple times.
- *
- * @param res Pointer to HTTP request/response structure.
- * @param name Header name.
- * @param value Header value.
- */
-int cHTTPX_HeaderAdd(chttpx_response_t* res, const char* name, const char* value);
+ /**
+ * Add a new HTTP header.
+ *
+ * This function appends a header to the request/response header list.
+ * Unlike HeaderSet, it does NOT replace existing headers with the same name.
+ * This is required for headers like "Set-Cookie" that may appear multiple times.
+ *
+ * @param res Pointer to HTTP request/response structure.
+ * @param name Header name.
+ * @param value Header value.
+ */
+ int cHTTPX_HeaderAdd(chttpx_response_t* res, const char* name, const char* value);
-/**
- * Set or add a request header.
- * If header exists (case-insensitive), its value will be replaced.
- * Otherwise a new header will be added.
- *
- * @param req Pointer to the HTTP request.
- * @param name Header name.
- * @param value Header value.
- * @return 0 on success, -1 on error.
- */
-int cHTTPX_HeaderSet(chttpx_request_t *req, const char *name, const char *value);
+ /**
+ * Set or add a request header.
+ * If header exists (case-insensitive), its value will be replaced.
+ * Otherwise a new header will be added.
+ *
+ * @param req Pointer to the HTTP request.
+ * @param name Header name.
+ * @param value Header value.
+ * @return 0 on success, -1 on error.
+ */
+ int cHTTPX_HeaderSet(chttpx_request_t* req, const char* name, const char* value);
-/**
- * Get the client's IP from the HEADER request.
- *
- * @param req a pointer to the query structure
- * @return const char* Client's IP
- */
-const char *cHTTPX_ClientIP(chttpx_request_t *req);
+ /**
+ * Get the client's IP from the HEADER request.
+ *
+ * @param req a pointer to the query structure
+ * @return const char* Client's IP
+ */
+ const char* cHTTPX_ClientIP(chttpx_request_t* req);
-/* Parse headers in request */
-void _parse_req_headers(chttpx_request_t *req, char *buffer, size_t buffer_len);
+ /* Parse headers in request */
+ void _parse_req_headers(chttpx_request_t* req, char* buffer, size_t buffer_len);
#ifdef __cplusplus
-extern }
+ extern
+}
#endif
#endif
\ No newline at end of file
diff --git a/include/http.h b/include/http.h
index 78f9bd8..cd8da45 100644
--- a/include/http.h
+++ b/include/http.h
@@ -9,85 +9,86 @@
#define HTTP_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
/* HTTP Content Types */
/* HTML document. Use this for web pages rendered by browsers. */
-#define cHTTPX_CTYPE_HTML "text/html"
+#define cHTTPX_CTYPE_HTML "text/html"
/* Plain text. Use for simple text responses or logs. */
-#define cHTTPX_CTYPE_TEXT "text/plain"
+#define cHTTPX_CTYPE_TEXT "text/plain"
/* XML document. Use for XML-based APIs or configurations. */
-#define cHTTPX_CTYPE_XML "application/xml"
+#define cHTTPX_CTYPE_XML "application/xml"
/* CSS stylesheet. Use when returning CSS files for web pages. */
-#define cHTTPX_CTYPE_CSS "text/css"
+#define cHTTPX_CTYPE_CSS "text/css"
/* CSV file. Use for spreadsheet-style data exports. */
-#define cHTTPX_CTYPE_CSV "text/csv"
+#define cHTTPX_CTYPE_CSV "text/csv"
/* JSON data. Use for REST API responses and requests. */
-#define cHTTPX_CTYPE_JSON "application/json"
+#define cHTTPX_CTYPE_JSON "application/json"
/* URL-encoded form data. Typical for HTML form submissions. */
-#define cHTTPX_CTYPE_FORM "application/x-www-form-urlencoded"
+#define cHTTPX_CTYPE_FORM "application/x-www-form-urlencoded"
/* Multipart form data. Used for file uploads via forms. */
-#define cHTTPX_CTYPE_MULTI "multipart/form-data"
+#define cHTTPX_CTYPE_MULTI "multipart/form-data"
/* Raw binary stream. Use when content type is unknown. */
-#define cHTTPX_CTYPE_OCTET "application/octet-stream"
+#define cHTTPX_CTYPE_OCTET "application/octet-stream"
/* JavaScript script file. Used for web applications. */
-#define cHTTPX_CTYPE_JS "application/javascript"
+#define cHTTPX_CTYPE_JS "application/javascript"
/* PNG image format. Lossless compressed image. */
-#define cHTTPX_CTYPE_PNG "image/png"
+#define cHTTPX_CTYPE_PNG "image/png"
/* JPEG image format. Common for photos. */
-#define cHTTPX_CTYPE_JPEG "image/jpeg"
+#define cHTTPX_CTYPE_JPEG "image/jpeg"
/* GIF image format. Supports simple animations. */
-#define cHTTPX_CTYPE_GIF "image/gif"
+#define cHTTPX_CTYPE_GIF "image/gif"
/* WebP image format. Modern compressed image format. */
-#define cHTTPX_CTYPE_WEBP "image/webp"
+#define cHTTPX_CTYPE_WEBP "image/webp"
/* SVG vector image format. */
-#define cHTTPX_CTYPE_SVG "image/svg+xml"
+#define cHTTPX_CTYPE_SVG "image/svg+xml"
/* BMP bitmap image format. Rarely used on the web. */
-#define cHTTPX_CTYPE_BMP "image/bmp"
+#define cHTTPX_CTYPE_BMP "image/bmp"
/* MP3 audio format. Common compressed audio. */
-#define cHTTPX_CTYPE_MP3 "audio/mpeg"
+#define cHTTPX_CTYPE_MP3 "audio/mpeg"
/* WAV audio format. Uncompressed audio. */
-#define cHTTPX_CTYPE_WAV "audio/wav"
+#define cHTTPX_CTYPE_WAV "audio/wav"
/* OGG audio format. Open-source audio container. */
-#define cHTTPX_CTYPE_OGG "audio/ogg"
+#define cHTTPX_CTYPE_OGG "audio/ogg"
/* MP4 video format. Most common video container. */
-#define cHTTPX_CTYPE_MP4 "video/mp4"
+#define cHTTPX_CTYPE_MP4 "video/mp4"
/* WebM video format. Open-source video format. */
-#define cHTTPX_CTYPE_WEBM "video/webm"
+#define cHTTPX_CTYPE_WEBM "video/webm"
/* AVI video format. Older Microsoft video format. */
-#define cHTTPX_CTYPE_AVI "video/x-msvideo"
+#define cHTTPX_CTYPE_AVI "video/x-msvideo"
/* ZIP archive file. */
-#define cHTTPX_CTYPE_ZIP "application/zip"
+#define cHTTPX_CTYPE_ZIP "application/zip"
/* RAR archive file. */
-#define cHTTPX_CTYPE_RAR "application/vnd.rar"
+#define cHTTPX_CTYPE_RAR "application/vnd.rar"
/* 7-Zip archive file. */
-#define cHTTPX_CTYPE_7Z "application/x-7z-compressed"
+#define cHTTPX_CTYPE_7Z "application/x-7z-compressed"
/* PDF document file. */
-#define cHTTPX_CTYPE_PDF "application/pdf"
+#define cHTTPX_CTYPE_PDF "application/pdf"
/* Microsoft Word DOC document. */
-#define cHTTPX_CTYPE_DOC "application/msword"
+#define cHTTPX_CTYPE_DOC "application/msword"
/* Microsoft Word DOCX document. */
-#define cHTTPX_CTYPE_DOCX "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
+#define cHTTPX_CTYPE_DOCX "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
/* Microsoft Excel XLS spreadsheet. */
-#define cHTTPX_CTYPE_XLS "application/vnd.ms-excel"
+#define cHTTPX_CTYPE_XLS "application/vnd.ms-excel"
/* Microsoft Excel XLSX spreadsheet. */
-#define cHTTPX_CTYPE_XLSX "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+#define cHTTPX_CTYPE_XLSX "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
/* Web Open Font Format. */
-#define cHTTPX_CTYPE_WOFF "font/woff"
+#define cHTTPX_CTYPE_WOFF "font/woff"
/* Web Open Font Format 2. */
-#define cHTTPX_CTYPE_WOFF2 "font/woff2"
+#define cHTTPX_CTYPE_WOFF2 "font/woff2"
/* TrueType font. */
-#define cHTTPX_CTYPE_TTF "font/ttf"
+#define cHTTPX_CTYPE_TTF "font/ttf"
/* OpenType font. */
-#define cHTTPX_CTYPE_OTF "font/otf"
+#define cHTTPX_CTYPE_OTF "font/otf"
/* HTTP methods */
-#define cHTTPX_MethodGet "GET"
-#define cHTTPX_MethodPost "POST"
-#define cHTTPX_MethodPut "PUT"
-#define cHTTPX_MethodPatch "PATCH"
-#define cHTTPX_MethodDelete "DELETE"
+#define cHTTPX_MethodGet "GET"
+#define cHTTPX_MethodPost "POST"
+#define cHTTPX_MethodPut "PUT"
+#define cHTTPX_MethodPatch "PATCH"
+#define cHTTPX_MethodDelete "DELETE"
#define cHTTPX_MethodOptions "OPTIONS"
/* HTTP statuses */
@@ -172,7 +173,8 @@ extern "C" {
#define cHTTPX_StatusInvalidSSLCertificate 526
#ifdef __cplusplus
-extern }
+ extern
+}
#endif
#endif
\ No newline at end of file
diff --git a/include/i18n.h b/include/i18n.h
index 277ce3f..ea4c4b3 100644
--- a/include/i18n.h
+++ b/include/i18n.h
@@ -9,7 +9,8 @@
#define I18N_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include
@@ -17,75 +18,79 @@ extern "C" {
#define MAX_LOCALES 64
-typedef struct {
- char *key;
- char *value;
-} i18n_entry_t;
+ typedef struct
+ {
+ char* key;
+ char* value;
+ } i18n_entry_t;
-typedef struct {
- /* Language en, ru, es */
- char locale[8];
+ typedef struct
+ {
+ /* Language en, ru, es */
+ char locale[8];
- /* Entries i18n */
- i18n_entry_t *entries;
- size_t count;
-} i18n_locale_t;
+ /* Entries i18n */
+ i18n_entry_t* entries;
+ size_t count;
+ } i18n_locale_t;
-typedef struct {
- i18n_locale_t locales[MAX_LOCALES];
- size_t count;
- i18n_locale_t *default_locale;
-} i18n_manager_t;
+ typedef struct
+ {
+ i18n_locale_t locales[MAX_LOCALES];
+ size_t count;
+ i18n_locale_t* default_locale;
+ } i18n_manager_t;
-typedef enum {
- LANG_EN,
- LANG_RU,
- LANG_ES,
- LANG_FR,
- LANG_COUNT
-} i18n_language_t;
+ typedef enum
+ {
+ LANG_EN,
+ LANG_RU,
+ LANG_ES,
+ LANG_FR,
+ LANG_COUNT
+ } i18n_language_t;
-i18n_language_t i18n_lang_from_string(const char* code);
+ i18n_language_t i18n_lang_from_string(const char* code);
-/**
- * Initializes the global i18n manager.
- *
- * Loads all locale JSON files from the specified directory.
- * The file name determines the locale language:
- * en.json -> "en"
- * ru.json -> "ru"
- * fr.json -> "fr"
- *
- * All translations are stored globally in memory and are used by the cHTTPX_i18n_t() function.
- *
- * The memory is automatically freed when the program ends.
- *
- * @param directory The path to the directory with locale JSON files.
- *
- * Example:
- * cHTTPX_i18n("public");
- */
-void cHTTPX_i18n(const char *directory);
+ /**
+ * Initializes the global i18n manager.
+ *
+ * Loads all locale JSON files from the specified directory.
+ * The file name determines the locale language:
+ * en.json -> "en"
+ * ru.json -> "ru"
+ * fr.json -> "fr"
+ *
+ * All translations are stored globally in memory and are used by the cHTTPX_i18n_t() function.
+ *
+ * The memory is automatically freed when the program ends.
+ *
+ * @param directory The path to the directory with locale JSON files.
+ *
+ * Example:
+ * cHTTPX_i18n("public");
+ */
+ void cHTTPX_i18n(const char* directory);
-/**
- * Returns a translation by key and language.
- *
- * Searches for a translation by key in the specified locale.
- * If the language is not found, the default locale is used.
- * If the key is not found, the key itself is returned.
- *
- * The function does not allocate memory — the returned string
- * belongs to the i18n manager.
- *
- * @param key Translation key (for example: "welcome").
- * @param lang Language code ("en", "ru", NULL for default).
- *
- * @return The translation string or key if the translation is not found.
- *
- * Example:
- * const char* text = cHTTPX_i18n_t("welcome", "ru");
- */
-const char* cHTTPX_i18n_t(const char *key, const char *lang);
+ /**
+ * Returns a translation by key and language.
+ *
+ * Searches for a translation by key in the specified locale.
+ * If the language is not found, the default locale is used.
+ * If the key is not found, the key itself is returned.
+ *
+ * The function does not allocate memory — the returned string
+ * belongs to the i18n manager.
+ *
+ * @param key Translation key (for example: "welcome").
+ * @param lang Language code ("en", "ru", NULL for default).
+ *
+ * @return The translation string or key if the translation is not found.
+ *
+ * Example:
+ * const char* text = cHTTPX_i18n_t("welcome", "ru");
+ */
+ const char* cHTTPX_i18n_t(const char* key, const char* lang);
#ifdef __cplusplus
}
diff --git a/include/inet.h b/include/inet.h
index bf042a4..7adf27c 100644
--- a/include/inet.h
+++ b/include/inet.h
@@ -9,29 +9,30 @@
#define INET_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "crosspltm.h"
-/**
- * Get client IP address from the underlying socket connection.
- *
- * This function retrieves the real network-level IP address of the client
- * using the TCP socket (`getpeername`). It supports both IPv4 and IPv6.
- *
- * The returned value is a pointer to a static buffer, so it will be
- * overwritten on subsequent calls and is NOT thread-safe.
- *
- * This IP cannot be spoofed by HTTP headers, but if the server is behind
- * a reverse proxy (Nginx, CDN, load balancer), the returned address will
- * be the proxy’s IP instead of the original client.
- *
- * @param client_fd Connected client socket file descriptor.
- * @return Pointer to a string with the client IP address,
- * or "-" if the address cannot be determined.
- */
-const char* cHTTPX_ClientInetIP(chttpx_socket_t client_fd);
+ /**
+ * Get client IP address from the underlying socket connection.
+ *
+ * This function retrieves the real network-level IP address of the client
+ * using the TCP socket (`getpeername`). It supports both IPv4 and IPv6.
+ *
+ * The returned value is a pointer to a static buffer, so it will be
+ * overwritten on subsequent calls and is NOT thread-safe.
+ *
+ * This IP cannot be spoofed by HTTP headers, but if the server is behind
+ * a reverse proxy (Nginx, CDN, load balancer), the returned address will
+ * be the proxy’s IP instead of the original client.
+ *
+ * @param client_fd Connected client socket file descriptor.
+ * @return Pointer to a string with the client IP address,
+ * or "-" if the address cannot be determined.
+ */
+ const char* cHTTPX_ClientInetIP(chttpx_socket_t client_fd);
#ifdef __cplusplus
}
diff --git a/include/libchttpx.h b/include/libchttpx.h
index 41f94ca..6fe7bdf 100644
--- a/include/libchttpx.h
+++ b/include/libchttpx.h
@@ -9,7 +9,8 @@
#define LIBCHTTPX_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "http.h"
diff --git a/include/media.h b/include/media.h
index 7846e1b..06f6672 100644
--- a/include/media.h
+++ b/include/media.h
@@ -9,7 +9,8 @@
#define MEDIA_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "http.h"
@@ -17,13 +18,14 @@ extern "C" {
#define FILE_BUFFER 65536
-typedef struct {
- const char* ctype;
- const char* ext;
-} content_type_map_t;
+ typedef struct
+ {
+ const char* ctype;
+ const char* ext;
+ } content_type_map_t;
-/* Parse media in request */
-void _parse_media(chttpx_request_t* req, char* buffer, size_t buffer_len);
+ /* Parse media in request */
+ void _parse_media(chttpx_request_t* req, char* buffer, size_t buffer_len);
#ifdef __cplusplus
}
diff --git a/include/middlewares.h b/include/middlewares.h
index dda9c69..cdc9da4 100644
--- a/include/middlewares.h
+++ b/include/middlewares.h
@@ -9,7 +9,8 @@
#define MIDDLEWARES_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "request.h"
@@ -20,116 +21,117 @@ extern "C" {
#define MAX_MIDDLEWARES 128
-/* Enum for result all middlewares */
-typedef enum {
- out = 0,
- next = 1,
-} chttpx_middleware_result_t;
-
-typedef chttpx_middleware_result_t (*chttpx_middleware_t)(
- chttpx_request_t *req,
- chttpx_response_t *res
-);
-
-/* Struct for base middlewares */
-typedef struct {
- chttpx_middleware_t middlewares[MAX_MIDDLEWARES];
- size_t middleware_count;
-} chttpx_middleware_stack_t;
-
-/**
- * Register a global middleware function.
- *
- * Middleware functions are executed in the order they are registered,
- * before the route handler is called.
- *
- * If a middleware returns 0(out), the middleware chain is aborted and the
- * response provided by the middleware is sent to the client.
- *
- * If a middleware returns 1(next), processing continues to the next middleware
- * or to the route handler.
- *
- * @param mw Middleware function pointer.
- */
-void cHTTPX_MiddlewareUse(chttpx_middleware_t mw);
+ /* Enum for result all middlewares */
+ typedef enum
+ {
+ out = 0,
+ next = 1,
+ } chttpx_middleware_result_t;
+
+ typedef chttpx_middleware_result_t (*chttpx_middleware_t)(chttpx_request_t* req, chttpx_response_t* res);
+
+ /* Struct for base middlewares */
+ typedef struct
+ {
+ chttpx_middleware_t middlewares[MAX_MIDDLEWARES];
+ size_t middleware_count;
+ } chttpx_middleware_stack_t;
+
+ /**
+ * Register a global middleware function.
+ *
+ * Middleware functions are executed in the order they are registered,
+ * before the route handler is called.
+ *
+ * If a middleware returns 0(out), the middleware chain is aborted and the
+ * response provided by the middleware is sent to the client.
+ *
+ * If a middleware returns 1(next), processing continues to the next middleware
+ * or to the route handler.
+ *
+ * @param mw Middleware function pointer.
+ */
+ void cHTTPX_MiddlewareUse(chttpx_middleware_t mw);
#define MAX_MIDDLEWARE_RATE_LIMIT_TABLE_SIZE 4096
-/* Struct for middleware [RATE LIMITER]*/
-typedef struct {
- /* Start limit window time*/
- time_t window_start;
- /* How many requests have already been received in this window */
- uint32_t requests;
-} rate_limiter_entry_t;
-
-/**
- * Configure the rate limiter and register the middleware.
- *
- * Example:
- * cHTTPX_MiddlewareRateLimiter(10, 1); // 10 requests per second
- *
- * @param max_requests maximum number of requests
- * @param window_sec time window in seconds
- */
-void cHTTPX_MiddlewareRateLimiter(uint32_t max_requests, uint32_t window_sec);
-
-/**
- * Initialize global recovery signal handlers.
- *
- * This function installs signal handlers for critical runtime errors
- * such as segmentation faults, abort signals, and floating-point exceptions.
- *
- * When a registered signal is raised during request processing,
- * the handler will transfer control back to the recovery middleware
- * using setjmp/longjmp instead of terminating the process.
- */
-void _recovery_init(void);
-
-/**
- * Recovery middleware.
- *
- * This middleware protects the request processing pipeline from fatal
- * runtime errors such as segmentation faults.
- *
- * Internally, it uses setjmp/longjmp together with POSIX signal handlers
- * to recover control flow if a critical signal occurs while handling
- * the request.
- *
- * If a signal is caught:
- * - The error is logged to stderr
- * - A 500 Internal Server Error JSON response is returned
- * - Further middleware and handlers are skipped
- *
- * @param req Pointer to the HTTP request structure.
- * @param res Pointer to the HTTP response structure.
- */
-void cHTTPX_MiddlewareRecovery();
-
-/**
- * Writes the HTTP request and response log to a file.
- *
- * This function is called after a request has been processed and a response
- * has been generated. It collects information about the client, HTTP method,
- * request path, protocol, response status, response size, and processing time,
- * then writes it to a log file.
- *
- * @param req Pointer to the chttpx_request_t request structure.
- * @param res Pointer to the chttpx_response_t response structure.
- */
-void postmiddleware_logging_write(chttpx_request_t* req, chttpx_response_t* res);
-
-/**
- * Registers a middleware for logging HTTP requests.
- *
- * This middleware is executed after every request to log request and response
- * information into a log file. If logging has not been initialized via
- * cHTTPX_LoggingInit, this middleware does not perform any logging.
- */
-void cHTTPX_MiddlewareLogging();
+ /* Struct for middleware [RATE LIMITER]*/
+ typedef struct
+ {
+ /* Start limit window time*/
+ time_t window_start;
+ /* How many requests have already been received in this window */
+ uint32_t requests;
+ } rate_limiter_entry_t;
+
+ /**
+ * Configure the rate limiter and register the middleware.
+ *
+ * Example:
+ * cHTTPX_MiddlewareRateLimiter(10, 1); // 10 requests per second
+ *
+ * @param max_requests maximum number of requests
+ * @param window_sec time window in seconds
+ */
+ void cHTTPX_MiddlewareRateLimiter(uint32_t max_requests, uint32_t window_sec);
+
+ /**
+ * Initialize global recovery signal handlers.
+ *
+ * This function installs signal handlers for critical runtime errors
+ * such as segmentation faults, abort signals, and floating-point exceptions.
+ *
+ * When a registered signal is raised during request processing,
+ * the handler will transfer control back to the recovery middleware
+ * using setjmp/longjmp instead of terminating the process.
+ */
+ void _recovery_init(void);
+
+ /**
+ * Recovery middleware.
+ *
+ * This middleware protects the request processing pipeline from fatal
+ * runtime errors such as segmentation faults.
+ *
+ * Internally, it uses setjmp/longjmp together with POSIX signal handlers
+ * to recover control flow if a critical signal occurs while handling
+ * the request.
+ *
+ * If a signal is caught:
+ * - The error is logged to stderr
+ * - A 500 Internal Server Error JSON response is returned
+ * - Further middleware and handlers are skipped
+ *
+ * @param req Pointer to the HTTP request structure.
+ * @param res Pointer to the HTTP response structure.
+ */
+ void cHTTPX_MiddlewareRecovery();
+
+ /**
+ * Writes the HTTP request and response log to a file.
+ *
+ * This function is called after a request has been processed and a response
+ * has been generated. It collects information about the client, HTTP method,
+ * request path, protocol, response status, response size, and processing time,
+ * then writes it to a log file.
+ *
+ * @param req Pointer to the chttpx_request_t request structure.
+ * @param res Pointer to the chttpx_response_t response structure.
+ */
+ void postmiddleware_logging_write(chttpx_request_t* req, chttpx_response_t* res);
+
+ /**
+ * Registers a middleware for logging HTTP requests.
+ *
+ * This middleware is executed after every request to log request and response
+ * information into a log file. If logging has not been initialized via
+ * cHTTPX_LoggingInit, this middleware does not perform any logging.
+ */
+ void cHTTPX_MiddlewareLogging();
#ifdef __cplusplus
-extern }
+ extern
+}
#endif
#endif
\ No newline at end of file
diff --git a/include/params.h b/include/params.h
index cbf8ed0..4419efc 100644
--- a/include/params.h
+++ b/include/params.h
@@ -9,22 +9,24 @@
#define PARAMS_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "request.h"
-/**
- * Get a route parameter value by its name.
- * @param req Pointer to the current HTTP request structure.
- * @param name Name of the route parameter (e.g., "uuid").
- *
- * @return Pointer to the parameter value string if found, or NULL if the parameter does not exist.
- */
-const char* cHTTPX_Param(chttpx_request_t *req, const char *name);
+ /**
+ * Get a route parameter value by its name.
+ * @param req Pointer to the current HTTP request structure.
+ * @param name Name of the route parameter (e.g., "uuid").
+ *
+ * @return Pointer to the parameter value string if found, or NULL if the parameter does not exist.
+ */
+ const char* cHTTPX_Param(chttpx_request_t* req, const char* name);
#ifdef __cplusplus
-extern }
+ extern
+}
#endif
#endif
\ No newline at end of file
diff --git a/include/queries.h b/include/queries.h
index 6a5dc87..0536832 100644
--- a/include/queries.h
+++ b/include/queries.h
@@ -9,28 +9,30 @@
#define QUERIES_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "request.h"
-/**
- * Get a query parameter value by name.
- *
- * Searches the parsed URL query parameters (e.g. ?name=value&age=10)
- * and returns the value associated with the given parameter name.
- *
- * @param req Pointer to the current HTTP request.
- * @param name Name of the query parameter.
- * @return Pointer to the parameter value string if found, or NULL if not present.
- */
-const char* cHTTPX_Query(chttpx_request_t *req, const char *name);
+ /**
+ * Get a query parameter value by name.
+ *
+ * Searches the parsed URL query parameters (e.g. ?name=value&age=10)
+ * and returns the value associated with the given parameter name.
+ *
+ * @param req Pointer to the current HTTP request.
+ * @param name Name of the query parameter.
+ * @return Pointer to the parameter value string if found, or NULL if not present.
+ */
+ const char* cHTTPX_Query(chttpx_request_t* req, const char* name);
-/* Parse queries in request */
-void _parse_req_query(chttpx_request_t *req, char *query);
+ /* Parse queries in request */
+ void _parse_req_query(chttpx_request_t* req, char* query);
#ifdef __cplusplus
-extern }
+ extern
+}
#endif
#endif
\ No newline at end of file
diff --git a/include/request.h b/include/request.h
index e22c7b0..006cca0 100644
--- a/include/request.h
+++ b/include/request.h
@@ -9,7 +9,8 @@
#define REQUEST_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "crosspltm.h"
@@ -25,175 +26,185 @@ extern "C" {
#define MAX_HEADER_NAME 128
#define MAX_HEADER_VALUE 4096
-/* Header structure */
-typedef struct {
- char name[MAX_HEADER_NAME];
- char value[MAX_HEADER_VALUE];
-} chttpx_header_t;
+ /* Header structure */
+ typedef struct
+ {
+ char name[MAX_HEADER_NAME];
+ char value[MAX_HEADER_VALUE];
+ } chttpx_header_t;
-/* Query structure */
-typedef struct {
- char *name;
- char *value;
-} chttpx_query_t;
+ /* Query structure */
+ typedef struct
+ {
+ char* name;
+ char* value;
+ } chttpx_query_t;
#define MAX_PARAMS 64
#define MAX_PARAM_NAME 128
#define MAX_PARAM_VALUE 1024
-/* Param structure */
-typedef struct {
- char name[MAX_PARAM_NAME];
- char value[MAX_PARAM_VALUE];
-} chttpx_param_t;
+ /* Param structure */
+ typedef struct
+ {
+ char name[MAX_PARAM_NAME];
+ char value[MAX_PARAM_VALUE];
+ } chttpx_param_t;
#define MAX_COOKIES 64
-/* Cookie structure */
-typedef struct {
- char* name;
- char* value;
+ /* Cookie structure */
+ typedef struct
+ {
+ char* name;
+ char* value;
- char* path;
- char* domain;
+ char* path;
+ char* domain;
- time_t expires;
+ time_t expires;
- bool http_only;
- bool secure;
+ bool http_only;
+ bool secure;
- /* 0 - None; 1 - Lax; 2 - Strict; 3 - None */
- int same_site;
-} chttpx_cookie_t;
+ /* 0 - None; 1 - Lax; 2 - Strict; 3 - None */
+ int same_site;
+ } chttpx_cookie_t;
-/* Validation structs */
-typedef enum {
- FIELD_STRING,
- FIELD_NUMBER,
- FIELD_BOOL,
- FIELD_STRING_ARRAY,
- FIELD_NUMBER_ARRAY
-} validation_t;
-
-typedef struct {
- char** items;
- size_t count;
-} chttpx_string_array_t;
-
-typedef struct {
- int* items;
- size_t count;
-} chttpx_number_array_t;
-
-typedef enum {
- VALIDATOR_NONE,
- VALIDATOR_EMAIL,
- VALIDATOR_PHONE,
- VALIDATOR_URL,
-} validator_type_t;
-
-typedef struct {
- const char *name;
-
- /* Target value in struct */
- void *target;
-
- /* Required field */
- bool required;
-
- /* Min/Max value string */
- size_t min_length;
- size_t max_length;
-
- /* Type field str/int/bool */
- validation_t type;
-
- /* Custom validator */
- validator_type_t validator;
-
- /* Present type for boolean required */
- uint8_t present;
-} chttpx_validation_t;
-
-/* Function for free REQuest context */
-typedef void (*chttpx_context_free_fn)(void*);
-
-// REQuest
-typedef struct {
- char* method;
- char* path;
-
- /* Body */
- unsigned char* body;
- size_t body_size;
-
- /* Content len. REQuest */
- size_t content_length;
-
- /* Content type REQuest */
- char content_type[512];
-
- /* Client socket */
- chttpx_socket_t client_fd;
-
- /* User-Agent */
- char user_agent[512];
-
- /* HTTP/1.1 HTTP/2 ... */
- char protocol[16];
-
- /* Client IP REQuest */
- char client_ip[46];
-
- /* Error REQuest message */
- char error_msg[BUFFER_SIZE];
-
- /* Headers in REQuest */
- chttpx_header_t headers[MAX_HEADERS];
- size_t headers_count;
-
- /* Query params in URL
- * exmaple: ?name=netcorelink
- */
- chttpx_query_t* query;
- size_t query_count;
-
- /* Params in URL
- * exmaple: /{uuid}
+ /* Validation structs */
+ typedef enum
+ {
+ FIELD_STRING,
+ FIELD_NUMBER,
+ FIELD_BOOL,
+ FIELD_STRING_ARRAY,
+ FIELD_NUMBER_ARRAY
+ } validation_t;
+
+ typedef struct
+ {
+ char** items;
+ size_t count;
+ } chttpx_string_array_t;
+
+ typedef struct
+ {
+ int* items;
+ size_t count;
+ } chttpx_number_array_t;
+
+ typedef enum
+ {
+ VALIDATOR_NONE,
+ VALIDATOR_EMAIL,
+ VALIDATOR_PHONE,
+ VALIDATOR_URL,
+ } validator_type_t;
+
+ typedef struct
+ {
+ const char* name;
+
+ /* Target value in struct */
+ void* target;
+
+ /* Required field */
+ bool required;
+
+ /* Min/Max value string */
+ size_t min_length;
+ size_t max_length;
+
+ /* Type field str/int/bool */
+ validation_t type;
+
+ /* Custom validator */
+ validator_type_t validator;
+
+ /* Present type for boolean required */
+ uint8_t present;
+ } chttpx_validation_t;
+
+ /* Function for free REQuest context */
+ typedef void (*chttpx_context_free_fn)(void*);
+
+ // REQuest
+ typedef struct
+ {
+ char* method;
+ char* path;
+
+ /* Body */
+ unsigned char* body;
+ size_t body_size;
+
+ /* Content len. REQuest */
+ size_t content_length;
+
+ /* Content type REQuest */
+ char content_type[512];
+
+ /* Client socket */
+ chttpx_socket_t client_fd;
+
+ /* User-Agent */
+ char user_agent[512];
+
+ /* HTTP/1.1 HTTP/2 ... */
+ char protocol[16];
+
+ /* Client IP REQuest */
+ char client_ip[46];
+
+ /* Error REQuest message */
+ char error_msg[BUFFER_SIZE];
+
+ /* Headers in REQuest */
+ chttpx_header_t headers[MAX_HEADERS];
+ size_t headers_count;
+
+ /* Query params in URL
+ * exmaple: ?name=netcorelink
+ */
+ chttpx_query_t* query;
+ size_t query_count;
+
+ /* Params in URL
+ * exmaple: /{uuid}
+ */
+ chttpx_param_t params[MAX_PARAMS];
+ size_t params_count;
+
+ /* Cookies */
+ chttpx_cookie_t cookies[MAX_COOKIES];
+ size_t cookies_count;
+
+ /* Media
+ * @filename - File name
+ */
+ char filename[384];
+
+ /* Context REQuest */
+ void* context;
+ chttpx_context_free_fn context_free;
+ } chttpx_request_t;
+
+ /**
+ * Parse a JSON body and validate fields according to the provided definitions.
+ * @param req Pointer to the HTTP request.
+ * @param fields Array of field validation definitions (cHTTPX_FieldValidation).
+ * @param field_count Number of fields in the array.
+ * @return 1 if parsing and validation succeed, 0 if there is an error.
+ * This function automatically checks required fields, string length, boolean types, etc.
*/
- chttpx_param_t params[MAX_PARAMS];
- size_t params_count;
+ int cHTTPX_Parse(chttpx_request_t* req, chttpx_validation_t* fields, size_t field_count);
- /* Cookies */
- chttpx_cookie_t cookies[MAX_COOKIES];
- size_t cookies_count;
-
- /* Media
- * @filename - File name
+ /*
+ * Validates an array of cHTTPX_FieldValidation structures.
+ * This function ensures that required fields are present, string lengths are within limits,
+ * and basic validation for integers and boolean fields is performed.
*/
- char filename[384];
-
- /* Context REQuest */
- void* context;
- chttpx_context_free_fn context_free;
-} chttpx_request_t;
-
-/**
- * Parse a JSON body and validate fields according to the provided definitions.
- * @param req Pointer to the HTTP request.
- * @param fields Array of field validation definitions (cHTTPX_FieldValidation).
- * @param field_count Number of fields in the array.
- * @return 1 if parsing and validation succeed, 0 if there is an error.
- * This function automatically checks required fields, string length, boolean types, etc.
- */
-int cHTTPX_Parse(chttpx_request_t *req, chttpx_validation_t *fields, size_t field_count);
-
-/*
- * Validates an array of cHTTPX_FieldValidation structures.
- * This function ensures that required fields are present, string lengths are within limits,
- * and basic validation for integers and boolean fields is performed.
- */
-int cHTTPX_Validate(chttpx_request_t *req, chttpx_validation_t *fields, size_t field_count, const char* l);
+ int cHTTPX_Validate(chttpx_request_t* req, chttpx_validation_t* fields, size_t field_count, const char* l);
/**
* Macro to define a string field for JSON request validation.
@@ -209,7 +220,8 @@ int cHTTPX_Validate(chttpx_request_t *req, chttpx_validation_t *fields, size_t f
*
* @return A chttpx_validation_t structure initialized for a string field.
*/
-#define chttpx_validation_string(name, ptr, required, min_length, max_length, validator) (chttpx_validation_t){name, ptr, required, min_length, max_length, FIELD_STRING, validator, 0}
+#define chttpx_validation_string(name, ptr, required, min_length, max_length, validator) \
+ (chttpx_validation_t){name, ptr, required, min_length, max_length, FIELD_STRING, validator, 0}
/**
* Macro to define an integer field for JSON request validation.
@@ -235,9 +247,9 @@ int cHTTPX_Validate(chttpx_request_t *req, chttpx_validation_t *fields, size_t f
*/
#define chttpx_validation_boolean(name, ptr, required) (chttpx_validation_t){name, ptr, required, 0, 0, FIELD_BOOL, VALIDATOR_NONE, 0}
-
#ifdef __cplusplus
-extern }
+ extern
+}
#endif
#endif
diff --git a/include/response.h b/include/response.h
index eb0f86c..860deab 100644
--- a/include/response.h
+++ b/include/response.h
@@ -9,99 +9,102 @@
#define RESPONSE_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "request.h"
#include
-// RESponse
-typedef struct {
- /* Response status code */
- int status;
-
- /* Response content type */
- const char *content_type;
-
- /* Headers in REQuest */
- chttpx_header_t headers[MAX_HEADERS];
- size_t headers_count;
-
- /* Response body */
- const unsigned char *body;
- /* Response body size */
- size_t body_size;
-
- /* Times for logging */
- struct timespec start_ts;
- struct timespec end_ts;
-} chttpx_response_t;
-
-/* handler */
-typedef void (*chttpx_handler_t)(chttpx_request_t *req, chttpx_response_t *res);
-
-/**
- * Handle a single client connection.
- * @param arg The file descriptor of the accepted client socket.
- * This function reads the request, parses it, calls the matching route handler,
- * and sends the response back to the client.
- */
-void* chttpx_handle(void* arg);
-
-/**
- * Create a JSON HTTP response with formatted content.
- *
- * Formats a JSON response body using printf-style arguments,
- * allocates memory for the response body, and returns a
- * fully initialized chttpx_response_t structure.
- *
- * @param status HTTP status code (e.g. 200, 400, 404).
- * @param fmt printf-style format string for the JSON body.
- * @param ... Format arguments.
- */
-chttpx_response_t cHTTPX_ResJson(uint16_t status, const char *fmt, ...);
-
-/**
- * Creates an HTTP response with HTML content.
- *
- * This function generates a chttpx_response_t structure with the specified
- * HTTP status code and HTML body. The body is created using a printf-style
- * format string (fmt) and additional arguments. Memory for the body is
- * dynamically allocated and must be freed after sending the response.
- *
- * @param status HTTP status code (e.g., 200, 404, 500).
- * @param fmt Format string containing the HTML content (like printf).
- * @param ... Arguments corresponding to the format string.
- */
-chttpx_response_t cHTTPX_ResHtml(uint16_t status, const char* fmt, ...);
-
-/**
- * Create a binary HTTP response (file, media, etc.).
- *
- * Allocates memory for the response body and returns a fully initialized
- * chttpx_response_t structure.
- *
- * @param status HTTP status code (e.g. 200, 400, 404)
- * @param content_type MIME type of the response (e.g. "image/png")
- * @param body Pointer to the data buffer
- * @param body_size Size of the data buffer in bytes
- * @return Initialized chttpx_response_t
- */
-chttpx_response_t cHTTPX_ResBinary(uint16_t status, const char *content_type, const unsigned char *body, size_t body_size);
-
-/**
- * Create a binary HTTP response from FILE.
- *
- * @param status HTTP status code (e.g. 200, 400, 404)
- * @param content_type MIME type of the response (e.g. "image/png")
- * @param path Path from return file
- * @return Initialized chttpx_response_t
- */
-chttpx_response_t cHTTPX_ResFile(uint16_t status, const char *content_type, const char *path);
+ // RESponse
+ typedef struct
+ {
+ /* Response status code */
+ int status;
+
+ /* Response content type */
+ const char* content_type;
+
+ /* Headers in REQuest */
+ chttpx_header_t headers[MAX_HEADERS];
+ size_t headers_count;
+
+ /* Response body */
+ const unsigned char* body;
+ /* Response body size */
+ size_t body_size;
+
+ /* Times for logging */
+ struct timespec start_ts;
+ struct timespec end_ts;
+ } chttpx_response_t;
+
+ /* handler */
+ typedef void (*chttpx_handler_t)(chttpx_request_t* req, chttpx_response_t* res);
+
+ /**
+ * Handle a single client connection.
+ * @param arg The file descriptor of the accepted client socket.
+ * This function reads the request, parses it, calls the matching route handler,
+ * and sends the response back to the client.
+ */
+ void* chttpx_handle(void* arg);
+
+ /**
+ * Create a JSON HTTP response with formatted content.
+ *
+ * Formats a JSON response body using printf-style arguments,
+ * allocates memory for the response body, and returns a
+ * fully initialized chttpx_response_t structure.
+ *
+ * @param status HTTP status code (e.g. 200, 400, 404).
+ * @param fmt printf-style format string for the JSON body.
+ * @param ... Format arguments.
+ */
+ chttpx_response_t cHTTPX_ResJson(uint16_t status, const char* fmt, ...);
+
+ /**
+ * Creates an HTTP response with HTML content.
+ *
+ * This function generates a chttpx_response_t structure with the specified
+ * HTTP status code and HTML body. The body is created using a printf-style
+ * format string (fmt) and additional arguments. Memory for the body is
+ * dynamically allocated and must be freed after sending the response.
+ *
+ * @param status HTTP status code (e.g., 200, 404, 500).
+ * @param fmt Format string containing the HTML content (like printf).
+ * @param ... Arguments corresponding to the format string.
+ */
+ chttpx_response_t cHTTPX_ResHtml(uint16_t status, const char* fmt, ...);
+
+ /**
+ * Create a binary HTTP response (file, media, etc.).
+ *
+ * Allocates memory for the response body and returns a fully initialized
+ * chttpx_response_t structure.
+ *
+ * @param status HTTP status code (e.g. 200, 400, 404)
+ * @param content_type MIME type of the response (e.g. "image/png")
+ * @param body Pointer to the data buffer
+ * @param body_size Size of the data buffer in bytes
+ * @return Initialized chttpx_response_t
+ */
+ chttpx_response_t cHTTPX_ResBinary(uint16_t status, const char* content_type, const unsigned char* body, size_t body_size);
+
+ /**
+ * Create a binary HTTP response from FILE.
+ *
+ * @param status HTTP status code (e.g. 200, 400, 404)
+ * @param content_type MIME type of the response (e.g. "image/png")
+ * @param path Path from return file
+ * @return Initialized chttpx_response_t
+ */
+ chttpx_response_t cHTTPX_ResFile(uint16_t status, const char* content_type, const char* path);
#ifdef __cplusplus
-extern }
+ extern
+}
#endif
#endif
\ No newline at end of file
diff --git a/include/serv.h b/include/serv.h
index 9c7ca11..c05ad39 100644
--- a/include/serv.h
+++ b/include/serv.h
@@ -9,7 +9,8 @@
#define SERV_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
#include "cors.h"
@@ -22,99 +23,103 @@ extern "C" {
#define MAX_PATH 4096
#define MAX_CLIENTS_DEFAULT 255
-/* Base struct route for library */
-typedef struct {
- const char* method;
- const char* path;
- chttpx_handler_t handler;
-} chttpx_route_t;
-
-typedef struct {
- uint16_t port;
-
- size_t server_fd;
-
- size_t max_clients;
- size_t current_clients;
-
- /* Server timeout params */
- uint16_t read_timeout_sec; // 2b
- uint16_t write_timeout_sec; // 2b
- uint16_t idle_timeout_sec; // 2b
-
- /* Routes params */
- chttpx_route_t* routes;
- size_t routes_count;
- size_t routes_capacity;
-
- /* Middlewares */
- chttpx_middleware_stack_t middleware;
-
- /* Cors */
- chttpx_cors_t cors;
-} chttpx_serv_t;
-
-/* Structure for register routes */
-typedef struct {
- chttpx_serv_t* serv;
- char* prefix;
-} chttpx_router_t;
-
-extern chttpx_serv_t *serv;
-
-/**
- * Initialize the HTTP server.
- * @param serv_p The basic structure for working with a server.
- * @param port The TCP port on which the server will listen (e.g., 80, 8080).
- * This function must be called before registering routes or starting the server.
- */
-int cHTTPX_Init(chttpx_serv_t* serv_p, uint16_t port, void* max_clients);
-
-/**
- * Create a router bound to the server with a fixed path prefix.
- *
- * This function allows grouping routes under a common URL prefix
- * without creating intermediate routers.
- *
- * @param serv Pointer to the initialized HTTP server.
- * @param prefix URL path prefix (e.g. "/api", "/api/v1").
- *
- * @return A router object bound to the server and the given path prefix.
- *
- * @note The returned router owns the prefix string internally.
- * It should be freed with cHTTPX_RouterFree() if necessary.
- */
-chttpx_router_t cHTTPX_RoutePathPrefix(const char* prefix);
-
-/**
- * Register a route handler for a specific HTTP method and path.
- * @param r router struct.
- * @param method HTTP method string, e.g., "GET", "POST".
- * @param path URL path to match, e.g., "/users".
- * @param handler Function pointer to handle the request. The handler should return httpx_response_t.
- * This allows the server to call the appropriate function when a matching request is received.
- */
-void cHTTPX_RegisterRoute(chttpx_router_t* r, const char *method, const char *path, chttpx_handler_t handler);
-
-/**
- * Start the server loop to listen for incoming connections.
- * This function blocks indefinitely, accepting new client connections
- * and dispatching them to cHTTPX_Handle.
- */
-void cHTTPX_Listen();
-
-/**
- * Shutdown the HTTPX server and release all resources.
- *
- * This function gracefully stops the server:
- * - closes listening and client sockets
- * - stops accepting new connections
- * - releases allocated memory and internal structures
- */
-void cHTTPX_Shutdown();
+ /* Base struct route for library */
+ typedef struct
+ {
+ const char* method;
+ const char* path;
+ chttpx_handler_t handler;
+ } chttpx_route_t;
+
+ typedef struct
+ {
+ uint16_t port;
+
+ size_t server_fd;
+
+ size_t max_clients;
+ size_t current_clients;
+
+ /* Server timeout params */
+ uint16_t read_timeout_sec; // 2b
+ uint16_t write_timeout_sec; // 2b
+ uint16_t idle_timeout_sec; // 2b
+
+ /* Routes params */
+ chttpx_route_t* routes;
+ size_t routes_count;
+ size_t routes_capacity;
+
+ /* Middlewares */
+ chttpx_middleware_stack_t middleware;
+
+ /* Cors */
+ chttpx_cors_t cors;
+ } chttpx_serv_t;
+
+ /* Structure for register routes */
+ typedef struct
+ {
+ chttpx_serv_t* serv;
+ char* prefix;
+ } chttpx_router_t;
+
+ extern chttpx_serv_t* serv;
+
+ /**
+ * Initialize the HTTP server.
+ * @param serv_p The basic structure for working with a server.
+ * @param port The TCP port on which the server will listen (e.g., 80, 8080).
+ * This function must be called before registering routes or starting the server.
+ */
+ int cHTTPX_Init(chttpx_serv_t* serv_p, uint16_t port, void* max_clients);
+
+ /**
+ * Create a router bound to the server with a fixed path prefix.
+ *
+ * This function allows grouping routes under a common URL prefix
+ * without creating intermediate routers.
+ *
+ * @param serv Pointer to the initialized HTTP server.
+ * @param prefix URL path prefix (e.g. "/api", "/api/v1").
+ *
+ * @return A router object bound to the server and the given path prefix.
+ *
+ * @note The returned router owns the prefix string internally.
+ * It should be freed with cHTTPX_RouterFree() if necessary.
+ */
+ chttpx_router_t cHTTPX_RoutePathPrefix(const char* prefix);
+
+ /**
+ * Register a route handler for a specific HTTP method and path.
+ * @param r router struct.
+ * @param method HTTP method string, e.g., "GET", "POST".
+ * @param path URL path to match, e.g., "/users".
+ * @param handler Function pointer to handle the request. The handler should return httpx_response_t.
+ * This allows the server to call the appropriate function when a matching request is received.
+ */
+ void cHTTPX_RegisterRoute(chttpx_router_t* r, const char* method, const char* path, chttpx_handler_t handler);
+
+ /**
+ * Start the server loop to listen for incoming connections.
+ * This function blocks indefinitely, accepting new client connections
+ * and dispatching them to cHTTPX_Handle.
+ */
+ void cHTTPX_Listen();
+
+ /**
+ * Shutdown the HTTPX server and release all resources.
+ *
+ * This function gracefully stops the server:
+ * - closes listening and client sockets
+ * - stops accepting new connections
+ * - releases allocated memory and internal structures
+ */
+ void cHTTPX_Shutdown();
#ifdef __cplusplus
-extern }
+ extern
+}
#endif
#endif
\ No newline at end of file
diff --git a/include/utils.h b/include/utils.h
index 970e69a..63a72e0 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -2,36 +2,39 @@
#define UTILS_H
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
/* Threads */
#if defined(_WIN32) || defined(_WIN64)
#include
-typedef HANDLE thread_t;
+ typedef HANDLE thread_t;
-inline int _thread_create(thread_t *thread, void *(*func)(void*), void *arg) {
- *thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, arg, 0, NULL);
- return *thread ? 0 : -1;
-}
+ inline int _thread_create(thread_t* thread, void* (*func)(void*), void* arg)
+ {
+ *thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, arg, 0, NULL);
+ return *thread ? 0 : -1;
+ }
-inline int _thread_join(thread_t thread) {
- WaitForSingleObject(thread, INFINITE);
- CloseHandle(thread);
- return 0;
-}
+ inline int _thread_join(thread_t thread)
+ {
+ WaitForSingleObject(thread, INFINITE);
+ CloseHandle(thread);
+ return 0;
+ }
#else
#include
typedef pthread_t thread_t;
-inline int _thread_create(thread_t *thread, void *(*func)(void*), void *arg)
+inline int _thread_create(thread_t* thread, void* (*func)(void*), void* arg)
{
return pthread_create(thread, NULL, func, arg);
}
-inline int _thread_join(thread_t thread)
+inline int _thread_join(thread_t thread)
{
return pthread_join(thread, NULL);
}
@@ -60,9 +63,7 @@ static inline const char* memmem_case(const void* haystack, size_t haystack_len,
{
size_t j = 0;
- while (j < needle_len &&
- tolower((unsigned char)h[i + j]) ==
- tolower((unsigned char)n[j]))
+ while (j < needle_len && tolower((unsigned char)h[i + j]) == tolower((unsigned char)n[j]))
{
j++;
}
diff --git a/include/websocket.h b/include/websocket.h
index 8b493bb..acecf98 100644
--- a/include/websocket.h
+++ b/include/websocket.h
@@ -16,10 +16,11 @@
#define CHTTPX_WSOCKET_OPCODE_PING 0x9
#define CHTTPX_WSOCKET_OPCODE_PONG 0xA
-typedef struct {
- /* FIN - final fragment
+typedef struct
+{
+ /* FIN - final fragment
* 1 eq. this is the last frame of the message
- * 0 eq. the message is divided into several parts
+ * 0 eq. the message is divided into several parts
*/
int fin;
/* Check define CHTTPX_WSOCKET_OPCODE */
@@ -33,7 +34,8 @@ typedef struct {
unsigned char* payload;
} wsocket_frame_t;
-typedef struct {
+typedef struct
+{
int socket;
int connected;
} chttpx_wsocket_t;
diff --git a/src/request.c b/src/request.c
index 4cd9bc5..74f9109 100644
--- a/src/request.c
+++ b/src/request.c
@@ -96,7 +96,7 @@ int cHTTPX_Parse(chttpx_request_t* req, chttpx_validation_t* fields, size_t fiel
*(char**)f->target = strdup(item->valuestring);
}
break;
-
+
case FIELD_STRING_ARRAY:
if (cJSON_IsArray(item))
{
From 1ea45f5f471ed56c76e785dac3a72127a027134f Mon Sep 17 00:00:00 2001
From: noneandundefined
Date: Fri, 17 Jul 2026 18:52:07 +0500
Subject: [PATCH 6/9] style: apply clang-format to headers and sources
---
.github/workflows/ci.yml | 19 -------------------
1 file changed, 19 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a02846b..7fc3c63 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -50,25 +50,6 @@ jobs:
- name: Build
run: mingw32-make win SHELL=cmd
- format-check:
- name: Format check
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Install clang-format
- run: sudo apt update && sudo apt install -y clang-format
-
- - name: Check formatting
- run: |
- mapfile -t files < <(find . -path './lib/cjson' -prune -o \( -name '*.c' -o -name '*.h' \) -print)
- if [ ${#files[@]} -eq 0 ]; then
- echo "No source files found."
- exit 0
- fi
- clang-format --dry-run --Werror -style=file "${files[@]}"
-
static-analysis:
name: Static analysis (cppcheck)
runs-on: ubuntu-latest
From 10738a919768ab9816e0be1a091d121ad129c3cc Mon Sep 17 00:00:00 2001
From: noneandundefined
Date: Fri, 17 Jul 2026 19:13:33 +0500
Subject: [PATCH 7/9] fix: resolve cpp format: clang-format
---
.github/pull_request_template.md | 21 +++++---
.github/release-drafter.yml | 74 ---------------------------
.github/workflows/auto-release.yml | 40 +++++++++++++++
.github/workflows/pr-title.yml | 31 +++++++++++
.github/workflows/release-drafter.yml | 22 --------
.pre-commit-config.yaml | 22 --------
6 files changed, 84 insertions(+), 126 deletions(-)
delete mode 100644 .github/release-drafter.yml
create mode 100644 .github/workflows/auto-release.yml
create mode 100644 .github/workflows/pr-title.yml
delete mode 100644 .github/workflows/release-drafter.yml
delete mode 100644 .pre-commit-config.yaml
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 5bcb3d8..2825d54 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -2,22 +2,27 @@
-## Type of change
+## PR title (important)
-- [ ] Bug fix
-- [ ] New feature
-- [ ] Breaking change
-- [ ] Documentation update
-- [ ] CI / tooling
+Use a **conventional commit** title — it becomes the release version on merge:
+
+| Title prefix | Release bump | Example |
+|--------------|--------------|---------|
+| `fix:` | patch (1.5.5 → 1.5.6) | `fix: correct Content-Length parsing` |
+| `feat:` | minor (1.5.5 → 1.6.0) | `feat: add rate limiter middleware` |
+| `feat!:` or `BREAKING CHANGE:` in body | major (1.5.5 → 2.0.0) | `feat!: rename cHTTPX_Parse signature` |
+| `chore:`, `ci:`, `docs:` | no release tag | `chore: update workflows` |
+
+> Use **Squash merge** so the PR title becomes the commit on `main`.
## Checklist
+- [ ] PR title follows the table above
- [ ] Code builds on Linux (`make lin` and `make libchttpx.so`)
- [ ] Code builds on Windows (`make win`) if applicable
- [ ] Source is formatted (`make lin-format` or `clang-format`)
-- [ ] `ChangeLog` updated for user-visible changes
- [ ] README updated if public API or usage changed
## Related issues
-
+
diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml
deleted file mode 100644
index 412dbd4..0000000
--- a/.github/release-drafter.yml
+++ /dev/null
@@ -1,74 +0,0 @@
-name-template: 'v$RESOLVED_VERSION'
-tag-template: 'v$RESOLVED_VERSION'
-version-template: '$MAJOR.$MINOR.$PATCH'
-
-categories:
- - title: 'Features'
- labels:
- - feature
- - enhancement
-
- - title: 'Bug Fixes'
- labels:
- - bug
- - fix
-
- - title: 'Security'
- labels:
- - security
-
- - title: 'Documentation'
- labels:
- - documentation
-
- - title: 'Maintenance'
- labels:
- - chore
- - dependencies
- - ci
-
- - title: 'Breaking Changes'
- labels:
- - breaking
-
-change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
-change-title-escapes: '\<*_&'
-
-version-resolver:
- major:
- labels:
- - breaking
- minor:
- labels:
- - feature
- - enhancement
- patch:
- labels:
- - bug
- - fix
- - chore
- - dependencies
- - ci
- - documentation
- - security
-
-template: |
- ## Changes
-
- $CHANGES
-
- ## Install
-
- ### Linux
-
- ```bash
- curl -s https://raw.githubusercontent.com/netcorelink/libchttpx/main/scripts/install.sh | sudo sh
- ```
-
- ### Windows
-
- ```powershell
- iwr https://raw.githubusercontent.com/netcorelink/libchttpx/main/scripts/install.ps1 -UseBasicParsing | iex
- ```
-
- **Full changelog**: https://github.com/netcorelink/libchttpx/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION
diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml
new file mode 100644
index 0000000..2f0281e
--- /dev/null
+++ b/.github/workflows/auto-release.yml
@@ -0,0 +1,40 @@
+name: Auto Release Tag
+
+on:
+ push:
+ branches: [main, master]
+
+permissions:
+ contents: write
+
+concurrency:
+ group: auto-release-${{ github.ref }}
+ cancel-in-progress: false
+
+jobs:
+ tag:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Determine next version
+ uses: paulhatch/semantic-version@v5.4.0
+ id: version
+ with:
+ tag_prefix: v
+ major_pattern: "BREAKING CHANGE|:!"
+ minor_pattern: "^feat(\\(.+\\))?!?:"
+ version_format: "${major}.${minor}.${patch}"
+ bump_each_commit: false
+ search_commit_body: true
+
+ - name: Create and push tag
+ if: steps.version.outputs.changed == 'true'
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+ git tag "${{ steps.version.outputs.version_tag }}"
+ git push origin "${{ steps.version.outputs.version_tag }}"
diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml
new file mode 100644
index 0000000..b4c40d6
--- /dev/null
+++ b/.github/workflows/pr-title.yml
@@ -0,0 +1,31 @@
+name: PR Title
+
+on:
+ pull_request:
+ types: [opened, edited, synchronize, reopened]
+
+permissions:
+ pull-requests: read
+
+jobs:
+ check:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Validate conventional PR title
+ uses: amannn/action-semantic-pull-request@v5
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ types: |
+ feat
+ fix
+ docs
+ style
+ refactor
+ perf
+ test
+ build
+ ci
+ chore
+ revert
+ requireScope: false
diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml
deleted file mode 100644
index e2bea34..0000000
--- a/.github/workflows/release-drafter.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-name: Release Drafter
-
-on:
- push:
- branches: [main, master]
- workflow_dispatch:
-
-permissions:
- contents: write
- pull-requests: read
-
-jobs:
- update-draft:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Update draft release
- uses: release-drafter/release-drafter@v6
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
deleted file mode 100644
index 5e3bd80..0000000
--- a/.pre-commit-config.yaml
+++ /dev/null
@@ -1,22 +0,0 @@
-repos:
- - repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v5.0.0
- hooks:
- - id: trailing-whitespace
- exclude: ^lib/cjson/
- - id: end-of-file-fixer
- exclude: ^lib/cjson/
- - id: check-yaml
- - id: check-added-large-files
- args: [--maxkb=1000]
- - id: check-merge-conflict
-
- - repo: local
- hooks:
- - id: clang-format
- name: clang-format
- entry: clang-format -i
- language: system
- types_or: [c, c++]
- exclude: ^lib/cjson/
- require_serial: true
From 897624f782e2671b6a105182a6b7feafb5c10b8a Mon Sep 17 00:00:00 2001
From: noneandundefined
Date: Fri, 17 Jul 2026 19:15:14 +0500
Subject: [PATCH 8/9] fix: resolve cpp format: clang-format
---
.github/workflows/pr-title.yml | 48 ++++++++++++++++++++++------------
1 file changed, 32 insertions(+), 16 deletions(-)
diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml
index b4c40d6..f79cbaa 100644
--- a/.github/workflows/pr-title.yml
+++ b/.github/workflows/pr-title.yml
@@ -12,20 +12,36 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Validate conventional PR title
- uses: amannn/action-semantic-pull-request@v5
env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- types: |
- feat
- fix
- docs
- style
- refactor
- perf
- test
- build
- ci
- chore
- revert
- requireScope: false
+ TITLE: ${{ github.event.pull_request.title }}
+ run: |
+ # Skip WIP PRs: title starts with [wip]
+ if echo "$TITLE" | grep -qiE '^\[wip\]'; then
+ echo "Skipped: WIP PR"
+ exit 0
+ fi
+
+ # type: description | type(scope): description | type!: breaking change
+ pattern='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([^)]+\))?!?: .+'
+
+ if echo "$TITLE" | grep -qiE "$pattern"; then
+ echo "PR title is valid: $TITLE"
+ exit 0
+ fi
+
+ echo "::error::Invalid PR title: \"$TITLE\""
+ echo ""
+ echo "Use conventional commit format:"
+ echo " type: short description"
+ echo ""
+ echo "Examples:"
+ echo " feat: add auth middleware"
+ echo " fix: correct Content-Length parsing"
+ echo " ci: fix workflows and formatting"
+ echo " chore: update dependabot config"
+ echo ""
+ echo "Breaking change:"
+ echo " feat!: rename cHTTPX_Parse API"
+ echo ""
+ echo "NOT valid: Feat/ci fix (use colon, not slash)"
+ exit 1
From 6f79eb374803174640f9007ab5be8289c9a05caf Mon Sep 17 00:00:00 2001
From: noneandundefined
Date: Fri, 17 Jul 2026 19:30:09 +0500
Subject: [PATCH 9/9] fix: resolve cpp format: clang-format
---
.github/workflows/auto-release.yml | 50 ++++++++++++++++++++++++++++++
.github/workflows/release.yml | 23 +++++++++++---
2 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml
index 2f0281e..380e3a0 100644
--- a/.github/workflows/auto-release.yml
+++ b/.github/workflows/auto-release.yml
@@ -14,6 +14,9 @@ concurrency:
jobs:
tag:
runs-on: ubuntu-latest
+ outputs:
+ changed: ${{ steps.version.outputs.changed }}
+ version_tag: ${{ steps.version.outputs.version_tag }}
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -38,3 +41,50 @@ jobs:
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag "${{ steps.version.outputs.version_tag }}"
git push origin "${{ steps.version.outputs.version_tag }}"
+
+ release:
+ needs: tag
+ if: needs.tag.outputs.changed == 'true'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ needs.tag.outputs.version_tag }}
+
+ - name: Install dependencies
+ run: |
+ sudo apt update
+ sudo apt install -y gcc make libcjson-dev
+
+ - name: Build release archive
+ run: make lin-lib
+
+ - name: Create GitHub Release
+ uses: softprops/action-gh-release@v2
+ with:
+ tag_name: ${{ needs.tag.outputs.version_tag }}
+ name: libchttpx ${{ needs.tag.outputs.version_tag }}
+ files: libchttpx-dev.tar.gz
+ body: |
+
+
+
netcorelink/libchttpx
+ A powerful, cross-platform HTTP server library in C/C++ for building full-featured web servers
+
+
+ ---
+
+ > :warning: **Warning:** Use the `linux environment` for stable library operation.
+
+ ## Linux
+
+ ```bash
+ curl -s https://raw.githubusercontent.com/netcorelink/libchttpx/main/scripts/install.sh | sudo sh
+ ```
+
+ ## Windows
+
+ ```powershell
+ iwr https://raw.githubusercontent.com/netcorelink/libchttpx/main/scripts/install.ps1 -UseBasicParsing | iex
+ ```
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 1255dda..9b0b336 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -1,9 +1,22 @@
+# Runs when a tag is pushed manually (local: git push origin v1.5.6).
+# Tags created by Auto Release Tag do NOT trigger this workflow (GitHub limitation).
+# Use "Run workflow" below to publish an existing tag without re-pushing it.
+
name: Release
on:
push:
tags:
- "v*"
+ workflow_dispatch:
+ inputs:
+ tag:
+ description: "Existing tag to publish (e.g. v1.5.6)"
+ required: true
+ type: string
+
+permissions:
+ contents: write
jobs:
release:
@@ -11,20 +24,22 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.inputs.tag || github.ref }}
- name: Install dependencies
run: |
sudo apt update
- sudo apt install -y gcc make libcjson-dev clang-format
+ sudo apt install -y gcc make libcjson-dev
- name: Build release archive
- run: |
- make lin-lib
+ run: make lin-lib
- name: Create Release
uses: softprops/action-gh-release@v2
with:
- name: libchttpx ${{ github.ref_name }}
+ tag_name: ${{ github.event.inputs.tag || github.ref_name }}
+ name: libchttpx ${{ github.event.inputs.tag || github.ref_name }}
files: libchttpx-dev.tar.gz
body: |