From 50df05b1b00a1aa6ba7339104c2167f4eb1bb91c Mon Sep 17 00:00:00 2001 From: Ivan Polyakov Date: Sun, 20 Nov 2022 17:22:39 +0300 Subject: [PATCH] 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);