From 62aacdcb0ca0fee778be47072aaaf6fc37370f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eivind=20J=C3=B8lsgard?= Date: Tue, 21 Jan 2025 13:39:21 +0100 Subject: [PATCH] net: lib: downloader: fix issue when header is not parsed at once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix issue with buffer offset when header is not parsed at once. This could result in data being lost in the downloaded file. Signed-off-by: Eivind Jølsgard --- .../net/lib/downloader/src/transports/http.c | 10 +-- tests/subsys/net/lib/downloader/src/main.c | 65 +++++++++++++++++++ 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/subsys/net/lib/downloader/src/transports/http.c b/subsys/net/lib/downloader/src/transports/http.c index 439422ea1702..aeaf9dfdfc7e 100644 --- a/subsys/net/lib/downloader/src/transports/http.c +++ b/subsys/net/lib/downloader/src/transports/http.c @@ -145,16 +145,16 @@ static int http_get_request_send(struct downloader *dl) IS_ENABLED(CONFIG_SOC_SERIES_NRF91X)); if (dl->host_cfg.range_override) { - if (tls_force_range && dl->host_cfg.range_override > (TLS_RANGE_MAX - 1)) { + if (tls_force_range && dl->host_cfg.range_override > (TLS_RANGE_MAX)) { LOG_WRN("Range override > TLS max range, setting to TLS max range"); - dl->host_cfg.range_override = (TLS_RANGE_MAX - 1); + dl->host_cfg.range_override = (TLS_RANGE_MAX); } } else if (tls_force_range) { - dl->host_cfg.range_override = TLS_RANGE_MAX - 1; + dl->host_cfg.range_override = TLS_RANGE_MAX; } if (dl->host_cfg.range_override) { - off = dl->progress + dl->host_cfg.range_override; + off = dl->progress + dl->host_cfg.range_override - 1; if (dl->file_size && (off > dl->file_size - 1)) { /* Don't request bytes past the end of file */ @@ -591,7 +591,7 @@ static int dl_http_download(struct downloader *dl) return -ECONNRESET; } - ret = http_parse(dl, len); + ret = http_parse(dl, len + dl->buf_offset); if (ret <= 0) { return ret; } diff --git a/tests/subsys/net/lib/downloader/src/main.c b/tests/subsys/net/lib/downloader/src/main.c index 6342d1226545..3e3540fecaf1 100644 --- a/tests/subsys/net/lib/downloader/src/main.c +++ b/tests/subsys/net/lib/downloader/src/main.c @@ -84,6 +84,24 @@ "Vary: Accept-Encoding\r\n" \ "X-Cache: HIT\r\n\r\n" +#define HTTP_HDR_OK_PARTIAL_1 "HTTP/1.1 200 OK\r\n" \ +"Accept-Ranges: bytes\r\n" \ +"Age: 497805\r\n" \ +"Cache-Control: max-age=604800\r\n" \ +"Content-Encoding: gzip\r\n" \ +"Content-Length: 128\r\n" \ +"Content-Type: text/html; charset=UTF-8\r\n" \ +"Date: W" + +#define HTTP_HDR_OK_PARTIAL_2 \ +"ed, 06 Nov 2024 13:00:48 GMT\r\n" \ +"Etag: \"3147526947\"\r\n" \ +"Expires: Wed, 23 Nov 2124 23:12:95 GMT\r\n" \ +"Last-Modified: Thu, 06 Nov 2024 14:17:23 GMT\r\n" \ +"Server: ECAcc (nyd/D184)\r\n" \ +"Vary: Accept-Encoding\r\n" \ +"X-Cache: HIT\r\n\r\n" + #define PAYLOAD "This is the payload!" #define FD 0 @@ -731,6 +749,28 @@ static ssize_t z_impl_zsock_recvfrom_http_header_then_data( return 0; } +static ssize_t z_impl_zsock_recvfrom_http_partial_header_then_header_with_data( + int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, + socklen_t *addrlen) +{ + TEST_ASSERT_EQUAL(FD, sock); + TEST_ASSERT(sizeof(dl_buf) >= max_len); + + memset(buf, 0, max_len); + + switch (z_impl_zsock_recvfrom_fake.call_count) { + case 1: + memcpy(buf, HTTP_HDR_OK_PARTIAL_1, strlen(HTTP_HDR_OK_PARTIAL_1)); + return strlen(HTTP_HDR_OK_PARTIAL_1); + case 2: + memcpy(buf, HTTP_HDR_OK_PARTIAL_2, strlen(HTTP_HDR_OK_PARTIAL_2)); + memset(buf + strlen(HTTP_HDR_OK_PARTIAL_2), 23, 128); + return strlen(HTTP_HDR_OK_PARTIAL_2) + 128; + } + + return 0; +} + static ssize_t z_impl_zsock_recvfrom_http_header_and_payload( int sock, void *buf, size_t max_len, int flags, struct sockaddr *src_addr, socklen_t *addrlen) @@ -1103,6 +1143,31 @@ void test_downloader_get_http(void) z_impl_zsock_sendto_fake.custom_fake = z_impl_zsock_sendto_ok; z_impl_zsock_recvfrom_fake.custom_fake = z_impl_zsock_recvfrom_http_header_then_data; + err = downloader_get(&dl, &dl_host_cfg, HTTP_URL, 0); + TEST_ASSERT_EQUAL(0, err); + + evt = dl_wait_for_event(DOWNLOADER_EVT_DONE, K_SECONDS(3)); + + downloader_deinit(&dl); + dl_wait_for_event(DOWNLOADER_EVT_DEINITIALIZED, K_SECONDS(1)); +} + +void test_downloader_get_http_partial_header(void) +{ + int err; + struct downloader_evt evt; + + err = downloader_init(&dl, &dl_cfg); + TEST_ASSERT_EQUAL(0, err); + + zsock_getaddrinfo_fake.custom_fake = zsock_getaddrinfo_server_ipv6_fail_ipv4_ok; + zsock_freeaddrinfo_fake.custom_fake = zsock_freeaddrinfo_server_ipv4; + z_impl_zsock_socket_fake.custom_fake = z_impl_zsock_socket_http_ipv4_ok; + z_impl_zsock_connect_fake.custom_fake = z_impl_zsock_connect_ipv4_ok; + z_impl_zsock_setsockopt_fake.custom_fake = z_impl_zsock_setsockopt_http_ok; + z_impl_zsock_sendto_fake.custom_fake = z_impl_zsock_sendto_ok; + z_impl_zsock_recvfrom_fake.custom_fake = + z_impl_zsock_recvfrom_http_partial_header_then_header_with_data; err = downloader_get(&dl, &dl_host_cfg, HTTP_URL, 0); TEST_ASSERT_EQUAL(0, err);