diff --git a/sys/include/net/nanocoap.h b/sys/include/net/nanocoap.h index a6612fd918..5dbc5e28be 100644 --- a/sys/include/net/nanocoap.h +++ b/sys/include/net/nanocoap.h @@ -1046,6 +1046,27 @@ static inline ssize_t coap_opt_add_uri_query(coap_pkt_t *pkt, const char *key, */ ssize_t coap_opt_add_proxy_uri(coap_pkt_t *pkt, const char *uri); +/** + * @brief Encode the given array of characters as option(s) into pkt + * + * Use separator to split array of characters into multiple options. + * + * @post pkt.payload advanced to first byte after option(s) + * @post pkt.payload_len reduced by option(s) length + * + * @param[in,out] pkt pkt referencing target buffer + * @param[in] optnum option number to use + * @param[in] chars array of characters to encode as option + * @param[in] chars_len length of @p chars + * @param[in] separator character used in @p string to separate parts + * + * @return number of bytes written to buffer + * @return <0 on error + * @return -ENOSPC if no available options or insufficient buffer space + */ +ssize_t coap_opt_add_chars(coap_pkt_t *pkt, uint16_t optnum, const char *chars, + size_t chars_len, char separator); + /** * @brief Encode the given string as option(s) into pkt * @@ -1063,7 +1084,11 @@ ssize_t coap_opt_add_proxy_uri(coap_pkt_t *pkt, const char *uri); * @return <0 on error * @return -ENOSPC if no available options or insufficient buffer space */ -ssize_t coap_opt_add_string(coap_pkt_t *pkt, uint16_t optnum, const char *string, char separator); +static inline ssize_t coap_opt_add_string(coap_pkt_t *pkt, uint16_t optnum, + const char *string, char separator) +{ + return coap_opt_add_chars(pkt, optnum, string, strlen(string), separator); +} /** * @brief Adds one or multiple Uri-Path options in the form '/path' into pkt diff --git a/sys/net/application_layer/nanocoap/nanocoap.c b/sys/net/application_layer/nanocoap/nanocoap.c index 4611e10973..580899c219 100644 --- a/sys/net/application_layer/nanocoap/nanocoap.c +++ b/sys/net/application_layer/nanocoap/nanocoap.c @@ -819,28 +819,31 @@ static ssize_t _add_opt_pkt(coap_pkt_t *pkt, uint16_t optnum, const uint8_t *val return optlen; } -ssize_t coap_opt_add_string(coap_pkt_t *pkt, uint16_t optnum, const char *string, - char separator) +ssize_t coap_opt_add_chars(coap_pkt_t *pkt, uint16_t optnum, const char *chars, + size_t chars_len, char separator) { - size_t unread_len = strlen(string); - if (!unread_len) { + /* chars_len denotes the length of the chars buffer and is + * gradually decremented below while iterating over the buffer */ + if (!chars_len) { return 0; } - char *uripos = (char *)string; + + char *uripos = (char *)chars; + char *endpos = ((char *)chars + chars_len); size_t write_len = 0; - while (unread_len) { + while (chars_len) { size_t part_len; if (*uripos == separator) { uripos++; } uint8_t *part_start = (uint8_t *)uripos; - while (unread_len) { + while (chars_len) { /* must decrement separately from while loop test to ensure * the value remains non-negative */ - unread_len--; - if ((*uripos == separator) || (*uripos == '\0')) { + chars_len--; + if ((*uripos == separator) || (uripos == endpos)) { break; } uripos++; diff --git a/tests/unittests/tests-nanocoap/tests-nanocoap.c b/tests/unittests/tests-nanocoap/tests-nanocoap.c index 8f564e4510..52146f1ab2 100644 --- a/tests/unittests/tests-nanocoap/tests-nanocoap.c +++ b/tests/unittests/tests-nanocoap/tests-nanocoap.c @@ -745,6 +745,35 @@ static void test_nanocoap__empty(void) TEST_ASSERT_EQUAL_INT(-EBADMSG, res); } +/* + * Test adding a path from an unterminated string + */ +static void test_nanocoap__add_path_unterminated_string(void) +{ + uint8_t buf[_BUF_SIZE]; + coap_pkt_t pkt; + uint16_t msgid = 0xABCD; + uint8_t token[2] = {0xDA, 0xEC}; + char path[16] = "/time"; + size_t path_len = strlen("/time"); + + /* some random non-zero character at the end of /time */ + path[path_len] = 'Z'; + + size_t len = coap_build_hdr((coap_hdr_t *)&buf[0], COAP_TYPE_NON, + &token[0], 2, COAP_METHOD_GET, msgid); + + coap_pkt_init(&pkt, &buf[0], sizeof(buf), len); + coap_opt_add_chars(&pkt, COAP_OPT_URI_PATH, &path[0], path_len, '/'); + + char uri[10] = {0}; + ssize_t parsed_path_len = coap_get_uri_path(&pkt, (uint8_t *)&uri[0]); + + /* we subtract one byte for '\0' at the end from parsed_uri_path */ + TEST_ASSERT_EQUAL_INT(path_len, parsed_path_len - 1); + TEST_ASSERT_EQUAL_INT(0, strncmp(path, uri, path_len)); +} + Test *tests_nanocoap_tests(void) { EMB_UNIT_TESTFIXTURES(fixtures) { @@ -769,6 +798,7 @@ Test *tests_nanocoap_tests(void) new_TestFixture(test_nanocoap__server_option_count_overflow_check), new_TestFixture(test_nanocoap__server_option_count_overflow), new_TestFixture(test_nanocoap__empty), + new_TestFixture(test_nanocoap__add_path_unterminated_string), }; EMB_UNIT_TESTCALLER(nanocoap_tests, NULL, NULL, fixtures);