Skip to content

Commit

Permalink
net: lib: downloader: fix issue when header is not parsed at once
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
eivindj-nordic committed Jan 21, 2025
1 parent fbec239 commit 8c850ad
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 6 deletions.
12 changes: 6 additions & 6 deletions subsys/net/lib/downloader/src/transports/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -215,7 +215,7 @@ static int http_header_parse(struct downloader *dl, size_t buf_len)

LOG_DBG("(partial) http header response:\n%s", dl->cfg.buf);

p = strnstr(dl->cfg.buf, "\r\n\r\n", dl->cfg.buf_size);
p = strnstr(dl->cfg.buf, "\r\n\r\n", buf_len);
if (p) {
/* End of header received */
http->header.has_end = true;
Expand Down Expand Up @@ -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;
}
Expand Down
65 changes: 65 additions & 0 deletions tests/subsys/net/lib/downloader/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 8c850ad

Please sign in to comment.