Skip to content

Commit

Permalink
path_query parsing: Remove need to define scratch buffer
Browse files Browse the repository at this point in the history
Create new options coap_uri_into_optlist(), coap_path_into_optlist() and
coap_query_into_optlist() to be used instead of coap_uri_into_options(),
coap_split_path() and coap_split_query() functions so the requirement
for a scratch buffer is not needed.

Getting the minimum size for a scratch buffer is not straight forward and
potential for unexpected boundary condition errors to occurif too small.

Correct parsing and stripping out of "%2E%2E" ("..") and "%2E" (".")
path segments.  ".." now removes the previous segment (if it exists).

Update documentation and unit testcases.

Update examples to use new options.
  • Loading branch information
mrdeep1 committed Jun 25, 2024
1 parent 63c5077 commit eff1f38
Show file tree
Hide file tree
Showing 20 changed files with 1,012 additions and 264 deletions.
9 changes: 3 additions & 6 deletions examples/coap-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1655,8 +1655,6 @@ main(int argc, char **argv) {
uint8_t *data = NULL;
size_t data_len = 0;
coap_addr_info_t *info_list = NULL;
#define BUFSIZE 100
static unsigned char buf[BUFSIZE];
#ifndef _WIN32
struct sigaction sa;
#endif
Expand Down Expand Up @@ -1930,10 +1928,9 @@ main(int argc, char **argv) {
coap_session_init_token(session, the_token.length, the_token.s);

/* Convert provided uri into CoAP options */
if (coap_uri_into_options(&uri, !uri_host_option && !proxy.host.length ?
&dst : NULL,
&optlist, create_uri_opts,
buf, sizeof(buf)) < 0) {
if (!coap_uri_into_optlist(&uri, !uri_host_option && !proxy.host.length ?
&dst : NULL,
&optlist, create_uri_opts)) {
coap_log_err("Failed to create options for URI\n");
goto failed;
}
Expand Down
24 changes: 11 additions & 13 deletions examples/coap-rd.c
Original file line number Diff line number Diff line change
Expand Up @@ -514,20 +514,18 @@ hnd_post_rd(coap_resource_t *resource COAP_UNUSED,

{
/* split path into segments and add Location-Path options */
unsigned char _b[LOCSIZE];
unsigned char *b = _b;
size_t buflen = sizeof(_b);
int nseg;

nseg = coap_split_path(loc, loc_size, b, &buflen);
while (nseg--) {
coap_add_option(response,
COAP_OPTION_LOCATION_PATH,
coap_opt_length(b),
coap_opt_value(b));
b += coap_opt_size(b);
}
coap_optlist_t *optlist_chain = NULL;

/* add Location-Path */
if (!coap_path_into_optlist(loc, loc_size, COAP_OPTION_LOCATION_PATH,
&optlist_chain))
goto error;
if (!coap_add_optlist_pdu(response, &optlist_chain))
goto error;

coap_delete_optlist(optlist_chain);
}
error:
coap_free(loc);
}

Expand Down
5 changes: 1 addition & 4 deletions examples/coap-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -997,8 +997,6 @@ hnd_proxy_uri(coap_resource_t *resource COAP_UNUSED,
coap_pdu_t *pdu;
coap_optlist_t *optlist = NULL;
coap_opt_t *option;
#define BUFSIZE 100
unsigned char buf[BUFSIZE];
coap_bin_const_t token = coap_pdu_get_token(request);

memset(&uri, 0, sizeof(uri));
Expand Down Expand Up @@ -1105,8 +1103,7 @@ hnd_proxy_uri(coap_resource_t *resource COAP_UNUSED,
proxy_scheme_option = 0;
const coap_address_t *dst = coap_session_get_addr_remote(ongoing);

if (coap_uri_into_options(&uri, dst, &optlist, 1,
buf, sizeof(buf)) < 0) {
if (!coap_uri_into_optlist(&uri, dst, &optlist, 1)) {
coap_log_err("Failed to create options for URI\n");
goto cleanup;
}
Expand Down
18 changes: 10 additions & 8 deletions examples/etsi_iot_01.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,10 @@ hnd_post_test(coap_resource_t *resource COAP_UNUSED,
const uint8_t *data;

#define BUFSIZE 20
int res;
unsigned char _buf[BUFSIZE];
unsigned char *buf = _buf;
size_t buflen = BUFSIZE;
coap_optlist_t *optlist_chain = NULL;

coap_get_data(request, &len, &data);

Expand Down Expand Up @@ -208,18 +208,20 @@ hnd_post_test(coap_resource_t *resource COAP_UNUSED,
coap_add_payload(r, test_payload);

/* add Location-Path */
res = coap_split_path(uri->s, uri->length, buf, &buflen);

while (res--) {
coap_add_option(response, COAP_OPTION_LOCATION_PATH,
coap_opt_length(buf), coap_opt_value(buf));
if (!coap_path_into_optlist(uri->s, uri->length, COAP_OPTION_LOCATION_PATH,
&optlist_chain))
goto error;
if (!coap_add_optlist_pdu(response, &optlist_chain))
goto error;

buf += coap_opt_size(buf);
}
coap_delete_optlist(optlist_chain);

coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
}
return;

error:
coap_delete_optlist(optlist_chain);
}

static void
Expand Down
6 changes: 3 additions & 3 deletions examples/etsi_testcases.sh
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ function TD_COAP_CORE_11 {
# Client sends a confirmable GET request to server's resource
#
# check: sent request contains Type=0(CON) and Code=1(GET), Option
# type=URI-Path (one for each path segment)
# type=Uri-Path (one for each path segment)
#
# check: Server sends response containing Code=69(2.05 content),
# Payload=Content of the requested resource, Content type option
Expand All @@ -365,7 +365,7 @@ function TD_COAP_CORE_12 {
# (e.g. ?first=1&second=2&third=3) to server's resource
#
# check: sent request contains Type=0(CON) and Code=1(GET), Option
# type=URI-Query (More than one query parameter)
# type=Uri-Query (More than one query parameter)
#
# check: Server sends response containing Type=0/2(Con/ACK),
# Code=69(2.05 content), Payload=Content of the requested resource,
Expand Down Expand Up @@ -500,7 +500,7 @@ function TD_COAP_LINK_01 {
# Client retrieves Server's list of resource of a specific Type 1
#
# check: client sends GET request for /.well-known/core resource
# containing URI-Query indicating "rt=Type1"
# containing Uri-Query indicating "rt=Type1"
#
# check: server sends response containing content-type option
# indicating 40 (application/link-format), payload indicating only the
Expand Down
4 changes: 2 additions & 2 deletions examples/lwip/client-coap.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,8 @@ client_coap_init(coap_lwip_input_wait_handler_t input_wait, void *input_arg,
coap_session_max_pdu_size(session));
LWIP_ASSERT("Failed to create PDU", pdu != NULL);

len = coap_uri_into_options(&uri, &dst, &optlist, 1, buf, sizeof(buf));
LWIP_ASSERT("Failed to create options", len == 0);
res = coap_uri_into_optlist(&uri, &dst, &optlist, 1);
LWIP_ASSERT("Failed to create options", res == 1);

/* Add option list (which will be sorted) to the PDU */
if (optlist) {
Expand Down
4 changes: 2 additions & 2 deletions examples/riot/examples_libcoap_client/client-coap.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,8 @@ client_coap_init(int argc, char **argv)
goto fail;
}

len = coap_uri_into_options(&uri, &dst, &optlist, 1, buf, sizeof(buf));
if (len) {
res = coap_uri_into_optlist(&uri, &dst, &optlist, 1);
if (res) {
coap_log_warn("Failed to create options\n");
goto fail;
}
Expand Down
4 changes: 2 additions & 2 deletions examples/riot/tests_pkg_libcoap/libcoap-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ coap_client_init(coap_context_t *ctx)
goto fail;
}

len = coap_uri_into_options(&uri, &dst, &optlist, 1, buf, sizeof(buf));
if (len) {
res = coap_uri_into_optlist(&uri, &dst, &optlist, 1);
if (res != 1) {
coap_log_warn("Failed to create options\n");
goto fail;
}
Expand Down
112 changes: 88 additions & 24 deletions include/coap3/coap_uri.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,20 @@ typedef enum coap_uri_scheme_t {
/**
* Representation of parsed URI. Components may be filled from a string with
* coap_split_uri() or coap_split_proxy_uri() and can be used as input for
* option-creation functions. Alternatively, coap_uri_into_options() can
* option-creation functions. Alternatively, coap_uri_into_optlist() can
* be used to convert coap_uri_t into CoAP options.
*/
typedef struct {
coap_str_const_t host; /**< The host part of the URI */
uint16_t port; /**< The port in host byte order */
coap_str_const_t path; /**< The complete path if present or {0, NULL}.
Needs to be split using coap_split_path()
or coap_uri_into_options(). */
Needs to be split into options using
coap_path_into_optlist() or
coap_uri_into_optlist(). */
coap_str_const_t query; /**< The complete query if present or {0, NULL}.
Needs to be split using coap_split_query()
or coap_uri_into_options(). */
Needs to be split into options using
coap_query_into_options() or
coap_uri_into_optlist(). */
/** The parsed scheme specifier. */
enum coap_uri_scheme_t scheme;
} coap_uri_t;
Expand Down Expand Up @@ -167,20 +169,22 @@ int coap_split_proxy_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri);
/**
* Takes a coap_uri_t and then adds CoAP options into the @p optlist_chain.
* If the port is not the default port and create_port_host_opt is not 0, then
* the Port option is added to the @p optlist_chain.
* the Uri-Port option is added to the @p optlist_chain.
* If the dst defines an address that does not match the host in uri->host and
* is not 0, then the Host option is added to the @p optlist_chain.
* Any path or query are broken down into the individual segment Path or Query
* options and added to the @p optlist_chain.
* is not 0, then the Uri-Host option is added to the @p optlist_chain.
* Any path or query are broken down into the individual segment Uri-Path or
* Uri-Query options and added to the @p optlist_chain.
*
* Note: coap_uri_into_optlist(3) is an alternative function (but has a
* different return value).
*
* @param uri The coap_uri_t object.
* @param dst The destination, or NULL if URI_HOST not to be added.
* @param optlist_chain Where to store the chain of options.
* @param buf Scratch buffer area (needs to be bigger than
* uri->path.length and uri->query.length)
* @param buflen Size of scratch buffer.
* @param create_port_host_opt @c 1 if port/host option to be added
* (if non-default) else @c 0
* @param buf Parameter ignored. Can be NULL.
* @param buflen Parameter ignored.
*
* @return @c 0 on success, or < 0 on error.
*
Expand All @@ -190,44 +194,104 @@ int coap_uri_into_options(const coap_uri_t *uri, const coap_address_t *dst,
int create_port_host_opt,
uint8_t *buf, size_t buflen);

/**
* Takes a coap_uri_t and then adds CoAP options into the @p optlist_chain.
* If the port is not the default port and create_port_host_opt is not 0, then
* the Uri-Port option is added to the @p optlist_chain.
* If the dst defines an address that does not match the host in uri->host and
* is not 0, then the Uri-Host option is added to the @p optlist_chain.
* Any path or query are broken down into the individual segment Uri-Path or
* Uri-Query options and added to the @p optlist_chain.
*
* @param uri The coap_uri_t object.
* @param dst The destination, or NULL if URI_HOST not to be added.
* @param optlist_chain Where to store the chain of options.
* @param create_port_host_opt @c 1 if port/host option to be added
* (if non-default) else @c 0.
*
* @return @c 1 on success, @c 0 if error.
*
*/
int coap_uri_into_optlist(const coap_uri_t *uri, const coap_address_t *dst,
coap_optlist_t **optlist_chain,
int create_port_host_opt);

/**
* Splits the given URI path into segments. Each segment is preceded
* by an option pseudo-header with delta-value 0 and the actual length
* of the respective segment after percent-decoding.
*
* @param s The path string to split.
* @param length The actual length of @p s.
* @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. Will be set to the actual number
* of bytes written into buf on success.
* of bytes written into buf on success. This needs to be
* at least @p length, but 2 bytes should be added for each
* segment to handle large segments.
*
* @return The number of segments created or @c -1 on error.
*/
int coap_split_path(const uint8_t *s,
int coap_split_path(const uint8_t *path,
size_t length,
unsigned char *buf,
size_t *buflen);

/**
* Splits the given URI path into '/' separate segments, and then adds
* the Uri-Path / Location-Path option for each segment to the @p optlist_chain.
*
* Note: any segments that are just '.' or '..' are stripped out.
*
* @param path The path string to split.
* @param length The actual length of @p path.
* @param optnum The CoAP option (COAP_OPTION_URI_PATH or
* COAP_OPTION_LOCATION_PATH)
* @param optlist_chain The chain of optlists to add to. optlist_chain
* parent is to be NULL or a previous set of optlists.
*
* @return @c 1 on success else @c 0 if error.
*/
int coap_path_into_optlist(const uint8_t *path, size_t length,
coap_option_num_t optnum,
coap_optlist_t **optlist_chain);

/**
* Splits the given URI query into segments. Each segment is preceded
* by an option pseudo-header with delta-value 0 and the actual length
* of the respective query term.
* of the respective query segment.
*
* @param s The query string to split.
* @param length The actual length of @p s.
* @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. Will be set to the actual number
* of bytes written into buf on success.
* of bytes written into buf on success. This needs to be
* at least @p length, but 2 bytes should be added for each
* segment to handle large segments.
*
* @return The number of segments created or @c -1 on error.
*
* @bug This function does not reserve additional space for delta > 12.
*/
int coap_split_query(const uint8_t *s,
int coap_split_query(const uint8_t *query,
size_t length,
unsigned char *buf,
size_t *buflen);

/**
* Splits the given URI query into '&' separate segments, and then adds
* the Uri-Query / Location-Query option for each segment to the @p optlist_chain.
*
* @param query The query string to split.
* @param length The actual length of @p query.
* @param optnum The CoAP option (COAP_OPTION_URI_QUERY or
* COAP_OPTION_LOCATION_QUERY)
* @param optlist_chain The chain of optlists to add to. optlist_chain
* parent is to be NULL or a previous set of optlists.
*
* @return @c 1 on success else @c 0 if error.
*/
int coap_query_into_optlist(const uint8_t *query, size_t length,
coap_option_num_t optnum,
coap_optlist_t **optlist_chain);

/**
* Extract query string from request PDU according to escape rules in 6.5.8.
* @param request Request PDU.
Expand All @@ -242,7 +306,7 @@ coap_string_t *coap_get_query(const coap_pdu_t *request);
* Extract uri_path string from request PDU
* @param request Request PDU.
* @return Reconstructed and escaped uri path string part or @c NULL
* if no URI-Path was contained in @p request. The
* if no Uri-Path was contained in @p request. The
* coap_string_t object returned by this function must be
* released with coap_delete_string.
*/
Expand Down
8 changes: 8 additions & 0 deletions include/coap3/coap_uri_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ typedef struct {

extern coap_uri_info_t coap_uri_scheme[COAP_URI_SCHEME_LAST];

/**
* replace any % hex definitions with the actual character.
*
* @param optlist The optlist entry to modify if % hex definitions.
*
*/
void coap_replace_percents(coap_optlist_t *optlist);

/** @} */

#endif /* COAP_URI_INTERNAL_H_ */
3 changes: 3 additions & 0 deletions libcoap-3.map
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ global:
coap_package_build;
coap_package_name;
coap_package_version;
coap_path_into_optlist;
coap_pdu_duplicate;
coap_pdu_get_code;
coap_pdu_get_mid;
Expand All @@ -194,6 +195,7 @@ global:
coap_prng;
coap_prng_init;
coap_q_block_is_supported;
coap_query_into_optlist;
coap_realloc_type;
coap_register_async;
coap_register_event_handler;
Expand Down Expand Up @@ -296,6 +298,7 @@ global:
coap_tls_engine_remove;
coap_tls_is_supported;
coap_uri_into_options;
coap_uri_into_optlist;
coap_write_block_b_opt;
coap_write_block_opt;
coap_ws_is_supported;
Expand Down
Loading

0 comments on commit eff1f38

Please sign in to comment.