From eff1f38f9f662fb3cff0453c2788694962eb81f4 Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Thu, 13 Jun 2024 21:26:32 +0100 Subject: [PATCH] path_query parsing: Remove need to define scratch buffer 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. --- examples/coap-client.c | 9 +- examples/coap-rd.c | 24 +- examples/coap-server.c | 5 +- examples/etsi_iot_01.c | 18 +- examples/etsi_testcases.sh | 6 +- examples/lwip/client-coap.c | 4 +- .../examples_libcoap_client/client-coap.c | 4 +- .../riot/tests_pkg_libcoap/libcoap-test.c | 4 +- include/coap3/coap_uri.h | 112 ++++- include/coap3/coap_uri_internal.h | 8 + libcoap-3.map | 3 + libcoap-3.sym | 3 + man/Makefile.am | 2 + man/coap_block.txt.in | 38 +- man/coap_pdu_setup.txt.in | 105 ++-- man/coap_uri.txt.in | 44 +- src/coap_option.c | 6 +- src/coap_oscore.c | 64 +-- src/coap_uri.c | 342 ++++++++++--- tests/test_uri.c | 475 +++++++++++++++++- 20 files changed, 1012 insertions(+), 264 deletions(-) diff --git a/examples/coap-client.c b/examples/coap-client.c index dd6f8aec72..5c9b919a9e 100644 --- a/examples/coap-client.c +++ b/examples/coap-client.c @@ -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 @@ -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; } diff --git a/examples/coap-rd.c b/examples/coap-rd.c index 7bc768f873..cf18392454 100644 --- a/examples/coap-rd.c +++ b/examples/coap-rd.c @@ -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); } diff --git a/examples/coap-server.c b/examples/coap-server.c index e6abf5f7f7..57665a65fc 100644 --- a/examples/coap-server.c +++ b/examples/coap-server.c @@ -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)); @@ -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; } diff --git a/examples/etsi_iot_01.c b/examples/etsi_iot_01.c index 55bfe7fa2c..1e0d348abf 100644 --- a/examples/etsi_iot_01.c +++ b/examples/etsi_iot_01.c @@ -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); @@ -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 diff --git a/examples/etsi_testcases.sh b/examples/etsi_testcases.sh index 63ba9a53d2..d37989a876 100644 --- a/examples/etsi_testcases.sh +++ b/examples/etsi_testcases.sh @@ -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 @@ -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, @@ -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 diff --git a/examples/lwip/client-coap.c b/examples/lwip/client-coap.c index bd5ef72f4b..55bbd48423 100644 --- a/examples/lwip/client-coap.c +++ b/examples/lwip/client-coap.c @@ -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) { diff --git a/examples/riot/examples_libcoap_client/client-coap.c b/examples/riot/examples_libcoap_client/client-coap.c index 406cf64718..bdf8db7151 100644 --- a/examples/riot/examples_libcoap_client/client-coap.c +++ b/examples/riot/examples_libcoap_client/client-coap.c @@ -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; } diff --git a/examples/riot/tests_pkg_libcoap/libcoap-test.c b/examples/riot/tests_pkg_libcoap/libcoap-test.c index b9f1a59feb..0943535da9 100644 --- a/examples/riot/tests_pkg_libcoap/libcoap-test.c +++ b/examples/riot/tests_pkg_libcoap/libcoap-test.c @@ -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; } diff --git a/include/coap3/coap_uri.h b/include/coap3/coap_uri.h index 285759ab14..99c530f920 100644 --- a/include/coap3/coap_uri.h +++ b/include/coap3/coap_uri.h @@ -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; @@ -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. * @@ -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. @@ -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. */ diff --git a/include/coap3/coap_uri_internal.h b/include/coap3/coap_uri_internal.h index 559ad57532..148c4b0d15 100644 --- a/include/coap3/coap_uri_internal.h +++ b/include/coap3/coap_uri_internal.h @@ -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_ */ diff --git a/libcoap-3.map b/libcoap-3.map index 6bb004e117..dc279b8b6e 100644 --- a/libcoap-3.map +++ b/libcoap-3.map @@ -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; @@ -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; @@ -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; diff --git a/libcoap-3.sym b/libcoap-3.sym index 71df243876..9d858da008 100644 --- a/libcoap-3.sym +++ b/libcoap-3.sym @@ -170,6 +170,7 @@ coap_oscore_is_supported coap_package_build coap_package_name coap_package_version +coap_path_into_optlist coap_pdu_duplicate coap_pdu_get_code coap_pdu_get_mid @@ -192,6 +193,7 @@ coap_print_wellknown coap_prng coap_prng_init coap_q_block_is_supported +coap_query_into_optlist coap_realloc_type coap_register_async coap_register_event_handler @@ -294,6 +296,7 @@ coap_tls_engine_configure 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 diff --git a/man/Makefile.am b/man/Makefile.am index 6025929680..b56bb1ff0f 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -172,7 +172,9 @@ install-man: install-man3 install-man5 install-man7 @echo ".so man3/coap_pdu_setup.3" > coap_add_data.3 @echo ".so man3/coap_pdu_setup.3" > coap_add_data_blocked_response.3 @echo ".so man3/coap_pdu_setup.3" > coap_send.3 + @echo ".so man3/coap_pdu_setup.3" > coap_path_into_optlist.3 @echo ".so man3/coap_pdu_setup.3" > coap_split_path.3 + @echo ".so man3/coap_pdu_setup.3" > coap_query_into_optlist.3 @echo ".so man3/coap_pdu_setup.3" > coap_split_query.3 @echo ".so man3/coap_pdu_setup.3" > coap_pdu_set_mid.3 @echo ".so man3/coap_pdu_setup.3" > coap_pdu_set_code.3 diff --git a/man/coap_block.txt.in b/man/coap_block.txt.in index 089a31dbc8..bec6170e0a 100644 --- a/man/coap_block.txt.in +++ b/man/coap_block.txt.in @@ -351,14 +351,12 @@ EXAMPLES static int build_send_pdu(coap_context_t *context, coap_session_t *session, - uint8_t msgtype, uint8_t request_code, const char *uri, + uint8_t msgtype, uint8_t request_code, const char *path, const char *query, unsigned char *data, size_t length, int observe) { coap_pdu_t *pdu; - uint8_t buf[1024]; + uint8_t buf[8]; size_t buflen; - uint8_t *sbuf = buf; - int res; coap_optlist_t *optlist_chain = NULL; /* Remove (void) definition if variable is used */ (void)context; @@ -379,30 +377,18 @@ build_send_pdu(coap_context_t *context, coap_session_t *session, goto error; } - if (uri) { - /* Add in the URI options */ - buflen = sizeof(buf); - res = coap_split_path((const uint8_t *)uri, strlen(uri), sbuf, &buflen); - while (res--) { - if (!coap_insert_optlist(&optlist_chain, - coap_new_optlist(COAP_OPTION_URI_PATH, - coap_opt_length(sbuf), coap_opt_value(sbuf)))) - goto error; - sbuf += coap_opt_size(sbuf); - } + if (path) { + /* Add in the Uri-Path options */ + if (!coap_path_into_optlist((const uint8_t *)path, strlen(path), + COAP_OPTION_URI_PATH, &optlist_chain)) + goto error; } if (query) { - /* Add in the QUERY options */ - buflen = sizeof(buf); - res = coap_split_query((const uint8_t *)query, strlen(query), sbuf, &buflen); - while (res--) { - if (!coap_insert_optlist(&optlist_chain, - coap_new_optlist(COAP_OPTION_URI_QUERY, - coap_opt_length(sbuf), coap_opt_value(sbuf)))) - goto error; - sbuf += coap_opt_size(sbuf); - } + /* Add in the Uri-Query options */ + if (!coap_query_into_optlist((const uint8_t *)query, strlen(query), + COAP_OPTION_URI_QUERY, &optlist_chain)) + goto error; } if (request_code == COAP_REQUEST_GET && observe) { @@ -429,12 +415,14 @@ build_send_pdu(coap_context_t *context, coap_session_t *session, if (coap_send(session, pdu) == COAP_INVALID_MID) goto error; + coap_delete_optlist(optlist_chain); return 1; error: if (pdu) coap_delete_pdu(pdu); + coap_delete_optlist(optlist_chain); return 0; } diff --git a/man/coap_pdu_setup.txt.in b/man/coap_pdu_setup.txt.in index 481af390aa..1aa38a88df 100644 --- a/man/coap_pdu_setup.txt.in +++ b/man/coap_pdu_setup.txt.in @@ -27,7 +27,9 @@ coap_add_option, coap_add_data, coap_add_data_blocked_response, coap_send, +coap_path_into_optlist, coap_split_path, +coap_query_into_optlist, coap_split_query, coap_pdu_set_mid, coap_pdu_set_code, @@ -82,9 +84,15 @@ const uint8_t *_data_);* *coap_mid_t coap_send(coap_session_t *_session_, coap_pdu_t *_pdu_);* +*int coap_path_into_optlist(const uint8_t *_path_, size_t _length_, +coap_option_num_t _optnum_, coap_optlist_t **_optlist_chain_);* + *int coap_split_path(const uint8_t *_path_, size_t _length_, uint8_t *_buffer_, size_t *_buflen_);* +*int coap_query_into_optlist(const uint8_t *_path_, size_t _length_, +coap_option_num_t _optnum_, coap_optlist_t **_optlist_chain_);* + *int coap_split_query(const uint8_t *_query_, size_t _length_, uint8_t *_buffer_, size_t *_buflen_);* @@ -411,25 +419,57 @@ The *coap_encode_var_safe8*() function encodes 8 byte _value_ into _buffer_ which has a size of _size_ in bytes. Normally, the _buffer_ size should be at least 8 bytes unless you definitely know less space is required. +*Function: coap_path_into_optlist()* + +The *coap_path_into_optlist*() function splits up _path_ of length _length_ +into '/' separated segments and then appends the _optnum_ option for each +segment to _optlist_chain_. _optlist_chain_ can contain previous optlist +entries or the parent has to be initialized to NULL. Any segment that is +just "." is not appended. Any segment that is just ".." causes the previous +segment (if just added by *coap_path_into_optlist*()) to be removed from +_optlist_chain_. Any % definitions are replaced by the actual byte. +_optnum_ should be one of COAP_OPTION_URI_PATH or COAP_OPTION_LOCATION_PATH. + *Function: coap_split_path()* -The *coap_split_path*() function splits up _path_ of length _length_ and -places the result in _buffer_ which has a size of _buflen_ with the nul -character separating each path component. _buflen_ needs -to be preset with the size of _buffer_ before the function call, and then -_buflen_ is updated with the actual size of _buffer_ used. The return -value indicates the number of components that individual COAP_OPTION_URI_PATH -options need to be created for. +The *coap_split_path*() function splits up _path_ of length _length_ into +'/' separated segments and places the result in _buffer_ which has a size +of _buflen_ with a dummy option separating each path segment. +_buflen_ needs to be preset with the size of _buffer_ before the function call, +and then _buflen_ is updated with the actual size of _buffer_ used. +_buflen_ needs to be at least _length_ with an extra 2 bytes per segment to +handle long segments. +Any segment that is just "." is not appended. Any segment that is just ".." +causes the previous segment (if any) to be removed from _buffer_. +Any % definitions are replaced by the actual byte. +The return value indicates the number of components that individual +COAP_OPTION_URI_PATH (or COAP_OPTION_LOCATION_PATH) options need to be +created for. + +Note: For simplicity, use *coap_path_into_optlist*() instead. + +*Function: coap_query_into_optlist()* + +The *coap_query_into_optlist*() function splits up _query_ of length _length_ +into '&' separated segments and then appends the _optnum_ option for each +segment to _optlist_chain_. _optlist_chain_ can contain previous optlist +entries or the parent has to be initialized to NULL. _optnum_ should be one of +COAP_OPTION_URI_QUERY or COAP_OPTION_LOCATION_QUERY. *Function: coap_split_query()* -The *coap_split_query*() function splits up _query_ of length _length_ and -places the result in _buffer_ which has a size of _buflen_ with the nul -character separating each path component. _buflen_ needs +The *coap_split_query*() function splits up _query_ of length _length_ into +'&' separated segments and +places the result in _buffer_ which has a size of _buflen_ with a dummy +option separating each query segment. _buflen_ needs to be preset with the size of _buffer_ before the function call, and then -_buflen_ is updated with the actual size of _buffer_ used. The return +_buflen_ is updated with the actual size of _buffer_ used. _buflen_ needs +to be at least _length_ with an extra 2 bytes per segment to handle long +segments. The return value indicates the number of components that individual COAP_OPTION_URI_QUERY -options need to be created for. +(or COAP_OPTION_LOCATION_QUERY) options need to be created for. + +Note: For simplicity, use *coap_query_into_optlist*() instead. PDU OPTIONS - LIBCOAP HANDLING ------------------------------ @@ -554,6 +594,9 @@ failure. *coap_send*() returns the CoAP message ID on success or COAP_INVALID_MID on failure. +*coap_path_into_optlist*() and *coap_query_into_optlist*() return 1 on +success or 0 on failure. + *coap_split_path*() and *coap_split_query*() return the number of components found. @@ -569,14 +612,12 @@ EXAMPLES static int build_send_pdu(coap_context_t *context, coap_session_t *session, - uint8_t msgtype, uint8_t request_code, const char *uri, + uint8_t msgtype, uint8_t request_code, const char *path, const char *query, unsigned char *data, size_t length, int observe) { coap_pdu_t *pdu; - uint8_t buf[1024]; + uint8_t buf[8]; size_t buflen; - uint8_t *sbuf = buf; - int res; coap_optlist_t *optlist_chain = NULL; /* Remove (void) definition if variable is used */ (void)context; @@ -597,32 +638,18 @@ build_send_pdu(coap_context_t *context, coap_session_t *session, goto error; } - if (uri) { - /* Add in the URI options */ - buflen = sizeof(buf); - res = coap_split_path((const uint8_t *)uri, strlen(uri), sbuf, &buflen); - while (res--) { - if (!coap_insert_optlist(&optlist_chain, - coap_new_optlist(COAP_OPTION_URI_PATH, - coap_opt_length(sbuf), - coap_opt_value(sbuf)))) - goto error; - sbuf += coap_opt_size(sbuf); - } + if (path) { + /* Add in the Uri-Path options */ + if (!coap_path_into_optlist((const uint8_t *)path, strlen(path), + COAP_OPTION_URI_PATH, &optlist_chain)) + goto error; } if (query) { - /* Add in the QUERY options */ - buflen = sizeof(buf); - res = coap_split_query((const uint8_t *)query, strlen(query), sbuf, &buflen); - while (res--) { - if (!coap_insert_optlist(&optlist_chain, - coap_new_optlist(COAP_OPTION_URI_QUERY, - coap_opt_length(sbuf), - coap_opt_value(sbuf)))) - goto error; - sbuf += coap_opt_size(sbuf); - } + /* Add in the Uri-Query options */ + if (!coap_query_into_optlist((const uint8_t *)query, strlen(query), + COAP_OPTION_URI_QUERY, &optlist_chain)) + goto error; } if (request_code == COAP_REQUEST_GET && observe) { diff --git a/man/coap_uri.txt.in b/man/coap_uri.txt.in index c4d397a084..1696c992bc 100644 --- a/man/coap_uri.txt.in +++ b/man/coap_uri.txt.in @@ -16,6 +16,7 @@ coap_split_proxy_uri, coap_new_uri, coap_clone_uri, coap_delete_uri, +coap_uri_into_optlist, coap_uri_into_options - Work with CoAP URIs @@ -35,6 +36,10 @@ coap_uri_t *_uri_);* *void coap_delete_uri(coap_uri_t *_uri_);* +*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_);* + *int coap_uri_into_options(const coap_uri_t *_uri_, const coap_address_t *_dst_, coap_optlist_t **_optlist_chain_, int _create_port_host_opt_, uint8_t *_buf_, size_t _buflen_);* @@ -72,11 +77,11 @@ 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 using coap_path_into_optlist(3) + 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 using coap_query_into_optlist(3) + or coap_uri_into_optlist(). */ enum coap_uri_scheme_t scheme; /* The parsed scheme specifier. */ } coap_uri_t; ---- @@ -115,9 +120,9 @@ The returned coap_uri_t structure needs to be freed off using The *coap_delete_uri*() function frees off a previously created _uri_ coap_uri_t structure. -*Function: coap_uri_into_options()* +*Function: coap_uri_into_optlist()* -The *coap_uri_into_options*() function takes the _uri_ structure and then takes +The *coap_uri_into_optlist*() function takes the _uri_ structure and then takes CoAP options derived from this information and adds them to _optlist_chain_. The initial _optlist_chain_ entry should be set to NULL before this function is called (unless *coap_insert_optlist*(3) has been previously @@ -128,26 +133,30 @@ option is added in if the _uri_ host definition is not an exact match with the ascii readable version of _dst. If the port is not the default port and _create_port_host_opt_ is not 0, then -the Port option is added to _optlist_chain_. +the Uri-Port option is added to _optlist_chain_. -If there is a path, then this is broken down into individual Path options for -each segment which are then added to _optlist_chain_. +If there is a path, then this is broken down into individual Uri-Path options +for each segment which are then added to _optlist_chain_. -Likewise, if -there is a query, individual Query options for each segment are then added to -_optlist_chain_. - -_buf_ provides a scratch buffer to use, of size _buflen_ bytes. _buf_ needs -to be as big as the path or query lengths. +Likewise, if there is a query, individual Uri-Query options for each segment are +then added to _optlist_chain_. *NOTE:* It is the responsibility of the application to free off the entries added to _optlist_chain_ using *coap_delete_optlist*(3). +*Function: coap_uri_into_options()* + +The *coap_uri_into_options*() function has the same functionality as +*coap_uri_into_optlist*() except that _buf_ and _buflen_ are ignored, but the +return values are different. + RETURN VALUES ------------- *coap_split_uri*(), *coap_split_proxy_uri*(), and *coap_uri_into_options*() return 0 on success, else < 0 on failure. +*coap_uri_into_optlist*() returns 1 on success, 0 on failure. + *coap_new_uri*() and *coap_clone_uri*() return a newly allocated coap_uri_t structure or NULL on failure. @@ -171,8 +180,6 @@ parse_and_send_uri(coap_session_t *session, const char *do_uri) { const coap_address_t *dst = coap_session_get_addr_remote(session); int res; coap_mid_t mid; -#define BUFSIZE 100 - unsigned char buf[BUFSIZE]; /* Parse the URI */ res = coap_split_uri((const uint8_t *)do_uri, strlen(do_uri), &uri); @@ -222,8 +229,7 @@ parse_and_send_uri(coap_session_t *session, const char *do_uri) { return 0; /* Create all the necessary options from the URI */ - res = coap_uri_into_options(&uri, dst, &optlist, 1, buf, sizeof(buf)); - if (res != 0) + if (!coap_uri_into_optlist(&uri, dst, &optlist, 1)) return 0; /* Add option list (which will get sorted) to the PDU */ diff --git a/src/coap_option.c b/src/coap_option.c index aa4cdf3ee0..4b06be98a9 100644 --- a/src/coap_option.c +++ b/src/coap_option.c @@ -560,11 +560,11 @@ coap_add_optlist_pdu(coap_pdu_t *pdu, coap_optlist_t **options) { LL_SORT((*options), order_opts); LL_FOREACH((*options), opt) { - coap_add_option_internal(pdu, opt->number, opt->length, opt->data); + if (!coap_add_option_internal(pdu, opt->number, opt->length, opt->data)) + return 0; } - return 1; } - return 0; + return 1; } int diff --git a/src/coap_oscore.c b/src/coap_oscore.c index dc66010775..b818e1974d 100644 --- a/src/coap_oscore.c +++ b/src/coap_oscore.c @@ -205,7 +205,7 @@ coap_rebuild_pdu_for_proxy(coap_pdu_t *pdu) { coap_opt_iterator_t opt_iter; coap_opt_t *option; uint8_t option_value_buffer[15]; - uint8_t *keep_proxy_uri = NULL; + coap_optlist_t *optlist_chain = NULL; if ((option = coap_check_option(pdu, COAP_OPTION_PROXY_URI, &opt_iter)) == NULL) @@ -213,12 +213,8 @@ coap_rebuild_pdu_for_proxy(coap_pdu_t *pdu) { /* Need to break down into the component parts, but keep data safe */ memset(&uri, 0, sizeof(uri)); - keep_proxy_uri = coap_malloc_type(COAP_STRING, coap_opt_length(option)); - if (keep_proxy_uri == NULL) - goto error; - memcpy(keep_proxy_uri, coap_opt_value(option), coap_opt_length(option)); - if (coap_split_proxy_uri(keep_proxy_uri, + if (coap_split_proxy_uri(coap_opt_value(option), coap_opt_length(option), &uri) < 0 || uri.scheme >= COAP_URI_SCHEME_LAST) { coap_log_warn("Proxy URI '%.*s' not decodable\n", @@ -243,59 +239,31 @@ coap_rebuild_pdu_for_proxy(coap_pdu_t *pdu) { option_value_buffer)) goto error; if (uri.path.length) { - uint8_t *buf; - uint8_t *kbuf; - size_t buflen = uri.path.length + 1; - int res; - - kbuf = buf = coap_malloc_type(COAP_STRING, uri.path.length + 1); - if (buf) { - res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen); - while (res--) { - if (!coap_insert_option(pdu, - COAP_OPTION_URI_PATH, - coap_opt_length(buf), - coap_opt_value(buf))) { - coap_free_type(COAP_STRING, buf); - goto error; - } - buf += coap_opt_size(buf); - } - } - coap_free_type(COAP_STRING, kbuf); + /* Add in the Uri-Path options */ + if (!coap_path_into_optlist(uri.path.s, uri.path.length, COAP_OPTION_URI_PATH, + &optlist_chain)) + goto error; } if (uri.query.length) { - uint8_t *buf; - size_t buflen = uri.query.length + 1; - int res; - - buf = coap_malloc_type(COAP_STRING, uri.query.length + 1); - if (buf) { - res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen); - while (res--) { - if (!coap_insert_option(pdu, - COAP_OPTION_URI_QUERY, - coap_opt_length(buf), - coap_opt_value(buf))) { - coap_free_type(COAP_STRING, buf); - goto error; - } - - buf += coap_opt_size(buf); - } - coap_free_type(COAP_STRING, buf); - } + /* Add in the Uri-Query options */ + if (!coap_query_into_optlist(uri.query.s, uri.query.length, COAP_OPTION_URI_QUERY, + &optlist_chain)) + goto error; } + if (!coap_add_optlist_pdu(pdu, &optlist_chain)) + goto error; + if (!coap_insert_option(pdu, COAP_OPTION_PROXY_SCHEME, strlen(coap_uri_scheme[uri.scheme].name), (const uint8_t *)coap_uri_scheme[uri.scheme].name)) goto error; - coap_free_type(COAP_STRING, keep_proxy_uri); + + coap_delete_optlist(optlist_chain); return 1; error: - coap_free_type(COAP_STRING, keep_proxy_uri); + coap_delete_optlist(optlist_chain); return 0; } diff --git a/src/coap_uri.c b/src/coap_uri.c index db3cea7c70..a196821ff1 100644 --- a/src/coap_uri.c +++ b/src/coap_uri.c @@ -277,14 +277,27 @@ coap_split_proxy_uri(const uint8_t *str_var, size_t len, coap_uri_t *uri) { return coap_split_uri_sub(str_var, len, uri, COAP_URI_CHECK_PROXY); } +static void +coap_replace_upper_lower(coap_optlist_t *optlist) { + size_t i; + + for (i = 0; i < optlist->length; i++) { + if (optlist->data[i] >= 'A' && optlist->data[i] <= 'Z') { + optlist->data[i] += 'a' - 'A'; + } + } +} + int coap_uri_into_options(const coap_uri_t *uri, const coap_address_t *dst, coap_optlist_t **optlist_chain, int create_port_host_opt, - uint8_t *_buf, size_t _buflen) { - int res; - unsigned char *buf = _buf; - size_t buflen = _buflen; + uint8_t *_buf COAP_UNUSED, size_t buflen COAP_UNUSED) { + return !coap_uri_into_optlist(uri, dst, optlist_chain, create_port_host_opt) ? -1 : 0; +} +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) { if (create_port_host_opt && !coap_host_is_unix_domain(&uri->host)) { int add_option = 0; @@ -294,8 +307,9 @@ coap_uri_into_options(const coap_uri_t *uri, const coap_address_t *dst, #else /* WITH_LWIP || WITH_CONTIKI */ char addr[40]; #endif /* WITH_LWIP || WITH_CONTIKI */ + coap_optlist_t *optlist; - /* Add in UriHost if not match (need to strip off &iface) */ + /* Add in Uri-Host if not match (need to strip off %iface) */ size_t uri_host_len = uri->host.length; const uint8_t *cp = uri->host.s; @@ -312,10 +326,15 @@ coap_uri_into_options(const coap_uri_t *uri, const coap_address_t *dst, (strlen(addr) != uri_host_len || memcmp(addr, uri->host.s, uri_host_len) != 0)) { /* add Uri-Host */ - coap_insert_optlist(optlist_chain, - coap_new_optlist(COAP_OPTION_URI_HOST, - uri->host.length, - uri->host.s)); + optlist = coap_new_optlist(COAP_OPTION_URI_HOST, uri->host.length, + uri->host.s); + if (!coap_host_is_unix_domain(&uri->host)) { + coap_replace_percents(optlist); + coap_replace_upper_lower(optlist); + } + if (!coap_insert_optlist(optlist_chain, optlist)) { + return 0; + } } } /* Add in UriPort if not default */ @@ -336,52 +355,29 @@ coap_uri_into_options(const coap_uri_t *uri, const coap_address_t *dst, add_option = 1; break; } - if (add_option) + if (add_option) { + u_char tbuf[4]; + coap_insert_optlist(optlist_chain, coap_new_optlist(COAP_OPTION_URI_PORT, - coap_encode_var_safe(buf, 4, + coap_encode_var_safe(tbuf, 4, (uri->port & 0xffff)), - buf)); + tbuf)); + } } if (uri->path.length) { - if (uri->path.length > buflen) - coap_log_warn("URI path will be truncated (max buffer %zu)\n", - buflen); - res = coap_split_path(uri->path.s, uri->path.length, buf, &buflen); - if (res < 0) - return -1; - - while (res--) { - coap_insert_optlist(optlist_chain, - coap_new_optlist(COAP_OPTION_URI_PATH, - coap_opt_length(buf), - coap_opt_value(buf))); - - buf += coap_opt_size(buf); - } + if (!coap_path_into_optlist(uri->path.s, uri->path.length, COAP_OPTION_URI_PATH, + optlist_chain)) + return 0; } if (uri->query.length) { - buflen = _buflen; - buf = _buf; - if (uri->query.length > buflen) - coap_log_warn("URI query will be truncated (max buffer %zu)\n", - buflen); - res = coap_split_query(uri->query.s, uri->query.length, buf, &buflen); - if (res < 0) - return -1; - - while (res--) { - coap_insert_optlist(optlist_chain, - coap_new_optlist(COAP_OPTION_URI_QUERY, - coap_opt_length(buf), - coap_opt_value(buf))); - - buf += coap_opt_size(buf); - } + if (!coap_query_into_optlist(uri->query.s, uri->query.length, COAP_OPTION_URI_QUERY, + optlist_chain)) + return 0; } - return 0; + return 1; } int @@ -532,35 +528,110 @@ typedef void (*segment_handler_t)(const uint8_t *, size_t, void *); /** * Checks if path segment @p s consists of one or two dots. + * + * returns 1 if . , 2 if .. else 0. */ -COAP_STATIC_INLINE int +static int dots(const uint8_t *s, size_t len) { - return len && *s == '.' && (len == 1 || (len == 2 && *(s+1) == '.')); + uint8_t p; + + if (!len) + return 0; + + p = *s; + + /* Check 'first' char */ + if (p == '%' && len >=3) { + if (s[1] == '2' && (s[2] == 'E' || s[2] == 'e')) { + s += 2; + len -= 2; + } + p = '.'; + } + if (p != '.') + return 0; + if (len == 1) + return 1; + + /* Check 'second' char, first is '.' */ + s++; + len--; + assert(len); + p = *s; + if (p == '%' && len >=3) { + if (s[1] == '2' && (s[2] == 'E' || s[2] == 'e')) { + len -= 2; + } + p = '.'; + } + if (p != '.') + return 0; + if (len == 1) + return 2; + + return 0; +} + +struct cnt_str { + coap_string_t base_buf; + coap_string_t buf; + int n; +}; + +static void +backup_segment(void *data) { + struct cnt_str *state = (struct cnt_str *)data; + int i; + uint8_t *buf; + + if (state->n == 0) + return; + + state->n--; + buf = state->base_buf.s; + for (i = 0; i < state->n; i++) { + buf += coap_opt_size(buf); + } + state->buf.s = buf; + state->buf.length = state->base_buf.length - (buf - state->base_buf.s); } /** * Splits the given string into segments. You should call one of the - * macros coap_split_path() or coap_split_query() instead. + * functions coap_split_path() or coap_split_query() instead. * - * @param s The URI string to be tokenized. - * @param length The length of @p s. + * @param path The URI path string to be tokenized. + * @param len The length of @p path. * @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. */ static size_t -coap_split_path_impl(const uint8_t *s, size_t length, +coap_split_path_impl(const uint8_t *path, size_t len, segment_handler_t h, void *data) { - const uint8_t *p, *q; + size_t length = len; + int num_dots; - p = q = s; + p = q = path; while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *q)) { - if (*q == '/') { /* start new segment */ - - if (!dots(p, q - p)) { + if (*q == '/') { + /* start new segment */ + num_dots = dots(p, q - p); + switch (num_dots) { + case 1: + /* drop segment */ + break; + case 2: + /* backup segment */ + backup_segment(data); + break; + case 0: + default: + /* add segment */ h(p, q - p, data); + break; } p = q + 1; @@ -571,18 +642,25 @@ coap_split_path_impl(const uint8_t *s, size_t length, } /* write last segment */ - if (!dots(p, q - p)) { + num_dots = dots(p, q - p); + switch (num_dots) { + case 1: + /* drop segment */ + break; + case 2: + /* backup segment */ + backup_segment(data); + break; + case 0: + default: + /* add segment */ h(p, q - p, data); + break; } - return q - s; + return q - path; } -struct cnt_str { - coap_string_t buf; - int n; -}; - static void write_option(const uint8_t *s, size_t len, void *data) { struct cnt_str *state = (struct cnt_str *)data; @@ -601,7 +679,7 @@ write_option(const uint8_t *s, size_t len, void *data) { int coap_split_path(const uint8_t *s, size_t length, unsigned char *buf, size_t *buflen) { - struct cnt_str tmp = { { *buflen, buf }, 0 }; + struct cnt_str tmp = { { *buflen, buf }, { *buflen, buf }, 0 }; coap_split_path_impl(s, length, write_option, &tmp); @@ -610,10 +688,116 @@ coap_split_path(const uint8_t *s, size_t length, return tmp.n; } +void +coap_replace_percents(coap_optlist_t *optlist) { + size_t i; + size_t o = 0; + + for (i = 0; i < optlist->length; i++) { + if (optlist->data[i] == '%' && optlist->length - i >= 3) { + optlist->data[o] = (hexchar_to_dec(optlist->data[i+1]) << 4) + + hexchar_to_dec(optlist->data[i+2]); + i+= 2; + } else if (o != i) { + optlist->data[o] = optlist->data[i]; + } + o++; + } + optlist->length = o; +} + +static void +backup_optlist(coap_optlist_t **optlist_begin) { + coap_optlist_t *last = NULL; + coap_optlist_t *cur = *optlist_begin; + + if (!cur) + return; + + while (cur) { + if (!cur->next) + break; + last = cur; + cur = cur->next; + } + coap_delete_optlist(cur); + if (last) { + last->next = NULL; + } else { + *optlist_begin = NULL; + } +} + +int +coap_path_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum, + coap_optlist_t **optlist_chain) { + const uint8_t *p = s; + coap_optlist_t *optlist; + int num_dots; + coap_optlist_t **optlist_start; + + if (*optlist_chain) { + /* Something previously in optlist_chain. Need to make that the start */ + optlist_start = &((*optlist_chain)->next); + } else { + optlist_start = optlist_chain; + } + + while (length > 0 && !strnchr((const uint8_t *)"?#", 2, *s)) { + if (*s == '/') { /* start of new path element */ + /* start new segment */ + num_dots = dots(p, s - p); + switch (num_dots) { + case 1: + /* drop segment */ + break; + case 2: + /* backup segment */ + backup_optlist(optlist_start); + break; + case 0: + default: + /* add segment */ + optlist = coap_new_optlist(optnum, s - p, p); + coap_replace_percents(optlist); + if (!coap_insert_optlist(optlist_chain, optlist)) { + return 0; + } + break; + } + p = s + 1; + } + s++; + length--; + + } + /* add last path element */ + num_dots = dots(p, s - p); + switch (num_dots) { + case 1: + /* drop segment */ + break; + case 2: + /* backup segment */ + backup_optlist(optlist_start); + break; + case 0: + default: + /* add segment */ + optlist = coap_new_optlist(optnum, s - p, p); + coap_replace_percents(optlist); + if (!coap_insert_optlist(optlist_chain, optlist)) { + return 0; + } + break; + } + return 1; +} + int coap_split_query(const uint8_t *s, size_t length, unsigned char *buf, size_t *buflen) { - struct cnt_str tmp = { { *buflen, buf }, 0 }; + struct cnt_str tmp = { { *buflen, buf }, { *buflen, buf }, 0 }; const uint8_t *p; p = s; @@ -634,6 +818,34 @@ coap_split_query(const uint8_t *s, size_t length, return tmp.n; } +int +coap_query_into_optlist(const uint8_t *s, size_t length, coap_option_num_t optnum, + coap_optlist_t **optlist_chain) { + const uint8_t *p = s; + coap_optlist_t *optlist; + + while (length > 0 && *s != '#') { + if (*s == '&') { /* start of new query element */ + /* add previous query element */ + optlist = coap_new_optlist(optnum, s - p, p); + coap_replace_percents(optlist); + if (!coap_insert_optlist(optlist_chain, optlist)) { + return 0; + } + p = s + 1; + } + s++; + length--; + } + /* add last query element */ + optlist = coap_new_optlist(optnum, s - p, p); + coap_replace_percents(optlist); + if (!coap_insert_optlist(optlist_chain, optlist)) { + return 0; + } + return 1; +} + #define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t)) coap_uri_t * diff --git a/tests/test_uri.c b/tests/test_uri.c index 9041bcc60a..d2dc916d27 100644 --- a/tests/test_uri.c +++ b/tests/test_uri.c @@ -145,6 +145,8 @@ t_parse_uri7(void) { coap_uri_t uri; unsigned char buf[40]; size_t buflen = sizeof(buf); + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; /* The list of path segments to check against. Each segment is preceded by a dummy option indicating that holds the (dummy) @@ -174,6 +176,18 @@ t_parse_uri7(void) { CU_ASSERT(result == 4); CU_ASSERT(buflen == sizeof(checkbuf)); CU_ASSERT_NSTRING_EQUAL(buf, checkbuf, buflen); + + result = coap_path_into_optlist(uri.path.s, uri.path.length, 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(checkbuf)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, checkbuf, pdu->used_size); + coap_delete_pdu(pdu); } else { CU_FAIL("uri parser error"); } @@ -244,6 +258,8 @@ t_parse_uri11(void) { coap_uri_t uri; unsigned char buf[40]; size_t buflen = sizeof(buf); + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; /* The list of path segments to check against. Each segment is preceded by a dummy option indicating that holds the (dummy) @@ -273,6 +289,18 @@ t_parse_uri11(void) { CU_ASSERT(result == 1); CU_ASSERT(buflen == sizeof(checkbuf)); CU_ASSERT_NSTRING_EQUAL(buf, checkbuf, buflen); + + result = coap_path_into_optlist(uri.path.s, uri.path.length, 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(checkbuf)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, checkbuf, pdu->used_size); + coap_delete_pdu(pdu); } else { CU_FAIL("uri parser error"); } @@ -285,6 +313,8 @@ t_parse_uri12(void) { coap_uri_t uri; unsigned char buf[40]; size_t buflen = sizeof(buf); + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; /* The list of path segments to check against. Each segment is preceded by a dummy option indicating that holds the (dummy) @@ -311,12 +341,36 @@ t_parse_uri12(void) { CU_ASSERT(buflen == sizeof(uricheckbuf)); CU_ASSERT_NSTRING_EQUAL(buf, uricheckbuf, buflen); + result = coap_path_into_optlist(uri.path.s, uri.path.length, 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(uricheckbuf)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, uricheckbuf, pdu->used_size); + coap_delete_pdu(pdu); + /* check query segments */ buflen = sizeof(buf); result = coap_split_query(uri.query.s, uri.query.length, buf, &buflen); CU_ASSERT(result == 2); CU_ASSERT(buflen == sizeof(querycheckbuf)); CU_ASSERT_NSTRING_EQUAL(buf, querycheckbuf, buflen); + optlist_chain = NULL; + result = coap_query_into_optlist(uri.query.s, uri.query.length, 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(querycheckbuf)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, querycheckbuf, pdu->used_size); + coap_delete_pdu(pdu); } else { CU_FAIL("uri parser error"); } @@ -357,6 +411,8 @@ t_parse_uri14(void) { char teststr[] = "longerthan13lessthan270=0123456789012345678901234567890123456789"; int result; + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; /* buf is large enough to hold sizeof(teststr) - 1 bytes content and * 2 bytes for the option header. */ @@ -370,6 +426,19 @@ t_parse_uri14(void) { CU_ASSERT(buf[1] == strlen(teststr) - 13); CU_ASSERT_NSTRING_EQUAL(buf+2, teststr, strlen(teststr)); + + result = coap_query_into_optlist((unsigned char *)teststr, + strlen(teststr), 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->token[0] == 0x0d); + CU_ASSERT(pdu->token[1] == strlen(teststr) - 13); + coap_delete_pdu(pdu); } else { CU_FAIL("uri parser error"); } @@ -416,6 +485,8 @@ t_parse_uri17(void) { "01234567890123456789012345678901234567890123456789" "01234567890123456789012345678901234567890123456789"; int result; + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; /* buf is large enough to hold sizeof(teststr) - 1 bytes content and * 3 bytes for the option header. */ @@ -430,6 +501,19 @@ t_parse_uri17(void) { CU_ASSERT(buf[2] == ((strlen(teststr) - 269) & 0xff)); CU_ASSERT_NSTRING_EQUAL(buf+3, teststr, strlen(teststr)); + result = coap_query_into_optlist((unsigned char *)teststr, strlen(teststr), + 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 300); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->token[0] == 0x0e); + CU_ASSERT(pdu->token[1] == (((strlen(teststr) - 269) >> 8) & 0xff)); + CU_ASSERT(pdu->token[2] == ((strlen(teststr) - 269) & 0xff)); + coap_delete_pdu(pdu); } else { CU_FAIL("uri parser error"); } @@ -569,17 +653,397 @@ t_parse_uri23(void) { */ static void t_parse_uri24(void) { - /* coap://\206cap:// */ + /* coap://\206coap:// */ uint8_t teststr[] = { 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x86, 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f, 0x2f }; int result; unsigned char buf[40]; size_t buflen = sizeof(buf); + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; result = coap_split_path(teststr, sizeof(teststr), buf, &buflen); CU_ASSERT(result == 5); CU_ASSERT(buflen == 16); + + result = coap_path_into_optlist(teststr, sizeof(teststr), 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == 16); + coap_delete_pdu(pdu); +} + +static void +t_parse_uri25(void) { + char teststr[] = "coap://198.51.100.1:61616//%2E//%2E%2E/./../a?%2e%2F&?%26"; + int result; + coap_uri_t uri; + unsigned char buf[40]; + size_t buflen = sizeof(buf); + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; + + /* The list of path segments to check against. Each segment is + preceded by a dummy option indicating that holds the (dummy) + delta value 0 and the actual segment length. */ + const uint8_t uricheckbuf[] = { 0x01, 0x61 }; + const uint8_t querycheckbuf[] = { 0x02, 0x2e, 0x2f, 0x02, 0x3f, 0x26 }; + + result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri); + if (result == 0) { + CU_ASSERT(uri.host.length == 12); + CU_ASSERT_NSTRING_EQUAL(uri.host.s, "198.51.100.1", 12); + + CU_ASSERT(uri.port == 61616); + + CU_ASSERT(uri.path.length == 19); + CU_ASSERT_NSTRING_EQUAL(uri.path.s, "/%2E//%2E%2E/./../a", 19); + + CU_ASSERT(uri.query.length == 11); + CU_ASSERT_NSTRING_EQUAL(uri.query.s, "%2e%2F&?%26", 11); + + /* check path segments */ + result = coap_split_path(uri.path.s, uri.path.length, buf, &buflen); + CU_ASSERT(result == 1); + CU_ASSERT(buflen == sizeof(uricheckbuf)); + CU_ASSERT_NSTRING_EQUAL(buf, uricheckbuf, buflen); + + result = coap_path_into_optlist(uri.path.s, uri.path.length, 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(uricheckbuf)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, uricheckbuf, pdu->used_size); + coap_delete_pdu(pdu); + + /* check query segments */ + buflen = sizeof(buf); + result = coap_split_query(uri.query.s, uri.query.length, buf, &buflen); + CU_ASSERT(result == 2); + CU_ASSERT(buflen == sizeof(querycheckbuf)); + CU_ASSERT_NSTRING_EQUAL(buf, querycheckbuf, buflen); + optlist_chain = NULL; + + result = coap_query_into_optlist(uri.query.s, uri.query.length, 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(querycheckbuf)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, querycheckbuf, pdu->used_size); + coap_delete_pdu(pdu); + } else { + CU_FAIL("uri parser error"); + } +} + +static void +t_parse_uri26(void) { + char teststr[] = "coap://198.51.100.1:61616//a/?a=b"; + int result; + coap_uri_t uri; + unsigned char buf[40]; + size_t buflen = sizeof(buf); + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; + + /* The list of path segments to check against. Each segment is + preceded by a dummy option indicating that holds the (dummy) + delta value 0 and the actual segment length. */ + const uint8_t uricheckbuf[] = { 0x00, 0x01, 0x61, 0x00 }; + const uint8_t querycheckbuf[] = { 0x03, 0x61, 0x3d, 0x62 }; + + result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri); + if (result == 0) { + CU_ASSERT(uri.host.length == 12); + CU_ASSERT_NSTRING_EQUAL(uri.host.s, "198.51.100.1", 12); + + CU_ASSERT(uri.port == 61616); + + CU_ASSERT(uri.path.length == 3); + CU_ASSERT_NSTRING_EQUAL(uri.path.s, "/a/", 3); + + CU_ASSERT(uri.query.length == 3); + CU_ASSERT_NSTRING_EQUAL(uri.query.s, "a=b", 3); + + /* check path segments */ + result = coap_split_path(uri.path.s, uri.path.length, buf, &buflen); + CU_ASSERT(result == 3); + CU_ASSERT(buflen == sizeof(uricheckbuf)); + CU_ASSERT_NSTRING_EQUAL(buf, uricheckbuf, buflen); + + result = coap_path_into_optlist(uri.path.s, uri.path.length, 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(uricheckbuf)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, uricheckbuf, pdu->used_size); + coap_delete_pdu(pdu); + + /* check query segments */ + buflen = sizeof(buf); + result = coap_split_query(uri.query.s, uri.query.length, buf, &buflen); + CU_ASSERT(result == 1); + CU_ASSERT(buflen == sizeof(querycheckbuf)); + CU_ASSERT_NSTRING_EQUAL(buf, querycheckbuf, buflen); + optlist_chain = NULL; + + result = coap_query_into_optlist(uri.query.s, uri.query.length, 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(querycheckbuf)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, querycheckbuf, pdu->used_size); + coap_delete_pdu(pdu); + } else { + CU_FAIL("uri parser error"); + } } +static void +t_parse_uri27(void) { + char testpath[] = "../a"; + int result; + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; + unsigned char buf[40]; + size_t buflen = sizeof(buf); + + const uint8_t pathcheckbuf_1[] = { 0x01, 0x61 }; + const uint8_t pathcheckbuf_2[] = { 0x34, 0x68, 0x6f, 0x73, 0x74, 0x81, 0x61 }; + + result = coap_split_path((uint8_t *)testpath, strlen(testpath), buf, &buflen); + CU_ASSERT(result == 1); + CU_ASSERT(buflen == sizeof(pathcheckbuf_1)); + CU_ASSERT_NSTRING_EQUAL(buf, pathcheckbuf_1, buflen); + + result = coap_path_into_optlist((uint8_t *)testpath, strlen(testpath), + 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(pathcheckbuf_1)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, pathcheckbuf_1, pdu->used_size); + coap_delete_pdu(pdu); + + optlist_chain = NULL; + /* Add in a Uri-Host: option to check .. backup */ + coap_insert_optlist(&optlist_chain, + coap_new_optlist(COAP_OPTION_URI_HOST, + 4, + (const uint8_t *)"host")); + result = coap_path_into_optlist((uint8_t *)testpath, strlen(testpath), + COAP_OPTION_URI_PATH, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(pathcheckbuf_2)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, pathcheckbuf_2, pdu->used_size); + coap_delete_pdu(pdu); +} + +static void +t_parse_uri28(void) { + char testpath[] = "a/"; + int result; + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; + unsigned char buf[40]; + size_t buflen = sizeof(buf); + + const uint8_t pathcheckbuf_1[] = { 0x01, 0x61, 0x00 }; + + result = coap_split_path((uint8_t *)testpath, strlen(testpath), buf, &buflen); + CU_ASSERT(result == 2); + CU_ASSERT(buflen == sizeof(pathcheckbuf_1)); + CU_ASSERT_NSTRING_EQUAL(buf, pathcheckbuf_1, buflen); + + result = coap_path_into_optlist((uint8_t *)testpath, strlen(testpath), + 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(pathcheckbuf_1)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, pathcheckbuf_1, pdu->used_size); + coap_delete_pdu(pdu); +} + +static void +t_parse_uri29(void) { + char testpath[] = "a/."; + int result; + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; + unsigned char buf[40]; + size_t buflen = sizeof(buf); + + const uint8_t pathcheckbuf_1[] = { 0x01, 0x61 }; + + result = coap_split_path((uint8_t *)testpath, strlen(testpath), buf, &buflen); + CU_ASSERT(result == 1); + CU_ASSERT(buflen == sizeof(pathcheckbuf_1)); + CU_ASSERT_NSTRING_EQUAL(buf, pathcheckbuf_1, buflen); + + result = coap_path_into_optlist((uint8_t *)testpath, strlen(testpath), + 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(pathcheckbuf_1)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, pathcheckbuf_1, pdu->used_size); + coap_delete_pdu(pdu); +} + +static void +t_parse_uri30(void) { + char testpath[] = "a/.."; + int result; + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; + unsigned char buf[40]; + size_t buflen = sizeof(buf); + + result = coap_split_path((uint8_t *)testpath, strlen(testpath), buf, &buflen); + CU_ASSERT(result == 0); + CU_ASSERT(buflen == 0); + + result = coap_path_into_optlist((uint8_t *)testpath, strlen(testpath), + 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == 0); + coap_delete_pdu(pdu); +} + +static void +t_parse_uri31(void) { + char testpath[] = "a/../"; + int result; + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; + unsigned char buf[40]; + size_t buflen = sizeof(buf); + + const uint8_t pathcheckbuf_1[] = { 0x00 }; + + result = coap_split_path((uint8_t *)testpath, strlen(testpath), buf, &buflen); + CU_ASSERT(result == 1); + CU_ASSERT(buflen == sizeof(pathcheckbuf_1)); + CU_ASSERT_NSTRING_EQUAL(buf, pathcheckbuf_1, buflen); + + result = coap_path_into_optlist((uint8_t *)testpath, strlen(testpath), + 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(pathcheckbuf_1)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, pathcheckbuf_1, pdu->used_size); + coap_delete_pdu(pdu); +} + +static void +t_parse_uri32(void) { + char testpath[] = "a/.b"; + int result; + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; + unsigned char buf[40]; + size_t buflen = sizeof(buf); + + const uint8_t pathcheckbuf_1[] = { 0x01, 0x61, 0x2, 0x2e, 0x62 }; + + result = coap_split_path((uint8_t *)testpath, strlen(testpath), buf, &buflen); + CU_ASSERT(result == 2); + CU_ASSERT(buflen == sizeof(pathcheckbuf_1)); + CU_ASSERT_NSTRING_EQUAL(buf, pathcheckbuf_1, buflen); + + result = coap_path_into_optlist((uint8_t *)testpath, strlen(testpath), + 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(pathcheckbuf_1)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, pathcheckbuf_1, pdu->used_size); + coap_delete_pdu(pdu); +} + +static void +t_parse_uri33(void) { + char testpath[] = "a/..b"; + int result; + coap_optlist_t *optlist_chain = NULL; + coap_pdu_t *pdu = NULL; + unsigned char buf[40]; + size_t buflen = sizeof(buf); + + const uint8_t pathcheckbuf_1[] = { 0x01, 0x61, 0x3, 0x2e, 0x2e, 0x62 }; + + result = coap_split_path((uint8_t *)testpath, strlen(testpath), buf, &buflen); + CU_ASSERT(result == 2); + CU_ASSERT(buflen == sizeof(pathcheckbuf_1)); + CU_ASSERT_NSTRING_EQUAL(buf, pathcheckbuf_1, buflen); + + result = coap_path_into_optlist((uint8_t *)testpath, strlen(testpath), + 0, &optlist_chain); + CU_ASSERT(result == 1); + pdu = coap_pdu_init(0, 0, 0, 128); + CU_ASSERT(pdu != NULL); + assert(pdu != NULL); + result = coap_add_optlist_pdu(pdu, &optlist_chain); + CU_ASSERT(result == 1); + coap_delete_optlist(optlist_chain); + CU_ASSERT(pdu->used_size == sizeof(pathcheckbuf_1)); + CU_ASSERT_NSTRING_EQUAL(pdu->token, pathcheckbuf_1, pdu->used_size); + coap_delete_pdu(pdu); +} CU_pSuite t_init_uri_tests(void) { @@ -623,6 +1087,15 @@ t_init_uri_tests(void) { URI_TEST(suite, t_parse_uri22); URI_TEST(suite, t_parse_uri23); URI_TEST(suite, t_parse_uri24); + URI_TEST(suite, t_parse_uri25); + URI_TEST(suite, t_parse_uri26); + URI_TEST(suite, t_parse_uri27); + URI_TEST(suite, t_parse_uri28); + URI_TEST(suite, t_parse_uri29); + URI_TEST(suite, t_parse_uri30); + URI_TEST(suite, t_parse_uri31); + URI_TEST(suite, t_parse_uri32); + URI_TEST(suite, t_parse_uri33); return suite; }