mirror of
https://github.com/obgm/libcoap.git
synced 2026-11-12 11:40:39 +03:00
Improved support for URI split and hashing.
This commit is contained in:
1 parent
5183fd951c
commit
f01582b4fe
2 files changed
+322
-62
No files matched your search
@@ -6,6 +6,7 @@
|
||||
* README for terms of use.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
@@ -16,8 +17,27 @@
|
||||
#include "option.h"
|
||||
#include "uri.h"
|
||||
|
||||
/**
|
||||
* A length-safe version of strchr(). This function returns a pointer
|
||||
* to the first occurrence of @p c in @p s, or @c NULL if not found.
|
||||
*
|
||||
* @param s The string to search for @p c.
|
||||
* @param len The length of @p s.
|
||||
* @param c The character to search.
|
||||
*
|
||||
* @return A pointer to the first occurence of @p c, or @c NULL
|
||||
* if not found.
|
||||
*/
|
||||
static inline unsigned char *
|
||||
strnchr(unsigned char *s, size_t len, unsigned char c) {
|
||||
while (len && *s++ != c)
|
||||
--len;
|
||||
|
||||
return len ? s : NULL;
|
||||
}
|
||||
|
||||
int
|
||||
coap_split_uri(const unsigned char *str_var, size_t len, coap_uri_t *uri) {
|
||||
coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) {
|
||||
unsigned char *p, *q;
|
||||
int secure = 0, res = 0;
|
||||
|
||||
@@ -167,7 +187,7 @@ coap_split_uri(const unsigned char *str_var, size_t len, coap_uri_t *uri) {
|
||||
* @param buf The result buffer.
|
||||
*/
|
||||
void
|
||||
decode_segment(unsigned char *seg, size_t length, unsigned char *buf) {
|
||||
decode_segment(const unsigned char *seg, size_t length, unsigned char *buf) {
|
||||
|
||||
while (length--) {
|
||||
|
||||
@@ -189,7 +209,7 @@ decode_segment(unsigned char *seg, size_t length, unsigned char *buf) {
|
||||
* or the length of @p s when decoded.
|
||||
*/
|
||||
int
|
||||
check_segment(unsigned char *s, size_t length) {
|
||||
check_segment(const unsigned char *s, size_t length) {
|
||||
|
||||
size_t n = 0;
|
||||
|
||||
@@ -223,9 +243,12 @@ check_segment(unsigned char *s, size_t length) {
|
||||
* @param buflen The maximum size of @p buf.
|
||||
*
|
||||
* @return The option's size, or @c -1 on error.
|
||||
*
|
||||
* @bug This function does not split segments that are bigger than 270
|
||||
* bytes.
|
||||
*/
|
||||
int
|
||||
make_decoded_option(unsigned char *s, size_t length,
|
||||
make_decoded_option(const unsigned char *s, size_t length,
|
||||
unsigned char *buf, size_t buflen) {
|
||||
int res;
|
||||
|
||||
@@ -238,15 +261,104 @@ make_decoded_option(unsigned char *s, size_t length,
|
||||
return -1;
|
||||
}
|
||||
|
||||
COAP_OPT_SETDELTA(*(coap_opt_t *)buf, 0);
|
||||
COAP_OPT_SETLENGTH(*(coap_opt_t *)buf, res);
|
||||
COAP_OPT_SETDELTA(buf, 0);
|
||||
COAP_OPT_SETLENGTH(buf, res);
|
||||
|
||||
decode_segment(s, length,
|
||||
COAP_OPT_VALUE(*(coap_opt_t *)buf));
|
||||
decode_segment(s, length, COAP_OPT_VALUE(buf));
|
||||
|
||||
return COAP_OPT_SIZE(*(coap_opt_t *)buf);
|
||||
return COAP_OPT_SIZE(buf);
|
||||
}
|
||||
|
||||
|
||||
#ifndef min
|
||||
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
typedef void (*segment_handler_t)(unsigned char *, size_t, void *);
|
||||
|
||||
/**
|
||||
* Splits the given string into segments. You should call one of the
|
||||
* macros coap_split_path() or coap_split_query() instead.
|
||||
*
|
||||
* @param parse_iter The iterator used for tokenizing.
|
||||
* @param h A handler that is called with every token.
|
||||
* @param data Opaque data that is passed to @p h when called.
|
||||
*
|
||||
* @return The number of characters that have been parsed from @p s.
|
||||
*/
|
||||
size_t
|
||||
coap_split_path_impl(coap_parse_iterator_t *parse_iter,
|
||||
segment_handler_t h, void *data) {
|
||||
unsigned char *seg;
|
||||
size_t length;
|
||||
|
||||
assert(parse_iter);
|
||||
assert(h);
|
||||
|
||||
length = parse_iter->n;
|
||||
|
||||
while ( (seg = coap_parse_next(parse_iter)) ) {
|
||||
|
||||
/* any valid path segment is handled here: */
|
||||
h(seg, parse_iter->segment_length, data);
|
||||
}
|
||||
|
||||
return length - (parse_iter->n - parse_iter->segment_length);
|
||||
}
|
||||
|
||||
struct cnt_str {
|
||||
str buf;
|
||||
int n;
|
||||
};
|
||||
|
||||
void
|
||||
write_option(unsigned char *s, size_t len, void *data) {
|
||||
struct cnt_str *state = (struct cnt_str *)data;
|
||||
int res;
|
||||
assert(state);
|
||||
|
||||
/* skip empty segments and those that consist of only one or two dots */
|
||||
if (memcmp(s, "..", min(len,2)) == 0)
|
||||
return;
|
||||
|
||||
res = make_decoded_option(s, len, state->buf.s, state->buf.length);
|
||||
if (res > 0) {
|
||||
state->buf.s += res;
|
||||
state->buf.length -= res;
|
||||
state->n++;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
coap_split_path(const unsigned char *s, size_t length,
|
||||
unsigned char *buf, size_t *buflen) {
|
||||
struct cnt_str tmp = { { *buflen, buf }, 0 };
|
||||
coap_parse_iterator_t pi;
|
||||
|
||||
coap_parse_iterator_init((unsigned char *)s, length,
|
||||
'/', (unsigned char *)"?#", 2, &pi);
|
||||
coap_split_path_impl(&pi, write_option, &tmp);
|
||||
|
||||
*buflen = tmp.buf.length;
|
||||
return tmp.n;
|
||||
}
|
||||
|
||||
int
|
||||
coap_split_query(const unsigned char *s, size_t length,
|
||||
unsigned char *buf, size_t *buflen) {
|
||||
struct cnt_str tmp = { { *buflen, buf }, 0 };
|
||||
coap_parse_iterator_t pi;
|
||||
|
||||
coap_parse_iterator_init((unsigned char *)s, length,
|
||||
'&', (unsigned char *)"#", 1, &pi);
|
||||
|
||||
coap_split_path_impl(&pi, write_option, &tmp);
|
||||
|
||||
*buflen = tmp.buf.length;
|
||||
return tmp.n;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
coap_split_path_impl(unsigned char *s, size_t length, int is_path,
|
||||
unsigned char *buf, size_t buflen) {
|
||||
@@ -298,6 +410,7 @@ coap_split_path_impl(unsigned char *s, size_t length, int is_path,
|
||||
debug("invalid segment in URI\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
|
||||
|
||||
@@ -305,12 +418,6 @@ coap_uri_t *
|
||||
coap_new_uri(const unsigned char *uri, unsigned int length) {
|
||||
unsigned char *result;
|
||||
|
||||
/**
|
||||
* @bug Some additional storage is needed to split path and query
|
||||
* into segments. Unfortunately, we do not know in advance, how
|
||||
* many segments we will get. A quick hack is to assume that every
|
||||
* segment will have 4 characters in average and hope for the best.
|
||||
*/
|
||||
result = coap_malloc(length + 1 + sizeof(coap_uri_t));
|
||||
|
||||
if (!result)
|
||||
@@ -366,3 +473,91 @@ coap_clone_uri(const coap_uri_t *uri) {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* hash URI path segments */
|
||||
|
||||
static inline void
|
||||
hash_segment(unsigned char *s, size_t len, void *data) {
|
||||
coap_hash(s, len, *(coap_key_t *)data);
|
||||
}
|
||||
|
||||
int
|
||||
coap_hash_path(const unsigned char *path, size_t len, coap_key_t key) {
|
||||
coap_parse_iterator_t pi;
|
||||
|
||||
if (!path)
|
||||
return 0;
|
||||
|
||||
memset(key, 0, sizeof(coap_key_t));
|
||||
|
||||
coap_parse_iterator_init((unsigned char *)path, len,
|
||||
'/', (unsigned char *)"?#", 2, &pi);
|
||||
coap_split_path_impl(&pi, hash_segment, &key);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* iterator functions */
|
||||
|
||||
coap_parse_iterator_t *
|
||||
coap_parse_iterator_init(unsigned char *s, size_t n,
|
||||
unsigned char separator,
|
||||
unsigned char *delim, size_t dlen,
|
||||
coap_parse_iterator_t *pi) {
|
||||
assert(s);
|
||||
assert(pi);
|
||||
assert(separator);
|
||||
|
||||
if (!s || !n)
|
||||
return NULL;
|
||||
|
||||
pi->separator = separator;
|
||||
pi->delim = delim;
|
||||
pi->dlen = dlen;
|
||||
pi->pos = s;
|
||||
pi->n = n;
|
||||
pi->segment_length = 0;
|
||||
|
||||
return pi;
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
coap_parse_next(coap_parse_iterator_t *pi) {
|
||||
unsigned char *p;
|
||||
|
||||
if (!pi)
|
||||
return NULL;
|
||||
|
||||
/* proceed to the next segment */
|
||||
pi->n -= pi->segment_length;
|
||||
pi->pos += pi->segment_length;
|
||||
pi->segment_length = 0;
|
||||
|
||||
/* last segment? */
|
||||
if (!pi->n || strnchr(pi->delim, pi->dlen, *pi->pos)) {
|
||||
pi->pos = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* skip following separator (the first segment might not have one) */
|
||||
if (*pi->pos == pi->separator) {
|
||||
++pi->pos;
|
||||
--pi->n;
|
||||
}
|
||||
|
||||
p = pi->pos;
|
||||
|
||||
while (pi->segment_length < pi->n && *p != pi->separator &&
|
||||
!strnchr(pi->delim, pi->dlen, *p)) {
|
||||
++p;
|
||||
++pi->segment_length;
|
||||
}
|
||||
|
||||
if (!pi->n) {
|
||||
pi->pos = NULL;
|
||||
pi->segment_length = 0;
|
||||
}
|
||||
|
||||
return pi->pos;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#ifndef _COAP_URI_H_
|
||||
#define _COAP_URI_H_
|
||||
|
||||
#include "hashkey.h"
|
||||
#include "str.h"
|
||||
|
||||
/** Representation of parsed URI. Components may be filled from a
|
||||
@@ -22,6 +23,98 @@ typedef struct {
|
||||
str query; /**< The query part if present */
|
||||
} coap_uri_t;
|
||||
|
||||
/**
|
||||
* Creates a new coap_uri_t object from the specified URI. Returns the new
|
||||
* object or NULL on error. The memory allocated by the new coap_uri_t
|
||||
* must be released using coap_free().
|
||||
* @param uri The URI path to copy.
|
||||
* @para length The length of uri.
|
||||
*
|
||||
* @return New URI object or NULL on error.
|
||||
*/
|
||||
coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length);
|
||||
|
||||
/**
|
||||
* Clones the specified coap_uri_t object. Thie function allocates sufficient
|
||||
* memory to hold the coap_uri_t structure and its contents. The object must
|
||||
* be released with coap_free(). */
|
||||
coap_uri_t *coap_clone_uri(const coap_uri_t *uri);
|
||||
|
||||
/**
|
||||
* Calculates a hash over the given path and stores the result in
|
||||
* @p key. This function returns @c 0 on error or @c 1 on success.
|
||||
*
|
||||
* @param path The URI path to generate hash for.
|
||||
* @param len The length of @p path.
|
||||
* @param key The output buffer.
|
||||
*
|
||||
* @return @c 1 if @p key was set, @c 0 otherwise.
|
||||
*/
|
||||
int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key);
|
||||
|
||||
/**
|
||||
* @defgroup uri_parse URI Parsing Functions
|
||||
*
|
||||
* CoAP PDUs contain normalized URIs with their path and query split into
|
||||
* multiple segments. The functions in this module help splitting strings.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Iterator to for tokenizing a URI path or query. This structure must
|
||||
* be initialized with coap_parse_iterator_init(). Call
|
||||
* coap_parse_next() to walk through the tokens.
|
||||
*
|
||||
* @code
|
||||
* unsigned char *token;
|
||||
* coap_parse_iterator_t pi;
|
||||
* coap_parse_iterator_init(uri.path.s, uri.path.length, '/', "?#", 2, &pi);
|
||||
*
|
||||
* while ((token = coap_parse_next(&pi))) {
|
||||
* ... do something with token ...
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
typedef struct {
|
||||
size_t n; /**< number of remaining characters in buffer */
|
||||
unsigned char separator; /**< segment separators */
|
||||
unsigned char *delim; /**< delimiters where to split the string */
|
||||
size_t dlen; /**< length of separator */
|
||||
unsigned char *pos; /**< current position in buffer */
|
||||
size_t segment_length; /**< length of current segment */
|
||||
} coap_parse_iterator_t;
|
||||
|
||||
/**
|
||||
* Initializes the given iterator @p pi.
|
||||
*
|
||||
* @param s The string to tokenize.
|
||||
* @param n The length of @p s.
|
||||
* @param separator The separator character that delimits tokens.
|
||||
* @param delim A set of characters that delimit @s.
|
||||
* @param dlen The length of @p delim.
|
||||
* @param pi The iterator object to initialize.
|
||||
*
|
||||
* @return The initialized iterator object @p pi.
|
||||
*/
|
||||
coap_parse_iterator_t *
|
||||
coap_parse_iterator_init(unsigned char *s, size_t n,
|
||||
unsigned char separator,
|
||||
unsigned char *delim, size_t dlen,
|
||||
coap_parse_iterator_t *pi);
|
||||
|
||||
/**
|
||||
* Updates the iterator @p pi to point to the next token. This
|
||||
* function returns a pointer to that token or @c NULL if no more
|
||||
* tokens exist. The contents of @p pi will be updated. In particular,
|
||||
* @c pi->segment_length specifies the length of the current token, @c
|
||||
* pi->pos points to its beginning.
|
||||
*
|
||||
* @param pi The iterator to update.
|
||||
*
|
||||
* @return The next token or @c NULL if no more tokens exist.
|
||||
*/
|
||||
unsigned char *coap_parse_next(coap_parse_iterator_t *pi);
|
||||
|
||||
/**
|
||||
* Parses a given string into URI components. The identified syntactic
|
||||
* components are stored in the result parameter @p uri. Optional URI
|
||||
@@ -34,69 +127,41 @@ typedef struct {
|
||||
* @param len The actual length of @p str_var
|
||||
* @param uri The coap_uri_t object to store the result.
|
||||
* @return @c 0 on success, or < 0 on error.
|
||||
*
|
||||
* @note The host name part will be converted to lower case by this
|
||||
* function.
|
||||
*/
|
||||
int
|
||||
coap_split_uri(const unsigned char *str_var, size_t len, coap_uri_t *uri);
|
||||
|
||||
/**
|
||||
* Splits the given string into segments. You should call one of the
|
||||
* macros coap_split_path() or coap_split_query() instead.
|
||||
*
|
||||
* @param s The string to split.
|
||||
* @param is_path Set to @c 1 to split path segments, @c 0 for query segments.
|
||||
* @param length The actual length of @p uri.
|
||||
* @param buf Result buffer for parsed segments.
|
||||
* @param buflen Maximum length of @p buf.
|
||||
*
|
||||
* @return The number of segments created or @c -1 on error.
|
||||
*/
|
||||
int coap_split_path_impl(unsigned char *s, size_t length, int is_path,
|
||||
unsigned char *buf, size_t buflen);
|
||||
coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri);
|
||||
|
||||
/**
|
||||
* Splits the given URI path into segments.
|
||||
*
|
||||
* @param Path The path string to split.
|
||||
* @param Length The actual length of @p Path.
|
||||
* @param Buf Result buffer for parsed segments.
|
||||
* @param Buflen Maximum length of @p Buf.
|
||||
* @param s The path string to split.
|
||||
* @param length The actual length of @p s.
|
||||
* @param buf Result buffer for parsed segments.
|
||||
* @param buflen Maximum length of @p buf. Will be set to the actual number
|
||||
* of bytes written into buf on success.
|
||||
*
|
||||
* @return The number of segments created or @c -1 on error.
|
||||
*/
|
||||
#define coap_split_path(Path, Length, Buf, Buflen) \
|
||||
coap_split_path_impl((Path), (Length), 1, (Buf), (Buflen))
|
||||
int coap_split_path(const unsigned char *s, size_t length,
|
||||
unsigned char *buf, size_t *buflen);
|
||||
|
||||
/**
|
||||
* Splits the given URI query into segments.
|
||||
*
|
||||
* @param Query The query string to split.
|
||||
* @param Length The actual length of @p Query.
|
||||
* @param Buf Result buffer for parsed segments.
|
||||
* @param Buflen Maximum length of @p Buf.
|
||||
* @param s The query string to split.
|
||||
* @param length The actual length of @p s.
|
||||
* @param buf Result buffer for parsed segments.
|
||||
* @param buflen Maximum length of @p buf. Will be set to the actual number
|
||||
* of bytes written into buf on success.
|
||||
*
|
||||
* @return The number of segments created or @c -1 on error.
|
||||
*/
|
||||
#define coap_split_query(Query, Length, Buf, Buflen) \
|
||||
coap_split_path_impl((Query), (Length), 0, (Buf), (Buflen))
|
||||
int coap_split_query(const unsigned char *s, size_t length,
|
||||
unsigned char *buf, size_t *buflen);
|
||||
|
||||
/**
|
||||
* Creates a new coap_uri_t object from the specified URI. Returns the new
|
||||
* object or NULL on error. The memory allocated by the new coap_uri_t
|
||||
* must be released using coap_free().
|
||||
* @param uri The URI path to copy.
|
||||
* @para length The length of uri.
|
||||
* @return New URI object or NULL on error.
|
||||
*
|
||||
* @depreated This function has inconvenient storage allocation
|
||||
* characteristics to split URI path and query. Better do that
|
||||
* manually.
|
||||
*/
|
||||
coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length);
|
||||
|
||||
/**
|
||||
* Clones the specified coap_uri_t object. Thie function allocates sufficient
|
||||
* memory to hold the coap_uri_t structure and its contents. The object must
|
||||
* be released with coap_free(). */
|
||||
coap_uri_t *coap_clone_uri(const coap_uri_t *uri);
|
||||
/** @} */
|
||||
|
||||
#endif /* _COAP_URI_H_ */
|
||||
Reference in new issue
Block a user