Skip to content

Commit

Permalink
api: move query functions to oc_query.c
Browse files Browse the repository at this point in the history
  • Loading branch information
Danielius1922 authored and Daniel Adam committed Aug 1, 2023
1 parent 2cc9224 commit 2a1116c
Show file tree
Hide file tree
Showing 13 changed files with 567 additions and 339 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ jobs:
- name: Build with clang and analyze with clang-tidy
run: |
mkdir build && cd build
cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DOC_CLANG_TIDY_ENABLED=ON -DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_MNT_ENABLED=ON -DOC_WKCORE_ENABLED=ON -DOC_SOFTWARE_UPDATE_ENABLED=ON -DOC_PUSH_ENABLED=ON -DPLGD_DEV_TIME_ENABLED=ON -DOC_ETAG_ENABLED=ON -DBUILD_TESTING=OFF ..
cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -DOC_CLANG_TIDY_ENABLED=ON -DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_MNT_ENABLED=ON -DOC_WKCORE_ENABLED=ON -DOC_SOFTWARE_UPDATE_ENABLED=ON -DOC_DISCOVERY_RESOURCE_OBSERVABLE_ENABLED=ON -DOC_PUSH_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DPLGD_DEV_TIME_ENABLED=ON -DOC_ETAG_ENABLED=ON -DBUILD_TESTING=OFF ..
cmake --build .
283 changes: 283 additions & 0 deletions api/oc_query.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
/****************************************************************************
*
* Copyright (c) 2016 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License"),
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************/

#include "api/oc_query_internal.h"
#include "api/oc_helpers_internal.h"
#include "api/oc_ri_internal.h"
#include "oc_api.h"
#include "oc_ri.h"

#include <assert.h>
#include <limits.h>
#include <stddef.h>
#include <string.h>

static size_t g_query_iterator;

#ifdef OC_SERVER

oc_string_view_t
oc_query_encode_interface(oc_interface_mask_t iface_mask)
{
switch (iface_mask) {
case OC_IF_BASELINE:
return OC_STRING_VIEW("if=" OC_IF_BASELINE_STR);
case OC_IF_LL:
return OC_STRING_VIEW("if=" OC_IF_LL_STR);
case OC_IF_B:
return OC_STRING_VIEW("if=" OC_IF_B_STR);
case OC_IF_R:
return OC_STRING_VIEW("if=" OC_IF_R_STR);
case OC_IF_RW:
return OC_STRING_VIEW("if=" OC_IF_RW_STR);
case OC_IF_A:
return OC_STRING_VIEW("if=" OC_IF_A_STR);
case OC_IF_S:
return OC_STRING_VIEW("if=" OC_IF_S_STR);
case OC_IF_CREATE:
return OC_STRING_VIEW("if=" OC_IF_CREATE_STR);
case OC_IF_W:
return OC_STRING_VIEW("if=" OC_IF_W_STR);
case OC_IF_STARTUP:
return OC_STRING_VIEW("if=" OC_IF_STARTUP_STR);
case OC_IF_STARTUP_REVERT:
return OC_STRING_VIEW("if=" OC_IF_STARTUP_REVERT_STR);
default:
break;
}
return oc_string_view_null();
}

#endif /* OC_SERVER */

// representation of query key-value pairs (&key=value)
typedef struct
{
const char *key;
size_t key_len;
const char *value;
size_t value_len;
} key_value_pair_t;

static key_value_pair_t
oc_ri_find_query_nth_key_value_pair(const char *query, size_t query_len,
size_t n)
{
key_value_pair_t res = { NULL, 0, NULL, 0 };
if (query == NULL) {
return res;
}
const char *start = query;
const char *end = query + query_len;
// find nth key-value pair
size_t i = 0;
while (i < (n - 1)) {
start = (const char *)memchr(start, '&', end - start);
if (start == NULL) {
return res;
}
++i;
++start;
}
res.key = start;

const char *value = (const char *)memchr(start, '=', end - start);
const char *next_pair = (const char *)memchr(start, '&', end - start);
// verify that the found value belongs to the current key
if (next_pair != NULL && (next_pair < value)) {
// the current key does not have a '='
value = NULL;
}
if (value == NULL) {
res.key_len = next_pair != NULL ? next_pair - res.key : end - res.key;
return res;
}
res.key_len = value - res.key;

++value; // move past '='
res.value = value;
res.value_len = next_pair != NULL ? next_pair - res.value : end - res.value;
return res;
}

int
oc_ri_get_query_nth_key_value(const char *query, size_t query_len,
const char **key, size_t *key_len,
const char **value, size_t *value_len, size_t n)
{
assert(key != NULL);
assert(key_len != NULL);
key_value_pair_t kv =
oc_ri_find_query_nth_key_value_pair(query, query_len, n);
if (kv.key == NULL) {
return -1;
}

*key = kv.key;
*key_len = kv.key_len;
if (value != NULL) {
*value = kv.value;
}
if (value_len != NULL) {
*value_len = kv.value_len;
}

size_t next_pos =
kv.value != NULL ? (size_t)((kv.value + kv.value_len) - query) : kv.key_len;
++next_pos; // +1 for '&'

assert(next_pos <= INT_MAX);
return (int)next_pos;
}

int
oc_ri_get_query_value(const char *query, size_t query_len, const char *key,
const char **value)
{
assert(key != NULL);
int found = -1;
size_t pos = 0;
while (pos < query_len) {
const char *k;
size_t kl;
size_t vl;
int next_pos = oc_ri_get_query_nth_key_value(query + pos, query_len - pos,
&k, &kl, value, &vl, 1u);
if (next_pos == -1) {
return -1;
}

if (kl == strlen(key) && strncasecmp(key, k, kl) == 0) {
found = (int)vl;
break;
}

pos += next_pos;
}
return found;
}

int
oc_ri_query_nth_key_exists(const char *query, size_t query_len,
const char **key, size_t *key_len, size_t n)
{
assert(key != NULL);
assert(key_len != NULL);
key_value_pair_t kv =
oc_ri_find_query_nth_key_value_pair(query, query_len, n);
if (kv.key == NULL) {
return -1;
}

*key = kv.key;
*key_len = kv.key_len;

size_t next_pos =
kv.value != NULL ? (size_t)((kv.value + kv.value_len) - query) : kv.key_len;
++next_pos; // +1 for '&'

assert(next_pos <= INT_MAX);
return (int)next_pos;
}

int
oc_ri_query_exists(const char *query, size_t query_len, const char *key)
{
assert(key != NULL);
int found = -1;
size_t pos = 0;
while (pos < query_len) {
const char *k;
size_t kl;
int next_pos =
oc_ri_query_nth_key_exists(query + pos, query_len - pos, &k, &kl, 1u);

if (next_pos == -1) {
return -1;
}

if (kl == strlen(key) && strncasecmp(key, k, kl) == 0) {
found = 1;
break;
}
if (next_pos == 0) {
return -1;
}

pos += next_pos;
}
return found;
}

void
oc_init_query_iterator(void)
{
g_query_iterator = 0;
}

int
oc_iterate_query(const oc_request_t *request, const char **key, size_t *key_len,
const char **value, size_t *value_len)
{
++g_query_iterator;
return oc_ri_get_query_nth_key_value(request->query, request->query_len, key,
key_len, value, value_len,
g_query_iterator);
}

bool
oc_iterate_query_get_values(const oc_request_t *request, const char *key,
const char **value, int *value_len)
{
size_t key_len = strlen(key);
int pos = 0;
do {
const char *k = NULL;
size_t k_len = 0;
const char *v = NULL;
size_t v_len = 0;
pos = oc_iterate_query(request, &k, &k_len, &v, &v_len);
if (pos != -1 && key_len == k_len && memcmp(key, k, k_len) == 0) {
*value = v;
*value_len = (int)v_len;
goto more_or_done;
}
} while (pos != -1);

more_or_done:
return pos != -1 && (size_t)pos < request->query_len;
}

int
oc_get_query_value(const oc_request_t *request, const char *key,
const char **value)
{
if (!request) {
return -1;
}
return oc_ri_get_query_value(request->query, request->query_len, key, value);
}

int
oc_query_value_exists(const oc_request_t *request, const char *key)
{
if (!request) {
return -1;
}
return oc_ri_query_exists(request->query, request->query_len, key);
}
40 changes: 40 additions & 0 deletions api/oc_query_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/****************************************************************************
*
* Copyright (c) 2023 plgd.dev s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License"),
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************/

#ifndef OC_QUERY_INTERNAL_H
#define OC_QUERY_INTERNAL_H

#include "api/oc_helpers_internal.h"
#include "oc_ri.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef OC_SERVER

/** @brief Encode interface to string in format "if=<interface>" */
oc_string_view_t oc_query_encode_interface(oc_interface_mask_t iface_mask);

#endif /* OC_SERVER */

#ifdef __cplusplus
}
#endif

#endif /* OC_QUERY_INTERNAL_H */
Loading

0 comments on commit 2a1116c

Please sign in to comment.