Browse Source

non-unique keyval storage

pull/2/head
Ivan Polyakov 2 years ago
parent
commit
bebbca1f92
  1. 33
      c/keyval.c
  2. 1
      c/response.c
  3. 18
      include/KeyVal.hxx
  4. 16
      include/keyval.h
  5. 1
      servers/fcgi.c
  6. 1
      servers/tcp.c
  7. 2
      tests/app.cxx
  8. 18
      tests/keyval.cxx

33
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) int rpd_keyval_init(rpd_keyval *keyval, int capacity)
{ {
keyval->size = keyval->capacity = 0; keyval->size = keyval->capacity = 0;
keyval->unique = 1;
if (capacity == 0) { if (capacity == 0) {
keyval->items = NULL; 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); rpd_keyval_item *item = rpd_keyval_find(keyval, key);
if (item) { if (item && keyval->unique) {
free(item->key); free(item->key);
item->key = NULL; item->key = NULL;
if (item->val) { if (item->val) {
@ -75,6 +76,36 @@ rpd_keyval_item *rpd_keyval_find(const rpd_keyval *keyval, const char *key)
return NULL; 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) void rpd_keyval_cleanup(rpd_keyval *keyval)
{ {
if (keyval->items) { if (keyval->items) {

1
c/response.c

@ -15,6 +15,7 @@ void rpd_res_init(rpd_res *dest)
dest->status = rpd_res_st_ok; dest->status = rpd_res_st_ok;
dest->body = NULL; dest->body = NULL;
rpd_keyval_init(&dest->headers, 5); rpd_keyval_init(&dest->headers, 5);
dest->headers.unique = 0;
} }
int rpd_res_headers_str(char **dest, const rpd_res *src) int rpd_res_headers_str(char **dest, const rpd_res *src)

18
include/KeyVal.hxx

@ -36,6 +36,24 @@ public:
_keyval = keyval; _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. * \brief Returns real key-value storage.
* *

16
include/keyval.h

@ -30,6 +30,7 @@ typedef struct {
rpd_keyval_item *items; /**< Key-value pairs array. */ rpd_keyval_item *items; /**< Key-value pairs array. */
int size; /**< Number of elements in rpd_keyval::items. */ int size; /**< Number of elements in rpd_keyval::items. */
int capacity; /**< Current capacity (allocated memory). */ int capacity; /**< Current capacity (allocated memory). */
int unique; /**< Unique flag */
} rpd_keyval; } 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); 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. * \brief Free key-val pairs and reset.
* *

1
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); // dest->cookie = FCGX_GetParam("HTTP_COOKIE", req->envp);
rpd_keyval_init(&dest->params, 0); rpd_keyval_init(&dest->params, 0);
rpd_keyval_init(&dest->headers, 0); rpd_keyval_init(&dest->headers, 0);
dest->headers.unique = 0;
char **env = req->envp; char **env = req->envp;
char *key = NULL, *val = NULL; char *key = NULL, *val = NULL;

1
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]); size_t i, max = sizeof(msg->headers) / sizeof(msg->headers[0]);
rpd_keyval_init(&req->headers, max); rpd_keyval_init(&req->headers, max);
req->headers.unique = 0;
// Iterate over request headers // Iterate over request headers
char *key = NULL, *val = NULL; char *key = NULL, *val = NULL;

2
tests/app.cxx

@ -9,7 +9,7 @@ using namespace rpd;
TEST_CASE("Application") TEST_CASE("Application")
{ {
rpd_app app; rpd_app app;
int res = rpd_app_create(&app, "/tmp/rapida.test.socket"); int res = rpd_app_create(&app);
SECTION("App creation") SECTION("App creation")
{ {

18
tests/keyval.cxx

@ -36,6 +36,24 @@ TEST_CASE("Key-value storage")
REQUIRE(std::string(item->val) == "val"); 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") SECTION("Cleanup")
{ {
rpd_keyval_cleanup(&keyval); rpd_keyval_cleanup(&keyval);

Loading…
Cancel
Save