Merge pull request #11189 from leandrolanzieri/gcoap_link_format_options
sys: Add Link Format module
This commit is contained in:
commit
033b60b2d0
@ -97,3 +97,7 @@ endif
|
|||||||
ifneq (native,$(BOARD))
|
ifneq (native,$(BOARD))
|
||||||
INCLUDES += -I$(RIOTBASE)/sys/libc/include
|
INCLUDES += -I$(RIOTBASE)/sys/libc/include
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter clif, $(USEMODULE)))
|
||||||
|
INCLUDES += -I$(RIOTBASE)/sys/clif/include
|
||||||
|
endif
|
||||||
|
|||||||
1
sys/clif/Makefile
Normal file
1
sys/clif/Makefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
include $(RIOTBASE)/Makefile.base
|
||||||
351
sys/clif/clif.c
Normal file
351
sys/clif/clif.c
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019 HAW Hamburg
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup sys_clif
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief CoRE Link format encoding and decoding library implementation
|
||||||
|
*
|
||||||
|
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "clif.h"
|
||||||
|
#include "clif_internal.h"
|
||||||
|
|
||||||
|
#define ENABLE_DEBUG (0)
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
/* returns the correspondant attribute string */
|
||||||
|
static const char *_attr_to_str[] = {
|
||||||
|
[CLIF_ATTR_ANCHOR] = LF_ATTR_ANCHOR,
|
||||||
|
[CLIF_ATTR_REL] = LF_ATTR_REL_TYPE,
|
||||||
|
[CLIF_ATTR_LANG] = LF_ATTR_LANG,
|
||||||
|
[CLIF_ATTR_MEDIA] = LF_ATTR_MEDIA,
|
||||||
|
[CLIF_ATTR_TITLE] = LF_ATTR_TITLE,
|
||||||
|
[CLIF_ATTR_TITLE_EXT] = LF_ATTR_TITLE_EXT,
|
||||||
|
[CLIF_ATTR_TYPE] = LF_ATTR_TYPE,
|
||||||
|
[CLIF_ATTR_RT] = LF_ATTR_RES_TYPE,
|
||||||
|
[CLIF_ATTR_IF] = LF_ATTR_IF_DESC,
|
||||||
|
[CLIF_ATTR_SZ] = LF_ATTR_SIZE,
|
||||||
|
[CLIF_ATTR_CT] = LF_ATTR_CT,
|
||||||
|
[CLIF_ATTR_OBS] = LF_ATTR_OBS
|
||||||
|
};
|
||||||
|
|
||||||
|
/* returns the correspondant attribute string size */
|
||||||
|
static const unsigned _attr_to_size[] = {
|
||||||
|
[CLIF_ATTR_ANCHOR] = LF_ATTR_ANCHOR_S,
|
||||||
|
[CLIF_ATTR_REL] = LF_ATTR_REL_TYPE_S,
|
||||||
|
[CLIF_ATTR_LANG] = LF_ATTR_LANG_S,
|
||||||
|
[CLIF_ATTR_MEDIA] = LF_ATTR_MEDIA_S,
|
||||||
|
[CLIF_ATTR_TITLE] = LF_ATTR_TITLE_S,
|
||||||
|
[CLIF_ATTR_TITLE_EXT] = LF_ATTR_TITLE_EXT_S,
|
||||||
|
[CLIF_ATTR_TYPE] = LF_ATTR_TYPE_S,
|
||||||
|
[CLIF_ATTR_RT] = LF_ATTR_RES_TYPE_S,
|
||||||
|
[CLIF_ATTR_IF] = LF_ATTR_IF_DESC_S,
|
||||||
|
[CLIF_ATTR_SZ] = LF_ATTR_SIZE_S,
|
||||||
|
[CLIF_ATTR_CT] = LF_ATTR_CT_S,
|
||||||
|
[CLIF_ATTR_OBS] = LF_ATTR_OBS_S
|
||||||
|
};
|
||||||
|
|
||||||
|
/* do not count extension attr type */
|
||||||
|
#define ATTRS_NUMOF (sizeof(_attr_to_str) / sizeof(_attr_to_str[0]))
|
||||||
|
|
||||||
|
ssize_t clif_decode_link(clif_t *link, clif_attr_t *attrs, unsigned attrs_len,
|
||||||
|
const char *buf, size_t maxlen)
|
||||||
|
{
|
||||||
|
|
||||||
|
assert(buf);
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
char *pos;
|
||||||
|
const char *end = buf + maxlen;
|
||||||
|
clif_attr_t _dummy_attr;
|
||||||
|
|
||||||
|
ssize_t size = clif_get_target(buf, maxlen, &pos);
|
||||||
|
if (size < 0) {
|
||||||
|
return CLIF_NOT_FOUND;
|
||||||
|
}
|
||||||
|
link->target = pos;
|
||||||
|
link->target_len = size;
|
||||||
|
link->attrs_len = 0;
|
||||||
|
link->attrs = attrs;
|
||||||
|
pos += size + 1; /* escape the '>' */
|
||||||
|
|
||||||
|
DEBUG("Found target (%u): %.*s\n", (unsigned)size, (unsigned)size,
|
||||||
|
link->target);
|
||||||
|
|
||||||
|
/* if there is no attr array iterate over the buffer, if not until all
|
||||||
|
* the array is used */
|
||||||
|
while ((!attrs && pos < end) || (attrs && link->attrs_len < attrs_len)) {
|
||||||
|
clif_attr_t *attr = attrs ? &attrs[link->attrs_len] : &_dummy_attr;
|
||||||
|
size = clif_get_attr(pos, end - pos, attr);
|
||||||
|
if (size < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += size;
|
||||||
|
link->attrs_len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos - buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t clif_encode_link(const clif_t *link, char *buf, size_t maxlen)
|
||||||
|
{
|
||||||
|
assert(link);
|
||||||
|
size_t pos = 0;
|
||||||
|
ssize_t res = 0;
|
||||||
|
|
||||||
|
res = clif_add_target(link->target, buf, maxlen);
|
||||||
|
if (res < 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
pos += res;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < link->attrs_len; i++) {
|
||||||
|
res = clif_add_attr(&link->attrs[i], buf ? &buf[pos] : NULL,
|
||||||
|
maxlen - pos);
|
||||||
|
if (res <= 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
pos += res;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t clif_add_target(const char *target, char *buf, size_t maxlen)
|
||||||
|
{
|
||||||
|
assert(target);
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
size_t target_len = strlen(target);
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
return target_len + 2; /* size after adding '<' and '>' */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((target_len + 2) > maxlen) {
|
||||||
|
return CLIF_NO_SPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[pos++] = LF_PATH_BEGIN_C;
|
||||||
|
|
||||||
|
memcpy(&buf[pos], target, target_len);
|
||||||
|
pos += target_len;
|
||||||
|
|
||||||
|
buf[pos++] = LF_PATH_END_C;
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t clif_add_link_separator(char *buf, size_t maxlen)
|
||||||
|
{
|
||||||
|
if (!buf) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxlen < 1) {
|
||||||
|
return CLIF_NO_SPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*buf = LF_LINK_SEPARATOR_C;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t clif_add_attr(clif_attr_t *attr, char *buf, size_t maxlen)
|
||||||
|
{
|
||||||
|
assert(attr);
|
||||||
|
assert(attr->key);
|
||||||
|
|
||||||
|
/* if no length given, calculate it */
|
||||||
|
if (!attr->key_len) {
|
||||||
|
attr->key_len = strlen(attr->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* count attr name size and separator ';' */
|
||||||
|
size_t req_space = attr->key_len + 1;
|
||||||
|
size_t pos = 0;
|
||||||
|
int quoted = strcmp(attr->key, LF_ATTR_SIZE) ? 1 : 0;
|
||||||
|
|
||||||
|
if (attr->value) {
|
||||||
|
if (!attr->value_len) {
|
||||||
|
attr->value_len = strlen(attr->value);
|
||||||
|
}
|
||||||
|
/* count also '=' */
|
||||||
|
req_space += attr->value_len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quoted) {
|
||||||
|
req_space += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
return req_space;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req_space > maxlen) {
|
||||||
|
return CLIF_NO_SPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add attribute separator ';' */
|
||||||
|
buf[pos++] = LF_ATTR_SEPARATOR_C;
|
||||||
|
|
||||||
|
/* add attribute name */
|
||||||
|
memcpy(&buf[pos], attr->key, attr->key_len);
|
||||||
|
pos += attr->key_len;
|
||||||
|
|
||||||
|
/* add attribute value if defined */
|
||||||
|
if (attr->value) {
|
||||||
|
buf[pos++] = LF_ATTR_VAL_SEPARATOR_C;
|
||||||
|
|
||||||
|
if (quoted) {
|
||||||
|
buf[pos++] = '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&buf[pos], attr->value, attr->value_len);
|
||||||
|
pos += attr->value_len;
|
||||||
|
|
||||||
|
if (quoted) {
|
||||||
|
buf[pos++] = '"';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t clif_get_target(const char *input, size_t input_len, char **output)
|
||||||
|
{
|
||||||
|
assert(input);
|
||||||
|
char *target_end;
|
||||||
|
|
||||||
|
*output = memchr(input, LF_PATH_BEGIN_C, input_len);
|
||||||
|
if (!*output) {
|
||||||
|
DEBUG("Path start not found\n");
|
||||||
|
return CLIF_NOT_FOUND;
|
||||||
|
}
|
||||||
|
*output += 1;
|
||||||
|
|
||||||
|
target_end = memchr(*output, LF_PATH_END_C, (input + input_len) - *output);
|
||||||
|
if (!target_end) {
|
||||||
|
DEBUG("Path end not found\n");
|
||||||
|
return CLIF_NOT_FOUND;
|
||||||
|
}
|
||||||
|
ssize_t res = target_end - *output;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t clif_get_attr(const char *input, size_t input_len, clif_attr_t *attr)
|
||||||
|
{
|
||||||
|
assert(input);
|
||||||
|
assert(attr);
|
||||||
|
const char *pos = input;
|
||||||
|
const char *end = input + input_len;
|
||||||
|
bool quoted = false;
|
||||||
|
bool scan_value = false;
|
||||||
|
|
||||||
|
/* initialize attr */
|
||||||
|
attr->value = NULL;
|
||||||
|
attr->key = NULL;
|
||||||
|
|
||||||
|
/* an attribute should start with the separator */
|
||||||
|
if (*pos != LF_ATTR_SEPARATOR_C) {
|
||||||
|
DEBUG("Attribute should start with separator, found %c\n", *pos);
|
||||||
|
return CLIF_NOT_FOUND;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
attr->key = pos;
|
||||||
|
|
||||||
|
/* iterate over key */
|
||||||
|
while (pos < end) {
|
||||||
|
if (*pos == LF_ATTR_SEPARATOR_C || *pos == LF_LINK_SEPARATOR_C) {
|
||||||
|
/* key ends, no value */
|
||||||
|
attr->key_len = pos - attr->key;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*pos == LF_ATTR_VAL_SEPARATOR_C) {
|
||||||
|
/* key ends, has value */
|
||||||
|
attr->key_len = pos - attr->key;
|
||||||
|
/* check if the value is quoted and prepare pointer for value scan */
|
||||||
|
pos++;
|
||||||
|
if (*pos == '"') {
|
||||||
|
quoted = true;
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
attr->value = (char *)pos;
|
||||||
|
scan_value = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scan_value) {
|
||||||
|
/* iterate over value */
|
||||||
|
while (pos < end) {
|
||||||
|
if (quoted) {
|
||||||
|
if (*pos == '"' && *(pos - 1) != '\\') {
|
||||||
|
/* found unescaped quote */
|
||||||
|
attr->value_len = pos - attr->value;
|
||||||
|
pos++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (*pos == LF_ATTR_SEPARATOR_C || *pos == LF_LINK_SEPARATOR_C) {
|
||||||
|
/* value ends */
|
||||||
|
attr->value_len = pos - attr->value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* buffer exhausted and no special character found, calculate length of
|
||||||
|
* attribute and exit */
|
||||||
|
attr->key_len = pos - attr->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos - input;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t clif_attr_type_to_str(clif_attr_type_t type, const char **str)
|
||||||
|
{
|
||||||
|
if (type < ATTRS_NUMOF) {
|
||||||
|
*str = _attr_to_str[type];
|
||||||
|
return _attr_to_size[type];
|
||||||
|
}
|
||||||
|
return CLIF_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
clif_attr_type_t clif_get_attr_type(const char *input, size_t input_len)
|
||||||
|
{
|
||||||
|
assert(input);
|
||||||
|
assert(input_len > 0);
|
||||||
|
clif_attr_type_t ret = CLIF_ATTR_EXT;
|
||||||
|
for (unsigned i = 0; i < ATTRS_NUMOF; i++) {
|
||||||
|
if (input_len == _attr_to_size[i] &&
|
||||||
|
!strncmp(input, _attr_to_str[i], input_len)) {
|
||||||
|
ret = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int clif_init_attr(clif_attr_t *attr, clif_attr_type_t type)
|
||||||
|
{
|
||||||
|
assert(attr);
|
||||||
|
attr->key_len = clif_attr_type_to_str(type, &attr->key);
|
||||||
|
return attr->key_len > 0 ? 0 : CLIF_NOT_FOUND;
|
||||||
|
}
|
||||||
155
sys/clif/include/clif_internal.h
Normal file
155
sys/clif/include/clif_internal.h
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 HAW Hamburg
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup sys_clif
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Internal definitions for CoRE Link format module
|
||||||
|
*
|
||||||
|
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
|
||||||
|
*/
|
||||||
|
#ifndef CLIF_INTERNAL_H
|
||||||
|
#define CLIF_INTERNAL_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _P_SIZE(p) (sizeof(p) - 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief link format path initial character
|
||||||
|
*/
|
||||||
|
#define LF_PATH_BEGIN_C '<'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief link format path final character
|
||||||
|
*/
|
||||||
|
#define LF_PATH_END_C '>'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief link format link separator character
|
||||||
|
*/
|
||||||
|
#define LF_LINK_SEPARATOR_C ','
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief link format attribute separator character
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_SEPARATOR_C ';'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief link format attribute value separator character
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_VAL_SEPARATOR_C '='
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Anchor attribute
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_ANCHOR "anchor" /**< attr name */
|
||||||
|
#define LF_ATTR_ANCHOR_S _P_SIZE(LF_ATTR_ANCHOR) /**< attr name length */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Relation type attribute
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_REL_TYPE "rel" /**< attr name */
|
||||||
|
#define LF_ATTR_REL_TYPE_S _P_SIZE(LF_ATTR_REL_TYPE) /**< attr name length */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Language attribute
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_LANG "hreflang" /**< attr name */
|
||||||
|
#define LF_ATTR_LANG_S _P_SIZE(LF_ATTR_LANG) /**< attr name length */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Media attribute
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_MEDIA "media" /**< attr name */
|
||||||
|
#define LF_ATTR_MEDIA_S _P_SIZE(LF_ATTR_MEDIA) /**< attr name length */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Title attribute
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_TITLE "title" /**< attr name */
|
||||||
|
#define LF_ATTR_TITLE_S _P_SIZE(LF_ATTR_TITLE) /**< attr name length */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Title extended attribute
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_TITLE_EXT "title*" /**< attr name */
|
||||||
|
#define LF_ATTR_TITLE_EXT_S _P_SIZE(LF_ATTR_TITLE_EXT) /**< attr name length */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Type attribute
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_TYPE "type" /**< attr name */
|
||||||
|
#define LF_ATTR_TYPE_S _P_SIZE(LF_ATTR_TYPE) /**< attr name length */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Resource type attribute
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_RES_TYPE "rt" /**< attr name */
|
||||||
|
#define LF_ATTR_RES_TYPE_S _P_SIZE(LF_ATTR_RES_TYPE) /**< attr name length */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Interface description attribute
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_IF_DESC "if" /**< attr name */
|
||||||
|
#define LF_ATTR_IF_DESC_S _P_SIZE(LF_ATTR_IF_DESC) /**< attr name length */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Size attribute
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_SIZE "sz" /**< attr name */
|
||||||
|
#define LF_ATTR_SIZE_S _P_SIZE(LF_ATTR_SIZE) /**< attr name length */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Content-format attribute
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_CT "ct" /**< attr name */
|
||||||
|
#define LF_ATTR_CT_S _P_SIZE(LF_ATTR_CT) /**< attr name length */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Observable attribute
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#define LF_ATTR_OBS "obs" /**< attr name */
|
||||||
|
#define LF_ATTR_OBS_S _P_SIZE(LF_ATTR_OBS) /**< attr name length */
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CLIF_INTERNAL_H */
|
||||||
|
/** @} */
|
||||||
317
sys/include/clif.h
Normal file
317
sys/include/clif.h
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 HAW Hamburg
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup sys_clif CoRE Link Format
|
||||||
|
* @ingroup sys_serialization
|
||||||
|
* @brief Simple encoding and decoding of CoRE Link Format (RFC 6690)
|
||||||
|
* strings
|
||||||
|
* @see RFC 6690: https://tools.ietf.org/html/rfc6690
|
||||||
|
*
|
||||||
|
* clif provides a high-level API for CoRE Link Format encoding and decoding of
|
||||||
|
* links, through the @ref clif_encode_link and @ref clif_decode_link
|
||||||
|
* respectively.
|
||||||
|
*
|
||||||
|
* The high-level API is built on top of low-level functions provided by clif,
|
||||||
|
* such as @ref clif_add_target, @ref clif_add_attr, and @ref clif_get_attr.
|
||||||
|
* Also, some convenience functions like @ref clif_get_attr_type,
|
||||||
|
* @ref clif_attr_type_to_str and @ref clif_init_attr are provided, to
|
||||||
|
* facilitate the work with links.
|
||||||
|
*
|
||||||
|
* ### Decoding
|
||||||
|
* @ref clif_decode_link takes a buffer which contains an encoded link and
|
||||||
|
* returns the information of it in a @ref clif_t structure and each attribute
|
||||||
|
* in a @ref clif_attr_t structure of a given array.
|
||||||
|
*
|
||||||
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
|
||||||
|
* // A buffer 'input_buf' of length 'input_len' contains the links to decode
|
||||||
|
* clif_attr_t out_attrs[ATTRS_NUM];
|
||||||
|
* clif_t out_links[LINKS_NUM];
|
||||||
|
*
|
||||||
|
* const char *pos = input_buf;
|
||||||
|
* unsigned links_numof = 0;
|
||||||
|
* unsigned attrs_numof = 0;
|
||||||
|
*
|
||||||
|
* while (pos < &input_buf[input_len]) {
|
||||||
|
* ssize_t res = clif_decode_link(&out_links[links_numof],
|
||||||
|
* &out_attrs[attrs_numof],
|
||||||
|
* ATTRS_NUM - attrs_numof, pos,
|
||||||
|
* &input_buf[input_len]- pos);
|
||||||
|
* if (res < 0) {
|
||||||
|
* break;
|
||||||
|
* }
|
||||||
|
* pos += res;
|
||||||
|
* attrs_numof += out_links[links_numof].attrs_len;
|
||||||
|
* links_numof++;
|
||||||
|
* }
|
||||||
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
*
|
||||||
|
* ### Encoding
|
||||||
|
* @ref clif_encode_link encodes a given link into a buffer, it can be called
|
||||||
|
* with a NULL pointer, in that case it will only calculate the amount of bytes
|
||||||
|
* needed to encode the link. After every call to this function a separator
|
||||||
|
* needs to be added to the buffer.
|
||||||
|
*
|
||||||
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
|
||||||
|
* // A 'links' array of clif_t, of length 'links_len' contains the links to encode
|
||||||
|
* char out[OUT_SIZE];
|
||||||
|
* ssize_t res;
|
||||||
|
* size_t pos = 0;
|
||||||
|
*
|
||||||
|
* for (unsigned i = 0; i < links_len; i++) {
|
||||||
|
* if (i) {
|
||||||
|
* res = clif_add_link_separator(&out[pos], OUT_SIZE - pos);
|
||||||
|
* if (res <= 0) {
|
||||||
|
* break;
|
||||||
|
* }
|
||||||
|
* pos += res;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* res = clif_encode_link(&links[i], &out[pos], OUT_SIZE - pos);
|
||||||
|
* if (res <= 0) {
|
||||||
|
* break;
|
||||||
|
* }
|
||||||
|
* pos += res;
|
||||||
|
* }
|
||||||
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
*
|
||||||
|
* @note 'attribute', in this module, extends to the term 'link-param' on the
|
||||||
|
* ABNF in [section 2 of RFC 6690](https://tools.ietf.org/html/rfc6690#section-2).
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief CoRE Link Format encoding and decoding library public
|
||||||
|
* definitions
|
||||||
|
*
|
||||||
|
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CLIF_H
|
||||||
|
#define CLIF_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "clif_internal.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return types for the @ref sys_clif API
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
CLIF_OK = 0, /**< success */
|
||||||
|
CLIF_NO_SPACE = -1, /**< not enough space in the buffer */
|
||||||
|
CLIF_NOT_FOUND = -2 /**< could not find a component in a buffer */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Types of link format attributes
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
CLIF_ATTR_ANCHOR = 0, /**< anchor */
|
||||||
|
CLIF_ATTR_REL = 1, /**< rel */
|
||||||
|
CLIF_ATTR_LANG = 2, /**< hreflang */
|
||||||
|
CLIF_ATTR_MEDIA = 3, /**< media */
|
||||||
|
CLIF_ATTR_TITLE = 4, /**< title */
|
||||||
|
CLIF_ATTR_TITLE_EXT = 5, /**< title* */
|
||||||
|
CLIF_ATTR_TYPE = 6, /**< type */
|
||||||
|
CLIF_ATTR_RT = 7, /**< rt */
|
||||||
|
CLIF_ATTR_IF = 8, /**< if */
|
||||||
|
CLIF_ATTR_SZ = 9, /**< sz */
|
||||||
|
CLIF_ATTR_CT = 10, /**< ct */
|
||||||
|
CLIF_ATTR_OBS = 11, /**< obs */
|
||||||
|
CLIF_ATTR_EXT = 12 /**< extensions */
|
||||||
|
} clif_attr_type_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Link format attribute descriptor
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
char *value; /**< string with the value */
|
||||||
|
unsigned value_len; /**< length of the value */
|
||||||
|
const char *key; /**< attribute name */
|
||||||
|
unsigned key_len; /**< length of the attribute name */
|
||||||
|
} clif_attr_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Link format descriptor
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
char *target; /**< target string */
|
||||||
|
unsigned target_len; /**< length of target string */
|
||||||
|
clif_attr_t *attrs; /**< array of attributes */
|
||||||
|
unsigned attrs_len; /**< size of array of attributes */
|
||||||
|
} clif_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Encodes a given link in link format into a given buffer
|
||||||
|
*
|
||||||
|
* @pre `link != NULL`
|
||||||
|
*
|
||||||
|
* @param[in] link link to encode.Must not be NULL.
|
||||||
|
* @param[out] buf buffer to output the encoded link. Can be NULL
|
||||||
|
* @param[in] maxlen size of @p buf
|
||||||
|
*
|
||||||
|
* @note If @p buf is NULL this will return the amount of bytes that would be
|
||||||
|
* needed
|
||||||
|
*
|
||||||
|
* @return amount of bytes used from @p buf in success
|
||||||
|
* @return CLIF_NO_SPACE if there is not enough space in the buffer
|
||||||
|
*/
|
||||||
|
ssize_t clif_encode_link(const clif_t *link, char *buf, size_t maxlen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decodes a string of link format. It decodes the first occurrence of
|
||||||
|
* a link.
|
||||||
|
*
|
||||||
|
* @pre `(link != NULL) && (buf != NULL)`
|
||||||
|
*
|
||||||
|
* @param[out] link link to populate. Must not be NULL.
|
||||||
|
* @param[out] attrs array of attrs to populate
|
||||||
|
* @param[in] attrs_len length of @p attrs
|
||||||
|
* @param[in] buf string to decode. Must not be NULL.
|
||||||
|
* @param[in] maxlen size of @p buf
|
||||||
|
*
|
||||||
|
* @return number of bytes parsed from @p buf in success
|
||||||
|
* @return CLIF_NOT_FOUND if the string is malformed
|
||||||
|
*/
|
||||||
|
ssize_t clif_decode_link(clif_t *link, clif_attr_t *attrs, unsigned attrs_len,
|
||||||
|
const char *buf, size_t maxlen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a given @p target to a given buffer @p buf using link format
|
||||||
|
*
|
||||||
|
* @pre `target != NULL`
|
||||||
|
*
|
||||||
|
* @param[in] target string containing the path to the resource. Must not be
|
||||||
|
* NULL.
|
||||||
|
* @param[out] buf buffer to output the formatted path. Can be NULL
|
||||||
|
* @param[in] maxlen size of @p buf
|
||||||
|
*
|
||||||
|
* @note If @p buf is NULL this will return the amount of bytes that would be
|
||||||
|
* needed
|
||||||
|
*
|
||||||
|
* @return in success the amount of bytes used in the buffer
|
||||||
|
* @return CLIF_NO_SPACE if there is not enough space in the buffer
|
||||||
|
*/
|
||||||
|
ssize_t clif_add_target(const char *target, char *buf, size_t maxlen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a given @p attr to a given buffer @p buf using link format
|
||||||
|
*
|
||||||
|
* @pre `(attr != NULL) && (attr->key != NULL)`
|
||||||
|
*
|
||||||
|
* @param[in] attr pointer to the attribute to add. Must not be NULL, and
|
||||||
|
* must contain a key.
|
||||||
|
* @param[out] buf buffer to add the attribute to. Can be NULL
|
||||||
|
* @param[in] maxlen size of @p buf
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* - If @p buf is NULL this will return the amount of bytes that would be
|
||||||
|
* needed.
|
||||||
|
* - If the lengths of the key or the value of the attribute are not
|
||||||
|
* defined a NULL-terminated string will be assumed, and it will be
|
||||||
|
* calculated.
|
||||||
|
*
|
||||||
|
* @return amount of bytes used from the buffer if successful
|
||||||
|
* @return CLIF_NO_SPACE if there is not enough space in the buffer
|
||||||
|
*/
|
||||||
|
ssize_t clif_add_attr(clif_attr_t *attr, char *buf, size_t maxlen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds the link separator character to a given @p buf, using link
|
||||||
|
* format
|
||||||
|
*
|
||||||
|
* @param[out] buf buffer to add the separator to. Can be NULL
|
||||||
|
* @param[in] maxlen size of @p buf
|
||||||
|
*
|
||||||
|
* @note If @p buf is NULL this will return the amount of bytes that would be
|
||||||
|
* needed
|
||||||
|
*
|
||||||
|
* @return amount of bytes used from buffer if successful
|
||||||
|
* @return CLIF_NO_SPACE if there is not enough space in the buffer
|
||||||
|
*/
|
||||||
|
ssize_t clif_add_link_separator(char *buf, size_t maxlen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Looks for a the target URI of a given link.
|
||||||
|
*
|
||||||
|
* @pre `input != NULL`
|
||||||
|
*
|
||||||
|
* @param[in] input string where to look for the target. It should only
|
||||||
|
* be ONE link. Must not be NULL.
|
||||||
|
* @param[in] input_len length of @p input.
|
||||||
|
* @param[out] output if a target is found this will point to the
|
||||||
|
* beginning of it
|
||||||
|
*
|
||||||
|
* @return length of the target if found
|
||||||
|
* @return CLIF_NOT_FOUND if no valid target is found
|
||||||
|
*/
|
||||||
|
ssize_t clif_get_target(const char *input, size_t input_len, char **output);
|
||||||
|
/**
|
||||||
|
* @brief Looks for the first attribute in a given link.
|
||||||
|
*
|
||||||
|
* @pre `(input != NULL) && (attr != NULL)`
|
||||||
|
*
|
||||||
|
* @note In order to consider that the string contains a valid attribute,
|
||||||
|
* @p input should start with the attribute separator character ';'.
|
||||||
|
*
|
||||||
|
* @param[in] input string where to look for the attribute. It should
|
||||||
|
* only be ONE link. Must not be NULL.
|
||||||
|
* @param[in] input_len length of @p input
|
||||||
|
* @param[out] attr pointer to store the found attribute information.
|
||||||
|
* Must not be NULL.
|
||||||
|
*
|
||||||
|
* @return length of the attribute in the buffer if found
|
||||||
|
* @return CLIF_NOT_FOUND if no valid attribute is found
|
||||||
|
*/
|
||||||
|
ssize_t clif_get_attr(const char *input, size_t input_len, clif_attr_t *attr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the attribute type of a given string.
|
||||||
|
*
|
||||||
|
* @pre `(input != NULL) && (input_len > 0)`
|
||||||
|
*
|
||||||
|
* @param[in] input string containing the attribute name. Must not be NULL.
|
||||||
|
* @param[in] input_len length of @p input. Must be greater than 0.
|
||||||
|
*
|
||||||
|
* @return type of the attribute
|
||||||
|
*/
|
||||||
|
clif_attr_type_t clif_get_attr_type(const char *input, size_t input_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns a constant string of a given attribute type
|
||||||
|
*
|
||||||
|
* @param[in] type type of the attribute
|
||||||
|
* @param[out] str pointer to store the string pointer
|
||||||
|
*
|
||||||
|
* @return length of the string
|
||||||
|
* @return CLIF_NOT_FOUND if the type is an extension or unknown
|
||||||
|
*/
|
||||||
|
ssize_t clif_attr_type_to_str(clif_attr_type_t type, const char **str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the key of a given attribute according to a given type.
|
||||||
|
*
|
||||||
|
* @param[out] attr attribute to initialize
|
||||||
|
* @param[in] type type of the attribute
|
||||||
|
*
|
||||||
|
* @return 0 if successful
|
||||||
|
* @return <0 otherwise
|
||||||
|
*/
|
||||||
|
int clif_init_attr(clif_attr_t *attr, clif_attr_type_t type);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CLIF_H */
|
||||||
|
/** @} */
|
||||||
1
tests/unittests/tests-clif/Makefile
Normal file
1
tests/unittests/tests-clif/Makefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
include $(RIOTBASE)/Makefile.base
|
||||||
1
tests/unittests/tests-clif/Makefile.include
Normal file
1
tests/unittests/tests-clif/Makefile.include
Normal file
@ -0,0 +1 @@
|
|||||||
|
USEMODULE += clif
|
||||||
292
tests/unittests/tests-clif/tests-clif.c
Normal file
292
tests/unittests/tests-clif/tests-clif.c
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 HAW Hamburg
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "embUnit.h"
|
||||||
|
#include "tests-clif.h"
|
||||||
|
|
||||||
|
#include "clif.h"
|
||||||
|
|
||||||
|
#ifdef TESTS_CLIF_PRINT
|
||||||
|
#include <stdio.h>
|
||||||
|
static void _print_attr(clif_attr_t *attr)
|
||||||
|
{
|
||||||
|
if (attr->key) {
|
||||||
|
printf("-- Attr: ");
|
||||||
|
printf("%.*s", attr->key_len, attr->key);
|
||||||
|
if (attr->value) {
|
||||||
|
printf(" = %.*s\n", attr->value_len, attr->value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
puts("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* TESTS_CLIF_PRINT */
|
||||||
|
|
||||||
|
#define _STR_LEN(s) (sizeof(s)-1)
|
||||||
|
#define _NEW_ATTR(k, v) { .key = k, .key_len = _STR_LEN(k), .value = v, \
|
||||||
|
.value_len = _STR_LEN(v) }
|
||||||
|
#define _NEW_ATTR_NO_VAL(k) { .key = k, .key_len = _STR_LEN(k), .value_len = 0 }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Compares two link format attributes
|
||||||
|
*
|
||||||
|
* @param[in] p1 first attribute to compare
|
||||||
|
* @param[in] p2 second attribute to compare
|
||||||
|
*
|
||||||
|
* @return 0 if attributes are equal
|
||||||
|
* @return 1 otherwise
|
||||||
|
*/
|
||||||
|
static unsigned _compare_attrs(clif_attr_t *p1, clif_attr_t *p2)
|
||||||
|
{
|
||||||
|
unsigned result = 1;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (p1->key_len != p2->key_len) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncmp(p1->key, p2->key, p1->key_len)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p1->value && !p2->value) {
|
||||||
|
goto success_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p1->value || !p2->value || (p1->value_len != p2->value_len)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = strncmp(p1->value, p2->value, p1->value_len);
|
||||||
|
if (res != 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
success_out:
|
||||||
|
result = 0;
|
||||||
|
out:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This also tests the functions `clif_add_target` and
|
||||||
|
* `clif_add_attr`. */
|
||||||
|
static void test_clif_encode_links(void)
|
||||||
|
{
|
||||||
|
const char exp_string[] = "</sensor/temp>;rt=\"temperature\";if=\"sensor\","
|
||||||
|
"</node/info>,</node/ep>;ct=\"40\"";
|
||||||
|
clif_attr_t attrs[] = {
|
||||||
|
{ .key = "rt", .value = "temperature" },
|
||||||
|
{ .key = "if", .value = "sensor" },
|
||||||
|
{ .key = "ct", .value = "40" }
|
||||||
|
};
|
||||||
|
|
||||||
|
clif_t links[] = {
|
||||||
|
{ .target = "/sensor/temp", .attrs = attrs, .attrs_len = 2 },
|
||||||
|
{ .target = "/node/info", .attrs_len = 0 },
|
||||||
|
{ .target = "/node/ep", .attrs = &attrs[2], .attrs_len = 1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
const size_t exp_size = sizeof(exp_string) - 1;
|
||||||
|
char output[sizeof(exp_string) + 1];
|
||||||
|
size_t pos = 0;
|
||||||
|
ssize_t res = 0;
|
||||||
|
|
||||||
|
/* first test with NULL output to check the needed bytes */
|
||||||
|
res = clif_encode_link(&links[0], NULL, 0);
|
||||||
|
pos += res;
|
||||||
|
|
||||||
|
for (unsigned i = 1; i < sizeof(links) / sizeof(links[0]); i++) {
|
||||||
|
res = clif_add_link_separator(NULL, 0);
|
||||||
|
if (res <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += res;
|
||||||
|
|
||||||
|
res = clif_encode_link(&links[i],NULL, 0);
|
||||||
|
if (res <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_INT(exp_size, pos);
|
||||||
|
|
||||||
|
/* now actually encode the links */
|
||||||
|
pos = 0;
|
||||||
|
res = clif_encode_link(&links[0], output, sizeof(output));
|
||||||
|
pos += res;
|
||||||
|
|
||||||
|
for (unsigned i = 1; i < sizeof(links) / sizeof(links[0]); i++) {
|
||||||
|
res = clif_add_link_separator(&output[pos], sizeof(output) - pos);
|
||||||
|
if (res <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += res;
|
||||||
|
|
||||||
|
res = clif_encode_link(&links[i], &output[pos], sizeof(output) - pos);
|
||||||
|
if (res <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += res;
|
||||||
|
}
|
||||||
|
output[pos++] = '\0';
|
||||||
|
|
||||||
|
#ifdef TESTS_CLIF_PRINT
|
||||||
|
puts("\n========================================");
|
||||||
|
puts("[Test: encode_links]");
|
||||||
|
puts("---------------------");
|
||||||
|
printf("Encoded links: %s\n", output);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING(exp_string, output);
|
||||||
|
TEST_ASSERT_EQUAL_INT(exp_size, pos - 1); /* do not count '\0' */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This also tests the functions `clif_get_target` and `clif_get_attr` */
|
||||||
|
static void test_clif_decode_links(void)
|
||||||
|
{
|
||||||
|
/* string to decode */
|
||||||
|
char input_string[] = "</sensors>;ct=40;title=\"\\\"Sensor\\\" Index, collection\","
|
||||||
|
"</sensors/temp>;rt=\"temperature-c\";if=\"sensor\","
|
||||||
|
"</sensors/light>;rt=\"light-lux\";if=sensor,"
|
||||||
|
"<http://www.example.com/sensors/t123>;"
|
||||||
|
"anchor=\"/sensors/temp\";rel=\"describedby\";sz=1234,"
|
||||||
|
"</t>;anchor=\"/sensors/temp\";rel=\"alternate\";a;s=\"This is \\\"escaped and has , \\\"\","
|
||||||
|
"</riot/board>,</riot/info>;obs";
|
||||||
|
|
||||||
|
/* ordered expected types to be decoded */
|
||||||
|
clif_attr_type_t exp_types[] = {
|
||||||
|
CLIF_ATTR_CT, CLIF_ATTR_TITLE, CLIF_ATTR_RT, CLIF_ATTR_IF,
|
||||||
|
CLIF_ATTR_RT, CLIF_ATTR_IF, CLIF_ATTR_ANCHOR, CLIF_ATTR_REL,
|
||||||
|
CLIF_ATTR_SZ, CLIF_ATTR_ANCHOR, CLIF_ATTR_REL, CLIF_ATTR_EXT,
|
||||||
|
CLIF_ATTR_EXT, CLIF_ATTR_OBS
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ordered amount of expected attributes per link to be decoded */
|
||||||
|
unsigned exp_attr_numof[] = { 2, 2, 2, 3, 4, 0, 1 };
|
||||||
|
|
||||||
|
/* ordered expected attributes to be decoded */
|
||||||
|
clif_attr_t exp_attrs[] = {
|
||||||
|
_NEW_ATTR("ct", "40"),
|
||||||
|
_NEW_ATTR("title", "\\\"Sensor\\\" Index, collection"),
|
||||||
|
_NEW_ATTR("rt", "temperature-c"),
|
||||||
|
_NEW_ATTR("if", "sensor"),
|
||||||
|
_NEW_ATTR("rt", "light-lux"),
|
||||||
|
_NEW_ATTR("if", "sensor"),
|
||||||
|
_NEW_ATTR("anchor", "/sensors/temp"),
|
||||||
|
_NEW_ATTR("rel", "describedby"),
|
||||||
|
_NEW_ATTR("sz", "1234"),
|
||||||
|
_NEW_ATTR("anchor", "/sensors/temp"),
|
||||||
|
_NEW_ATTR("rel", "alternate"),
|
||||||
|
_NEW_ATTR_NO_VAL("a"),
|
||||||
|
_NEW_ATTR("s", "This is \\\"escaped and has , \\\""),
|
||||||
|
_NEW_ATTR_NO_VAL("obs"),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ordered expected targets to be decoded */
|
||||||
|
const char *exp_targets[] = {
|
||||||
|
"/sensors", "/sensors/temp", "/sensors/light",
|
||||||
|
"http://www.example.com/sensors/t123", "/t", "/riot/board", "/riot/info"
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned exp_links_numof = sizeof(exp_targets) / sizeof(exp_targets[0]);
|
||||||
|
const unsigned exp_attrs_numof = sizeof(exp_attrs) / sizeof(exp_attrs[0]);
|
||||||
|
const size_t input_len = sizeof(input_string) - 1;
|
||||||
|
|
||||||
|
clif_t out_link;
|
||||||
|
char *pos = input_string;
|
||||||
|
unsigned links_numof = 0;
|
||||||
|
|
||||||
|
/* first test without attributes array, to test the expected attributes
|
||||||
|
* functionality */
|
||||||
|
do {
|
||||||
|
ssize_t res = clif_decode_link(&out_link, NULL, 0, pos,
|
||||||
|
input_len - (pos - input_string));
|
||||||
|
if (res < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += res;
|
||||||
|
|
||||||
|
/* check expected target */
|
||||||
|
TEST_ASSERT(!strncmp(exp_targets[links_numof], out_link.target, out_link.target_len));
|
||||||
|
|
||||||
|
/* check expected amount of attributes */
|
||||||
|
TEST_ASSERT_EQUAL_INT(exp_attr_numof[links_numof], out_link.attrs_len);
|
||||||
|
links_numof++;
|
||||||
|
} while (pos < input_string + sizeof(input_string));
|
||||||
|
|
||||||
|
#ifdef TESTS_CLIF_PRINT
|
||||||
|
puts("\n========================================");
|
||||||
|
puts("[Test: decode_links]");
|
||||||
|
printf("- Amount of decoded links: %u\n", links_numof);
|
||||||
|
#endif
|
||||||
|
TEST_ASSERT(exp_links_numof == links_numof);
|
||||||
|
|
||||||
|
/* now decode again but saving the attributes */
|
||||||
|
clif_attr_t out_attrs[sizeof(exp_attrs) / sizeof(exp_attrs[0])];
|
||||||
|
pos = input_string;
|
||||||
|
unsigned attrs_numof = 0;
|
||||||
|
do {
|
||||||
|
ssize_t res = clif_decode_link(&out_link, &out_attrs[attrs_numof],
|
||||||
|
exp_attrs_numof - attrs_numof, pos,
|
||||||
|
input_len - (pos - input_string));
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos += res;
|
||||||
|
#ifdef TESTS_CLIF_PRINT
|
||||||
|
puts("---------------------");
|
||||||
|
puts("New link:");
|
||||||
|
printf("- Target: %.*s\n", out_link.target_len, out_link.target);
|
||||||
|
printf("- Number of attributes: %d\n", out_link.attrs_len);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < out_link.attrs_len; i++) {
|
||||||
|
#ifdef TESTS_CLIF_PRINT
|
||||||
|
_print_attr(&out_link.attrs[i]);
|
||||||
|
#endif
|
||||||
|
/* compare the attribute structure with the expected one */
|
||||||
|
TEST_ASSERT(!_compare_attrs(&out_link.attrs[i],
|
||||||
|
&exp_attrs[attrs_numof]));
|
||||||
|
clif_attr_type_t type = clif_get_attr_type(out_link.attrs[i].key,
|
||||||
|
out_link.attrs[i].key_len);
|
||||||
|
|
||||||
|
/* check that the returned type is the expected one */
|
||||||
|
TEST_ASSERT_EQUAL_INT(exp_types[attrs_numof], type);
|
||||||
|
|
||||||
|
/* test type to string conversion */
|
||||||
|
const char *t;
|
||||||
|
if (clif_attr_type_to_str(type, &t) < 0) {
|
||||||
|
t = NULL;
|
||||||
|
}
|
||||||
|
TEST_ASSERT_EQUAL_STRING(type == CLIF_ATTR_EXT ?
|
||||||
|
NULL : exp_attrs[attrs_numof].key, t);
|
||||||
|
attrs_numof++;
|
||||||
|
}
|
||||||
|
} while (pos < input_string + sizeof(input_string));
|
||||||
|
TEST_ASSERT_EQUAL_INT(exp_attrs_numof, attrs_numof);
|
||||||
|
}
|
||||||
|
|
||||||
|
Test *tests_clif_tests(void)
|
||||||
|
{
|
||||||
|
EMB_UNIT_TESTFIXTURES(fixtures) {
|
||||||
|
new_TestFixture(test_clif_encode_links),
|
||||||
|
new_TestFixture(test_clif_decode_links)
|
||||||
|
};
|
||||||
|
|
||||||
|
EMB_UNIT_TESTCALLER(clif_tests, NULL, NULL, fixtures);
|
||||||
|
|
||||||
|
return (Test *)&clif_tests;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tests_clif(void)
|
||||||
|
{
|
||||||
|
TESTS_RUN(tests_clif_tests());
|
||||||
|
}
|
||||||
43
tests/unittests/tests-clif/tests-clif.h
Normal file
43
tests/unittests/tests-clif/tests-clif.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 HAW Hamburg
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup unittests
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Unittests for the ``clif`` module
|
||||||
|
*
|
||||||
|
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
|
||||||
|
*/
|
||||||
|
#ifndef TESTS_CLIF_H
|
||||||
|
#define TESTS_CLIF_H
|
||||||
|
#include "embUnit/embUnit.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The entry point of this test suite.
|
||||||
|
*/
|
||||||
|
void tests_clif(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generates tests for link format
|
||||||
|
*
|
||||||
|
* @return embUnit tests if successful, NULL if not.
|
||||||
|
*/
|
||||||
|
Test *tests_clif_tests(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* TESTS_CLIF_H */
|
||||||
|
/** @} */
|
||||||
Loading…
x
Reference in New Issue
Block a user