Skip to content

Commit 4a85e47

Browse files
rluboskartben
authored andcommitted
net: http: client: Notify application about unprocessed data
The HTTP client would read data from a socket up to the size of the receiving buffer, however it may not process them all. This is usually only the case if protocol switching takes place, where the data read may belong to another protocol. Therefore we need a way to notify the caller about any potential data that is already present in the buffer and needs to be processed. Introduce an new data_len member in struct http_request to provide the information about the data already available in the receive buffer. If, after HTTP response processing, the value is non-zero, the data will be available in the beginning of the user provided receive buffer. To make this possible however, we need to track how many bytes were actually processed by the http_parser, therefore the code will no longer ignore the http_parser_execute() return value. To simplify processing, it's also been changed how the receive buffer is used. Instead of using it in a ring-buffer-like way, the offset variable will track how many bytes are available in the buffer, and in the rare occasions when not all data from the buffer was processed by the HTTP parser, we'll memmomve the remaining data to the beginning of the buffer. Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
1 parent 44ed0c6 commit 4a85e47

File tree

2 files changed

+50
-11
lines changed

2 files changed

+50
-11
lines changed

include/zephyr/net/http/client.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,13 @@ struct http_request {
260260
/** Length of the user supplied receive buffer */
261261
size_t recv_buf_len;
262262

263+
/** Length of the unprocessed data left inside the user supplied receive
264+
* buffer. In typical HTTP processing this should be 0, however in case
265+
* of switching protocols, there may be some data left belonging to the
266+
* new protocol.
267+
*/
268+
size_t data_len;
269+
263270
/** The URL for this request, for example: /index.html */
264271
const char *url;
265272

subsys/net/lib/http/http_client.c

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ static void http_report_progress(struct http_request *req)
480480
static int http_wait_data(int sock, struct http_request *req, const k_timepoint_t req_end_timepoint)
481481
{
482482
int total_received = 0;
483-
size_t offset = 0;
483+
size_t offset = 0, processed = 0;
484484
int received, ret;
485485
struct zsock_pollfd fds[1];
486486
int nfds = 1;
@@ -525,35 +525,67 @@ static int http_wait_data(int sock, struct http_request *req, const k_timepoint_
525525
} else if (received < 0) {
526526
ret = -errno;
527527
goto error;
528-
} else {
529-
req->internal.response.data_len += received;
530-
531-
(void)http_parser_execute(
532-
&req->internal.parser, &req->internal.parser_settings,
533-
req->internal.response.recv_buf + offset, received);
534528
}
535529

536530
total_received += received;
537531
offset += received;
538532

533+
processed = http_parser_execute(
534+
&req->internal.parser, &req->internal.parser_settings,
535+
req->internal.response.recv_buf, offset);
536+
537+
if (processed > offset) {
538+
LOG_ERR("HTTP parser error, too much data consumed");
539+
ret = -EBADMSG;
540+
goto error;
541+
}
542+
543+
if (req->internal.parser.http_errno != HPE_OK) {
544+
LOG_ERR("HTTP parsing error, %d",
545+
req->internal.parser.http_errno);
546+
ret = -EBADMSG;
547+
goto error;
548+
}
549+
550+
req->internal.response.data_len += processed;
551+
offset -= processed;
552+
539553
if (offset >= req->internal.response.recv_buf_len) {
540-
offset = 0;
554+
/* This means the parser did not consume any data
555+
* and we can't fit any more in the buffer.
556+
*/
557+
LOG_ERR("HTTP RX buffer full, cannot proceed");
558+
ret = -ENOMEM;
559+
goto error;
541560
}
542561

543562
if (req->internal.response.message_complete) {
544563
http_report_complete(req);
545-
break;
546-
} else if (offset == 0) {
564+
} else {
547565
http_report_progress(req);
548566

549567
/* Re-use the result buffer and start to fill it again */
550568
req->internal.response.data_len = 0;
551569
req->internal.response.body_frag_start = NULL;
552570
req->internal.response.body_frag_len = 0;
553571
}
572+
573+
if (offset > 0) {
574+
/* In case there are any unprocessed data left,
575+
* move them to the front of the buffer.
576+
*/
577+
memmove(req->internal.response.recv_buf,
578+
req->internal.response.recv_buf + processed,
579+
offset);
580+
}
554581
}
555582

556-
} while (true);
583+
} while (!req->internal.response.message_complete);
584+
585+
/* If there's still some data left in the buffer after HTTP processing,
586+
* reflect this in data_len variable.
587+
*/
588+
req->data_len = offset;
557589

558590
return total_received;
559591

0 commit comments

Comments
 (0)