From 556f1d5e99e409df0530efe1cbd1d474c46b5ebe Mon Sep 17 00:00:00 2001 From: noneandundefined Date: Fri, 17 Jul 2026 17:35:39 +0500 Subject: [PATCH 1/8] 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/8] 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/8] 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/8] 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/8] 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/8] 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/8] 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/8] 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