diff --git a/sys/include/net/nanocoap.h b/sys/include/net/nanocoap.h index 4d9a916056..6d3b17ca9e 100644 --- a/sys/include/net/nanocoap.h +++ b/sys/include/net/nanocoap.h @@ -1269,12 +1269,32 @@ static inline size_t coap_opt_put_block2_control(uint8_t *buf, uint16_t lastonum * or 0 if first option * @param[in] optnum option number to use * @param[in] string string to encode as option + * @param[in] len length of the string * @param[in] separator character used in @p string to separate parts * * @return number of bytes written to @p buf */ -size_t coap_opt_put_string(uint8_t *buf, uint16_t lastonum, uint16_t optnum, - const char *string, char separator); +size_t coap_opt_put_string_with_len(uint8_t *buf, uint16_t lastonum, uint16_t optnum, + const char *string, size_t len, char separator); +/** + * @brief Encode the given string as multi-part option into buffer + * + * @param[out] buf buffer to write to + * @param[in] lastonum number of previous option (for delta calculation), + * or 0 if first option + * @param[in] optnum option number to use + * @param[in] string string to encode as option + * @param[in] separator character used in @p string to separate parts + * + * @return number of bytes written to @p buf + */ +static inline size_t coap_opt_put_string(uint8_t *buf, uint16_t lastonum, + uint16_t optnum, + const char *string, char separator) +{ + return coap_opt_put_string_with_len(buf, lastonum, optnum, + string, strlen(string), separator); +} /** * @brief Convenience function for inserting LOCATION_PATH option into buffer @@ -1344,6 +1364,25 @@ static inline size_t coap_opt_put_uri_query(uint8_t *buf, uint16_t lastonum, return coap_opt_put_string(buf, lastonum, COAP_OPT_URI_QUERY, uri, '&'); } +/** + * @brief Convenience function for inserting URI_PATH and URI_QUERY into buffer + * This function will automatically split path and query parameters. + * + * @param[out] buf buffer to write to + * @param[in,out] lastonum number of previous option (for delta calculation), + * or 0 if first option + * @param[in] uri ptr into a source URI, to the first character after + * the authority component + * + * @returns amount of bytes written to @p buf + * + * This function may produce two different options (Uri-Path and Uri-Query). + * Users that need to insert Content-Format, Max-Age or the currently + * unassigned option 13 need to split their URI themselves and call the + * respective helper functions. + */ +size_t coap_opt_put_uri_pathquery(uint8_t *buf, uint16_t *lastonum, const char *uri); + /** * @brief Convenience function for inserting PROXY_URI option into buffer * diff --git a/sys/net/application_layer/nanocoap/nanocoap.c b/sys/net/application_layer/nanocoap/nanocoap.c index 8d62d987cc..3905e8a320 100644 --- a/sys/net/application_layer/nanocoap/nanocoap.c +++ b/sys/net/application_layer/nanocoap/nanocoap.c @@ -747,11 +747,9 @@ size_t coap_opt_put_block(uint8_t *buf, uint16_t lastonum, coap_block_slicer_t * return coap_opt_put_uint(buf, lastonum, option, _slicer2blkopt(slicer, more)); } -size_t coap_opt_put_string(uint8_t *buf, uint16_t lastonum, uint16_t optnum, - const char *string, char separator) +size_t coap_opt_put_string_with_len(uint8_t *buf, uint16_t lastonum, uint16_t optnum, + const char *string, size_t len, char separator) { - size_t len = strlen(string); - if (len == 0) { return 0; } @@ -789,6 +787,26 @@ size_t coap_opt_put_string(uint8_t *buf, uint16_t lastonum, uint16_t optnum, return bufpos - buf; } +size_t coap_opt_put_uri_pathquery(uint8_t *buf, uint16_t *lastonum, const char *uri) +{ + const char *query = strchr(uri, '?'); + size_t len = query ? (size_t)(query - uri - 1) : strlen(uri); + size_t bytes_out = coap_opt_put_string_with_len(buf, *lastonum, + COAP_OPT_URI_PATH, + uri, len, '/'); + + if (query) { + buf += bytes_out; + bytes_out += coap_opt_put_uri_query(buf, COAP_OPT_URI_PATH, query + 1); + *lastonum = COAP_OPT_URI_QUERY; + } + else { + *lastonum = COAP_OPT_URI_PATH; + } + + return bytes_out; +} + size_t coap_opt_put_uint(uint8_t *buf, uint16_t lastonum, uint16_t onum, uint32_t value) { diff --git a/sys/suit/transport/coap.c b/sys/suit/transport/coap.c index 77e3702012..fefa6aecc1 100644 --- a/sys/suit/transport/coap.c +++ b/sys/suit/transport/coap.c @@ -198,14 +198,15 @@ static int _fetch_block(coap_pkt_t *pkt, uint8_t *buf, sock_udp_t *sock, const char *path, coap_blksize_t blksize, size_t num) { uint8_t *pktpos = buf; + uint16_t lastonum = 0; pkt->hdr = (coap_hdr_t *)buf; pktpos += coap_build_hdr(pkt->hdr, COAP_TYPE_CON, NULL, 0, COAP_METHOD_GET, num); - pktpos += coap_opt_put_uri_path(pktpos, 0, path); + pktpos += coap_opt_put_uri_pathquery(pktpos, &lastonum, path); pktpos += - coap_opt_put_uint(pktpos, COAP_OPT_URI_PATH, COAP_OPT_BLOCK2, + coap_opt_put_uint(pktpos, lastonum, COAP_OPT_BLOCK2, (num << 4) | blksize); pkt->payload = pktpos; diff --git a/tests/unittests/tests-nanocoap/tests-nanocoap.c b/tests/unittests/tests-nanocoap/tests-nanocoap.c index 00d5c85147..09ccdf1109 100644 --- a/tests/unittests/tests-nanocoap/tests-nanocoap.c +++ b/tests/unittests/tests-nanocoap/tests-nanocoap.c @@ -58,6 +58,37 @@ static void test_nanocoap__hdr(void) TEST_ASSERT_EQUAL_STRING((char *)loc_path, (char *)path_tmp); } +/* + * Validates encoded message ID byte order and put/get URI & Query option. + */ +static void test_nanocoap__hdr_2(void) +{ + uint8_t buf[_BUF_SIZE]; + uint16_t msgid = 0xABCD; + char path[] = "/test/abcd/efgh?foo=bar&baz=blub"; + unsigned char path_tmp[64] = {0}; + unsigned char query_tmp[64] = {0}; + + uint8_t *pktpos = &buf[0]; + uint16_t lastonum = 0; + pktpos += coap_build_hdr((coap_hdr_t *)pktpos, COAP_TYPE_CON, NULL, 0, + COAP_METHOD_GET, msgid); + pktpos += coap_opt_put_uri_pathquery(pktpos, &lastonum, path); + + coap_pkt_t pkt; + coap_parse(&pkt, &buf[0], pktpos - &buf[0]); + + TEST_ASSERT_EQUAL_INT(msgid, coap_get_id(&pkt)); + + int res = coap_get_uri_path(&pkt, path_tmp); + TEST_ASSERT_EQUAL_INT(sizeof("/test/abcd/efgh"), res); + TEST_ASSERT_EQUAL_STRING("/test/abcd/efgh", (char *)path_tmp); + + res = coap_get_uri_query(&pkt, query_tmp); + TEST_ASSERT_EQUAL_INT(sizeof("&foo=bar&baz=blub"), res); + TEST_ASSERT_EQUAL_STRING("&foo=bar&baz=blub", (char *)query_tmp); +} + /* * Client GET request with simple path. Test request generation. * Request /time resource from libcoap example @@ -840,6 +871,7 @@ Test *tests_nanocoap_tests(void) { EMB_UNIT_TESTFIXTURES(fixtures) { new_TestFixture(test_nanocoap__hdr), + new_TestFixture(test_nanocoap__hdr_2), new_TestFixture(test_nanocoap__get_req), new_TestFixture(test_nanocoap__put_req), new_TestFixture(test_nanocoap__get_multi_path),