From ec7fd1d728c1a3f789989f70109cdc4d0c229d43 Mon Sep 17 00:00:00 2001 From: Ivan Polyakov Date: Fri, 18 Nov 2022 19:48:31 +0300 Subject: [PATCH 1/6] setting response headers using function instead of struct fields --- c/keyval.c | 1 - c/response.c | 74 ++++++++++++++++++---------------------- cxx/Response.cxx | 8 +++++ examples/c/example.c | 8 ++--- examples/c/minimal.c | 13 ++++--- examples/cxx/example.cxx | 2 +- examples/cxx/minimal.cxx | 3 +- include/Response.hxx | 39 +++------------------ include/keyval.h | 2 +- include/response.h | 4 +-- servers/tcp.c | 1 + 11 files changed, 62 insertions(+), 93 deletions(-) diff --git a/c/keyval.c b/c/keyval.c index 0a17d06..cf8fa9b 100644 --- a/c/keyval.c +++ b/c/keyval.c @@ -3,7 +3,6 @@ #include "keyval.h" #include "utils.h" -#include #include #include diff --git a/c/response.c b/c/response.c index 66c963a..72f31d8 100644 --- a/c/response.c +++ b/c/response.c @@ -6,22 +6,24 @@ #include #include -static size_t calc_res_headers_sz(const rpd_res *res); +static size_t calc_res_status_sz(const rpd_res *res); + +static size_t calc_res_headers_sz(const rpd_keyval *res); void rpd_res_init(rpd_res *dest) { dest->status = rpd_res_st_ok; - dest->location = dest->content_type = NULL; dest->body = NULL; - - rpd_keyval_init(&dest->cookie, 0); + rpd_keyval_init(&dest->headers, 5); } int rpd_res_headers_str(char **dest, const rpd_res *src) { - size_t size = calc_res_headers_sz(src); + size_t size, i = 0; char *ptr; + size = calc_res_headers_sz(&src->headers); + *dest = (char *) malloc(sizeof(char) * size); if (!*dest) { perror("malloc"); @@ -29,12 +31,13 @@ int rpd_res_headers_str(char **dest, const rpd_res *src) } ptr = *dest; - if (src->content_type) { - ptr += sprintf(ptr, "Content-Type: %s\r\n", src->content_type); - } - - if (src->location) { - ptr += sprintf(ptr, "Location: %s\r\n", src->location); + while (i < src->headers.size) { + ptr += sprintf( + ptr, + "%s: %s\r\n", + src->headers.items[i].key, + src->headers.items[i].val); + i++; } return 0; @@ -44,7 +47,9 @@ int rpd_res_str(char **dest, const rpd_res *res) { size_t headers_size, size; char *ptr, *headers; - size = headers_size = calc_res_headers_sz(res); + size = headers_size = calc_res_headers_sz(&res->headers); + size += calc_res_status_sz(res); + if (res->body) size += 2 + strlen(res->body); @@ -78,25 +83,24 @@ int rpd_res_str(char **dest, const rpd_res *res) return 0; } -static size_t calc_res_headers_sz(const rpd_res *res) +static size_t calc_res_status_sz(const rpd_res *res) { size_t size = 0; + size += strlen("Status: \r\n"); + size += 3; /* plus status code */ + return size; +} - size += strlen("Status: \r\n") + 3; - if (res->location) { - size += strlen("Location: \r\n") + strlen(res->location); - } - - if (res->content_type) { - size += strlen("Content-Type: \r\n") + strlen(res->content_type); - } - - if (res->cookie.size) { - size += strlen("Set-Cookie: \r\n") * res->cookie.size; - for (int i = 0; i < res->cookie.size; i++) { - rpd_keyval_item *item = res->cookie.items + i; - size += strlen(item->key) + strlen(item->val); - } +static size_t calc_res_headers_sz(const rpd_keyval *headers) +{ + size_t size = 0, i = 0; + + while (i < headers->size) { + size += strlen(headers->items[i].key); + size++; /* plus space */ + size += strlen(headers->items[i].val); + size += 2; /* plus CRLF */ + i++; } return size; @@ -106,22 +110,12 @@ void rpd_res_cleanup(rpd_res *res) { res->status = rpd_res_st_ok; - if (res->location) { - free(res->location); - res->location = NULL; - } - - if (res->content_type) { - free(res->content_type); - res->content_type = NULL; - } - if (res->body) { free(res->body); res->body = NULL; } - if (res->cookie.capacity) { - rpd_keyval_cleanup(&res->cookie); + if (res->headers.capacity) { + rpd_keyval_cleanup(&res->headers); } } diff --git a/cxx/Response.cxx b/cxx/Response.cxx index 0917f18..b9f95fa 100644 --- a/cxx/Response.cxx +++ b/cxx/Response.cxx @@ -9,6 +9,14 @@ using namespace rpd; +int Response::header(const char *key, const char *value) +{ + return rpd_keyval_insert( + &this->res->headers, + key, + value); +} + #ifdef EXTENSIONS_INJA void Response::render(const char *path, nlohmann::json data) { diff --git a/examples/c/example.c b/examples/c/example.c index b3a2089..4770985 100644 --- a/examples/c/example.c +++ b/examples/c/example.c @@ -28,6 +28,7 @@ static void products_handler(rpd_req *req, rpd_res *res, void *userdata) int bufflen = strlen(body) + strlen(cat->val) + strlen(id->val); res->body = (char *) malloc(sizeof(char) * (bufflen + 1)); if (!res->body) { + perror("malloc"); res->status = rpd_res_st_internal_server_error; return; } @@ -37,12 +38,7 @@ static void products_handler(rpd_req *req, rpd_res *res, void *userdata) res->status = rpd_res_st_ok; - /* - * place all values in heap, please, - * because after call handler - * `req` and `res` will be freed - */ - res->content_type = strdup("text/html"); + rpd_keyval_insert(&res->headers, "Content-Type", "text/html"); } int main() diff --git a/examples/c/minimal.c b/examples/c/minimal.c index ec4583a..6c58087 100644 --- a/examples/c/minimal.c +++ b/examples/c/minimal.c @@ -15,15 +15,18 @@ static void home_page_handler(rpd_req *req, rpd_res *res, void *userdata) /* Check request method */ switch (req->method) { case HEAD: - /* Process GET request */ res->status = rpd_res_st_ok; + rpd_keyval_insert(&res->headers, "Content-Type", "text/plain"); + break; + case GET: + res->status = rpd_res_st_ok; + rpd_keyval_insert(&res->headers, "Content-Type", "text/plain"); + rpd_keyval_insert(&res->headers, "JavaScript", "Sucks"); - /* Please allocate data on the heap, + /* Please allocate body on the heap, * because after calling this handler - * Rapida will free it all. + * Rapida will free it. */ - res->content_type = strdup("text/plain"); - case GET: res->body = strdup("Hello World!"); break; default: diff --git a/examples/cxx/example.cxx b/examples/cxx/example.cxx index 85480b3..6cc303e 100644 --- a/examples/cxx/example.cxx +++ b/examples/cxx/example.cxx @@ -35,7 +35,7 @@ protected: virtual void handle_head(const rpd::Request &req, rpd::Response &res) override { res.status(rpd_res_st_ok); - res.content_type("text/html"); + res.header("Content-Type", "text/html"); } }; diff --git a/examples/cxx/minimal.cxx b/examples/cxx/minimal.cxx index d8febda..3bb0fa1 100644 --- a/examples/cxx/minimal.cxx +++ b/examples/cxx/minimal.cxx @@ -1,7 +1,6 @@ #include "../../include/rapida.hxx" #include "../../include/servers/tcp.h" - /* * \brief Home page route handler. */ @@ -29,7 +28,7 @@ protected: virtual void handle_head(const rpd::Request &req, rpd::Response &res) override { res.status(rpd_res_st_ok); - res.content_type("text/plain"); + res.header("Content-Type", "text/plain"); } }; diff --git a/include/Response.hxx b/include/Response.hxx index 75db59a..9d7fee1 100644 --- a/include/Response.hxx +++ b/include/Response.hxx @@ -59,43 +59,14 @@ public: } /*! - * \brief Sets _location_ response field. + * \brief Sets response header. * - * \param location Location URL. - */ - void location(const char *location) - { - if (res->location) - free(res->location); - res->location = strdup(location); - } - - /*! - * \brief Sets _Content-Type_ response field. - * - * \param content_type Response content type. - */ - void content_type(const char *content_type) - { - if (res->content_type) - free(res->content_type); - res->content_type = strdup(content_type); - } - - /*! - * \brief Sets cookie field. + * \param key Header key. + * \param value Header value * - * Adds new cookie field to key-value storage. - * If you need to set cookie parameters such as lifetime, - * place it to val. - * - * \param key Cookie field key. - * \param val Cookie field value. + * \return Status code. 0 is success. */ - void cookie(const char *key, const char *val) - { - rpd_keyval_insert(&res->cookie, key, val); - } + int header(const char *key, const char *value); /*! * \brief Sets response body. diff --git a/include/keyval.h b/include/keyval.h index 60c270b..4c91307 100644 --- a/include/keyval.h +++ b/include/keyval.h @@ -9,7 +9,7 @@ #ifndef RAPIDA_KEYVAL_H_ENTRY #define RAPIDA_KEYVAL_H_ENTRY -#include "unistd.h" +#include #ifdef __cplusplus extern "C" { diff --git a/include/response.h b/include/response.h index 6e6d64e..3cd949a 100644 --- a/include/response.h +++ b/include/response.h @@ -86,10 +86,8 @@ enum rpd_res_statuses { */ typedef struct { enum rpd_res_statuses status; /**< Response status code. */ - char *location; /**< Location field. */ - char *content_type; /**< Content type. */ char *body; /**< Response body. */ - rpd_keyval cookie; /**< Set-Cookie fields. */ + rpd_keyval headers; /**< Response headers. */ } rpd_res; /*! diff --git a/servers/tcp.c b/servers/tcp.c index 89e4df6..3b993fb 100644 --- a/servers/tcp.c +++ b/servers/tcp.c @@ -64,6 +64,7 @@ static void handle_request(struct mg_connection *conn, int ev, void *ev_data, vo rpd_app_handle_request((rpd_app *) app, req, res); rpd_res_headers_str(&headers_buff, res); + puts(headers_buff); mg_http_reply(conn, res->status, headers_buff, res->body ? res->body : ""); free(headers_buff); -- 2.36.1 From 56ca12fb63497e8f42743faf1da300c8bb3e0fae Mon Sep 17 00:00:00 2001 From: Ivan Polyakov Date: Fri, 18 Nov 2022 20:54:09 +0300 Subject: [PATCH 2/6] fix headers size calculation --- c/response.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/response.c b/c/response.c index 72f31d8..b040dfb 100644 --- a/c/response.c +++ b/c/response.c @@ -97,7 +97,7 @@ static size_t calc_res_headers_sz(const rpd_keyval *headers) while (i < headers->size) { size += strlen(headers->items[i].key); - size++; /* plus space */ + size += 2; /* plus ": " */ size += strlen(headers->items[i].val); size += 2; /* plus CRLF */ i++; -- 2.36.1 From 50df05b1b00a1aa6ba7339104c2167f4eb1bb91c Mon Sep 17 00:00:00 2001 From: Ivan Polyakov Date: Sun, 20 Nov 2022 17:22:39 +0300 Subject: [PATCH 3/6] getting all request headers --- c/utils.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ c/utils.h | 17 ++++++++++++ cxx/Request.cxx | 12 +++++++++ examples/c/minimal.c | 1 - include/Request.hxx | 21 ++++++++------- include/request.h | 3 +-- servers/fcgi.c | 56 ++++++++++++++++++++++++++++++++++++++-- servers/tcp.c | 17 +++++++++++- 8 files changed, 171 insertions(+), 17 deletions(-) create mode 100644 cxx/Request.cxx diff --git a/c/utils.c b/c/utils.c index 174ed2a..0df63b3 100644 --- a/c/utils.c +++ b/c/utils.c @@ -2,6 +2,7 @@ /* Copyright 2022 Ivan Polyakov */ #include "utils.h" +#include #include #include @@ -43,3 +44,63 @@ char *rpd_strsep(char **str, const char *sep) *str = end; return s; } + +const char *rpd_splitbyc(char **dest1, char **dest2, const char *src, const char sep) +{ + const char *start = src, *end = src; + + if (!src) + return 0; + + while (*end) { + if (*end == sep) { + size_t len = end - start; + *dest1 = malloc(sizeof(char) * (len + 1)); + if (!*dest1) { + perror("malloc"); + return NULL; + } + memcpy(*dest1, start, len); + (*dest1)[len] = '\0'; + + end++; + len = strlen(start) - (end - start); + if (!len) { + *dest2 = NULL; + return 0; + } + + *dest2 = malloc(sizeof(char) * (len + 1)); + if ((!*dest2)) { + perror("malloc"); + return NULL; + } + memcpy(*dest2, end, len); + (*dest2)[len + 1] = '\0'; + return 0; + } + end++; + } + + return 0; +} + +void rpd_strerase(char *src, int nchars) +{ + char *ptr = NULL; + size_t len = strlen(src); + if (!src) + return; + + ptr = src + nchars; + while (*ptr != '\0') { + *(ptr - nchars) = *ptr; + ptr++; + } + + ptr = src + len; + while (ptr >= (src + len) - nchars) { + *ptr = '\0'; + ptr--; + } +} diff --git a/c/utils.h b/c/utils.h index 53c6430..a2e3008 100644 --- a/c/utils.h +++ b/c/utils.h @@ -10,4 +10,21 @@ char *rpd_strdup(const char *src); char *rpd_strsep(char **str, const char *sep); +const char *rpd_splitbyc(char **dest1, char **dest2, const char *src, const char sep); + +/*! + * \brief Erases part of the string. + * + * This function moves characters to the beginning of the string + * and inserts '\0' at the original position without reallocation. + * + * To erase characters not from beginning of the string, + * you can pass a pointer to the beginning of the desired + * part of the string. + * + * \param src String to erase. + * \param nchars Number of charecters to erase. + */ +void rpd_strerase(char *src, int nchars); + #endif /* RAPIDA_UTILS_H_ENTRY */ diff --git a/cxx/Request.cxx b/cxx/Request.cxx new file mode 100644 index 0000000..b8ff622 --- /dev/null +++ b/cxx/Request.cxx @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* Copyright 2022 Ivan Polyakov */ + +#include "Request.hxx" + +using namespace rpd; + +const char *Request::header(const char *key) const +{ + rpd_keyval_item *hi = rpd_keyval_find(&req->headers, key); + return hi ? hi->val : NULL; +} diff --git a/examples/c/minimal.c b/examples/c/minimal.c index 6c58087..67cbfc8 100644 --- a/examples/c/minimal.c +++ b/examples/c/minimal.c @@ -21,7 +21,6 @@ static void home_page_handler(rpd_req *req, rpd_res *res, void *userdata) case GET: res->status = rpd_res_st_ok; rpd_keyval_insert(&res->headers, "Content-Type", "text/plain"); - rpd_keyval_insert(&res->headers, "JavaScript", "Sucks"); /* Please allocate body on the heap, * because after calling this handler diff --git a/include/Request.hxx b/include/Request.hxx index dfa6d94..2a5e89e 100644 --- a/include/Request.hxx +++ b/include/Request.hxx @@ -69,24 +69,23 @@ public: } /*! - * \brief Gets authorization string. + * \brief Gets the request header. * - * \return Authorization string. + * \params key Header key. + * + * \return Found header or NULL. */ - const char *authorization() const - { - return req->auth; - } + const char *header(const char *key) const; /*! - * \brief Gets cookie string. + * \brief Gets all request headers. * - * \return Cookie string. + * \return Key-value pairs. */ - const char *cookie() const + KeyVal headers() const { - return req->cookie; - }; + return &req->headers; + } /*! * \brief Gets request body content. diff --git a/include/request.h b/include/request.h index af3eca3..5e1cb14 100644 --- a/include/request.h +++ b/include/request.h @@ -36,10 +36,9 @@ enum rpd_req_methods { */ typedef struct { enum rpd_req_methods method; /**< Request method. */ - char *auth; /**< Authorization field. */ - char *cookie; /**< Cookie field. */ char *body; /**< Body field. */ rpd_url path; /**< Requested URL. */ + rpd_keyval headers; /**< Request headers. */ rpd_keyval query; /**< Query. */ rpd_keyval params; /**< Dynamic parameters. */ } rpd_req; diff --git a/servers/fcgi.c b/servers/fcgi.c index 1d3d335..f4670a5 100644 --- a/servers/fcgi.c +++ b/servers/fcgi.c @@ -2,7 +2,11 @@ /* Copyright 2022 Ivan Polyakov */ #include "../include/servers/fcgi.h" +#include "../c/utils.h" +#include +#include #include +#include #ifdef MT_ENABLED #include @@ -56,6 +60,8 @@ static int read_fcgx_req_body(char **dest, FCGX_Request *req); */ static void send_response(rpd_res *res, FCGX_Stream *out); +static int env_to_req_header(char **key, char **val, const char *envp); + int rpd_fcgi_server_start(rpd_app *app, const char *sock_path) { FCGX_Init(); @@ -155,9 +161,39 @@ static int fcgx_to_rpd_req(rpd_req *dest, FCGX_Request *req) dest->method = rpd_req_smethod(FCGX_GetParam("REQUEST_METHOD", req->envp)); rpd_url_parse(&dest->path, FCGX_GetParam("DOCUMENT_URI", req->envp)); - dest->auth = FCGX_GetParam("HTTP_AUTHORIZATION", req->envp); - dest->cookie = FCGX_GetParam("HTTP_COOKIE", req->envp); + // dest->auth = FCGX_GetParam("HTTP_AUTHORIZATION", req->envp); + // dest->cookie = FCGX_GetParam("HTTP_COOKIE", req->envp); rpd_keyval_init(&dest->params, 0); + rpd_keyval_init(&dest->headers, 0); + + char **env = req->envp; + char *key = NULL, *val = NULL; + while (*(++env)) { + char *ptr = NULL; + + /* keep only http request fields */ + ptr = strstr(*env, "HTTP"); + if (ptr == NULL || ptr - *env != 0) + continue; + + env_to_req_header(&key, &val, *env); + if (!val || !key) + continue; + rpd_strerase(key, 5); + ptr = key; + while (*ptr) { + *ptr = tolower(*ptr); + if (ptr == key || *(ptr - 1) == '-') + *ptr = toupper(*ptr); + if (*ptr == '_') + *ptr = '-'; + ptr++; + } + + rpd_keyval_insert(&dest->headers, key, val); + free(key); + free(val); + } if (dest->method != GET) { if (read_fcgx_req_body(&dest->body, req)) { @@ -186,3 +222,19 @@ static int read_fcgx_req_body(char **dest, FCGX_Request *req) return 0; } + +static int env_to_req_header(char **key, char **val, const char *env) +{ + const char *ptr = NULL; + + rpd_splitbyc(key, val, env, '='); + if (!*key || !*val) { + if (*key) + free(*key); + if (*val) + free(*val); + return 1; + } + + return 0; +} diff --git a/servers/tcp.c b/servers/tcp.c index 3b993fb..392ea12 100644 --- a/servers/tcp.c +++ b/servers/tcp.c @@ -45,6 +45,22 @@ static int mg_to_rpd_req(rpd_req *req, struct mg_http_message *msg) rpd_query_parse(&req->query, tmp); } + size_t i, max = sizeof(msg->headers) / sizeof(msg->headers[0]); + rpd_keyval_init(&req->headers, max); + + // Iterate over request headers + char *key = NULL, *val = NULL; + for (i = 0; i < max && msg->headers[i].name.len > 0; i++) { + struct mg_str *k = &msg->headers[i].name, *v = &msg->headers[i].value; + + mg_str_alloc(&key, *k); + mg_str_alloc(&val, *v); + + rpd_keyval_insert(&req->headers, key, val); + } + free(key); + free(val); + free(tmp); return 0; } @@ -64,7 +80,6 @@ static void handle_request(struct mg_connection *conn, int ev, void *ev_data, vo rpd_app_handle_request((rpd_app *) app, req, res); rpd_res_headers_str(&headers_buff, res); - puts(headers_buff); mg_http_reply(conn, res->status, headers_buff, res->body ? res->body : ""); free(headers_buff); -- 2.36.1 From bebbca1f92fb954e0a6da45f485ecc20d9baddbe Mon Sep 17 00:00:00 2001 From: Ivan Polyakov Date: Mon, 21 Nov 2022 22:32:28 +0300 Subject: [PATCH 4/6] non-unique keyval storage --- c/keyval.c | 33 ++++++++++++++++++++++++++++++++- c/response.c | 1 + include/KeyVal.hxx | 18 ++++++++++++++++++ include/keyval.h | 16 ++++++++++++++++ servers/fcgi.c | 1 + servers/tcp.c | 1 + tests/app.cxx | 2 +- tests/keyval.cxx | 18 ++++++++++++++++++ 8 files changed, 88 insertions(+), 2 deletions(-) diff --git a/c/keyval.c b/c/keyval.c index cf8fa9b..41ae2f8 100644 --- a/c/keyval.c +++ b/c/keyval.c @@ -19,6 +19,7 @@ static int rpd_keyval_realloc(rpd_keyval *keyval, int capacity); int rpd_keyval_init(rpd_keyval *keyval, int capacity) { keyval->size = keyval->capacity = 0; + keyval->unique = 1; if (capacity == 0) { keyval->items = NULL; @@ -45,7 +46,7 @@ int rpd_keyval_insert(rpd_keyval *keyval, const char *key, const char *value) } rpd_keyval_item *item = rpd_keyval_find(keyval, key); - if (item) { + if (item && keyval->unique) { free(item->key); item->key = NULL; if (item->val) { @@ -75,6 +76,36 @@ rpd_keyval_item *rpd_keyval_find(const rpd_keyval *keyval, const char *key) return NULL; } +rpd_keyval_item **rpd_keyval_findall(const rpd_keyval *keyval, const char *key) +{ + int i = 0, n = 0; + rpd_keyval_item **items = NULL; + while (i < keyval->size) { + if (!strcmp(keyval->items[i].key, key)) { + n++; + } + i++; + } + if (!n) + return NULL; + + items = malloc(sizeof(rpd_keyval_item *) * (n + 1)); + if (!items) + return NULL; + + items[n] = NULL; + i = 0, n = 0; + while (i < keyval->size) { + if (!strcmp(keyval->items[i].key, key)) { + items[n] = keyval->items + i; + n++; + } + i++; + } + + return items; +} + void rpd_keyval_cleanup(rpd_keyval *keyval) { if (keyval->items) { diff --git a/c/response.c b/c/response.c index b040dfb..4125582 100644 --- a/c/response.c +++ b/c/response.c @@ -15,6 +15,7 @@ void rpd_res_init(rpd_res *dest) dest->status = rpd_res_st_ok; dest->body = NULL; rpd_keyval_init(&dest->headers, 5); + dest->headers.unique = 0; } int rpd_res_headers_str(char **dest, const rpd_res *src) diff --git a/include/KeyVal.hxx b/include/KeyVal.hxx index ace50e2..3adfdde 100644 --- a/include/KeyVal.hxx +++ b/include/KeyVal.hxx @@ -36,6 +36,24 @@ public: _keyval = keyval; } + /*! + * \brief Is the storage unique? + */ + bool unique() const + { + return _keyval->unique; + } + + /*! + * \brief Sets the uniqueness flag. + * + * \param is_unique Uniqueness flag. + */ + void unique(bool is_unique) + { + _keyval->unique = is_unique; + } + /*! * \brief Returns real key-value storage. * diff --git a/include/keyval.h b/include/keyval.h index 4c91307..a532019 100644 --- a/include/keyval.h +++ b/include/keyval.h @@ -30,6 +30,7 @@ typedef struct { rpd_keyval_item *items; /**< Key-value pairs array. */ int size; /**< Number of elements in rpd_keyval::items. */ int capacity; /**< Current capacity (allocated memory). */ + int unique; /**< Unique flag */ } rpd_keyval; /*! @@ -70,6 +71,21 @@ int rpd_keyval_insert(rpd_keyval *keyval, const char *key, const char *value); */ rpd_keyval_item *rpd_keyval_find(const rpd_keyval *keyval, const char *key); +/*! + * \brief Finds all key-value pair by key. + * + * Useful when storage is not unique. + * In request header fields, for example. + * + * Last item will be NULL. + * + * \param keyval Key-value storage instance. + * \param key Key to search. + * + * \return Found items or NULL. + */ +rpd_keyval_item **rpd_keyval_findall(const rpd_keyval *keyval, const char *key); + /*! * \brief Free key-val pairs and reset. * diff --git a/servers/fcgi.c b/servers/fcgi.c index f4670a5..e8dec1b 100644 --- a/servers/fcgi.c +++ b/servers/fcgi.c @@ -165,6 +165,7 @@ static int fcgx_to_rpd_req(rpd_req *dest, FCGX_Request *req) // dest->cookie = FCGX_GetParam("HTTP_COOKIE", req->envp); rpd_keyval_init(&dest->params, 0); rpd_keyval_init(&dest->headers, 0); + dest->headers.unique = 0; char **env = req->envp; char *key = NULL, *val = NULL; diff --git a/servers/tcp.c b/servers/tcp.c index 392ea12..1093e9f 100644 --- a/servers/tcp.c +++ b/servers/tcp.c @@ -47,6 +47,7 @@ static int mg_to_rpd_req(rpd_req *req, struct mg_http_message *msg) size_t i, max = sizeof(msg->headers) / sizeof(msg->headers[0]); rpd_keyval_init(&req->headers, max); + req->headers.unique = 0; // Iterate over request headers char *key = NULL, *val = NULL; diff --git a/tests/app.cxx b/tests/app.cxx index e49e2b5..7c4cd7f 100644 --- a/tests/app.cxx +++ b/tests/app.cxx @@ -9,7 +9,7 @@ using namespace rpd; TEST_CASE("Application") { rpd_app app; - int res = rpd_app_create(&app, "/tmp/rapida.test.socket"); + int res = rpd_app_create(&app); SECTION("App creation") { diff --git a/tests/keyval.cxx b/tests/keyval.cxx index a217efe..3fa95df 100644 --- a/tests/keyval.cxx +++ b/tests/keyval.cxx @@ -36,6 +36,24 @@ TEST_CASE("Key-value storage") REQUIRE(std::string(item->val) == "val"); } + SECTION("Passing duplicates to non-unique storage and finding them") + { + int sz = keyval.size; + keyval.unique = 0; + + rpd_keyval_insert(&keyval, "Set-Cookie", "param=val"); + rpd_keyval_insert(&keyval, "Set-Cookie", "param1=val1"); + REQUIRE(keyval.size == sz + 2); + + rpd_keyval_item **cookies = rpd_keyval_findall(&keyval, "Set-Cookie"); + REQUIRE(cookies != NULL); + REQUIRE(std::string(cookies[0]->key) == "Set-Cookie"); + REQUIRE(std::string(cookies[0]->val) == "param=val"); + REQUIRE(std::string(cookies[1]->key) == "Set-Cookie"); + REQUIRE(std::string(cookies[1]->val) == "param1=val1"); + REQUIRE(cookies[2] == NULL); + } + SECTION("Cleanup") { rpd_keyval_cleanup(&keyval); -- 2.36.1 From e0211053c67431fec1880c60b0bb5455ad72685b Mon Sep 17 00:00:00 2001 From: Ivan Polyakov Date: Tue, 22 Nov 2022 21:41:04 +0300 Subject: [PATCH 5/6] inja removed --- README.md | 5 ----- config.mk | 10 ---------- cxx/Response.cxx | 30 ------------------------------ include/Response.hxx | 13 ------------- 4 files changed, 58 deletions(-) diff --git a/README.md b/README.md index 9844b1d..313ba82 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,6 @@ make install clean ``` Run `make help` to see targets, flags and arguments. -Extensions ----------- -* [inja](https://github.com/pantor/inja) (template rendering, - requires [nlohmann/json](https://github.com/nlohmann/json)) - Examples -------- See [examples](examples). diff --git a/config.mk b/config.mk index 422e1f4..bf7638f 100644 --- a/config.mk +++ b/config.mk @@ -31,16 +31,6 @@ ifeq ($(FCGI_SERVER), 1) LDFLAGS += -lfcgi endif -#flag Enable inja extension -EXTENSIONS_INJA ?= 0 -#arg Dist path. Needed only if inja is enabled. -DIST_PATH = /var/www/html -ifneq ($(EXTENSIONS_INJA), 0) - CXXFLAGS+=-DEXTENSIONS_INJA -DDIST_PATH=\"$(DIST_PATH)\" - CXXSTD=-std=c++17 -endif - - #flag Multithread support MT_ENABLED ?= 0 #arg Number of threads. 8 by default. diff --git a/cxx/Response.cxx b/cxx/Response.cxx index b9f95fa..784cbcc 100644 --- a/cxx/Response.cxx +++ b/cxx/Response.cxx @@ -3,10 +3,6 @@ #include "Response.hxx" -#ifdef EXTENSIONS_INJA -#include -#endif - using namespace rpd; int Response::header(const char *key, const char *value) @@ -16,29 +12,3 @@ int Response::header(const char *key, const char *value) key, value); } - -#ifdef EXTENSIONS_INJA -void Response::render(const char *path, nlohmann::json data) -{ - inja::Environment env; - inja::Template tpl; - - try { - std::string tplpath = DIST_PATH; - tplpath += path; - tpl = env.parse_template(tplpath); - } catch (inja::FileError &e) { - std::cerr << e.what() << std::endl; - return; - } - - try { - std::string result = env.render(tpl, data); - body(result.c_str()); - } catch (inja::RenderError &e) { - std::cerr << e.what() << std::endl; - status(rpd_res_st_internal_server_error); - return; - } -} -#endif diff --git a/include/Response.hxx b/include/Response.hxx index 9d7fee1..2ef0c7a 100644 --- a/include/Response.hxx +++ b/include/Response.hxx @@ -8,10 +8,6 @@ #include #include -#ifdef EXTENSIONS_INJA -#include -#endif - namespace rpd { /*! * \brief C++ response wrapper. @@ -80,15 +76,6 @@ public: res->body = strdup(body); } -#ifdef EXTENSIONS_INJA - /*! - * \brief Render data to HTML template. - * \param path Path to HTML template relative to dist location. - * \param data Template data to interpolate. - */ - void render(const char *path, nlohmann::json data); -#endif - /*! * \brief Destructor. */ -- 2.36.1 From 1be159e9f6f2fe3e138050e1c02749c1e5ef3ac5 Mon Sep 17 00:00:00 2001 From: Ivan Polyakov Date: Tue, 22 Nov 2022 21:42:01 +0300 Subject: [PATCH 6/6] ver upd --- config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.mk b/config.mk index bf7638f..1ea7d81 100644 --- a/config.mk +++ b/config.mk @@ -1,4 +1,4 @@ -VERSION=0.3.1 +VERSION=0.4 #arg Installation prefix PREFIX=/usr/local -- 2.36.1