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); @@ -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) @@ -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) @@ -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) {

1
c/response.c

@ -15,6 +15,7 @@ void rpd_res_init(rpd_res *dest) @@ -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)

18
include/KeyVal.hxx

@ -36,6 +36,24 @@ public: @@ -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.
*

16
include/keyval.h

@ -30,6 +30,7 @@ typedef struct { @@ -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); @@ -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.
*

1
servers/fcgi.c

@ -165,6 +165,7 @@ static int fcgx_to_rpd_req(rpd_req *dest, FCGX_Request *req) @@ -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;

1
servers/tcp.c

@ -47,6 +47,7 @@ static int mg_to_rpd_req(rpd_req *req, struct mg_http_message *msg) @@ -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;

2
tests/app.cxx

@ -9,7 +9,7 @@ using namespace rpd; @@ -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")
{

18
tests/keyval.cxx

@ -36,6 +36,24 @@ TEST_CASE("Key-value storage") @@ -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);

Loading…
Cancel
Save