Skip to content

Commit be7faf7

Browse files
rlubosnashif
authored andcommitted
net: http: Fix HTTP_DATA_FINAL notification
HTTP_DATA_FINAL was incorrectly notified in case Content Length field was present in the HTTP respone - in such case it was set for every response fragment, not only the last one. Fix this by relying on `message_complete` flag instead of `http_should_keep_alive()` function to determine whether to notify HTTP_DATA_FINAL or not. As the HTTP parser calls the `on_message_complete()` callback in either case (response is chunked or not), this seems to be a more reasonable apporach to determine whether the fragment is final or not. Additinally, instead of calling response callback for `on_body`/`on_message_complete` separately, call it directly from `http_wait_data()` function, after the parsing round. This fixes the case when headers were not reported correctly when the provided buffer was smaller than the total headers length, resulting in corrupted data being reported to the user. Signed-off-by: Robert Lubos <[email protected]>
1 parent 55c3dde commit be7faf7

File tree

1 file changed

+40
-30
lines changed

1 file changed

+40
-30
lines changed

subsys/net/lib/http/http_client.c

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -269,28 +269,6 @@ static int on_body(struct http_parser *parser, const char *at, size_t length)
269269
req->internal.response.body_start = (uint8_t *)at;
270270
}
271271

272-
if (req->internal.response.cb) {
273-
if (http_should_keep_alive(parser)) {
274-
NET_DBG("Calling callback for partitioned %zd len data",
275-
req->internal.response.data_len);
276-
277-
req->internal.response.cb(&req->internal.response,
278-
HTTP_DATA_MORE,
279-
req->internal.user_data);
280-
} else {
281-
NET_DBG("Calling callback for %zd len data",
282-
req->internal.response.data_len);
283-
284-
req->internal.response.cb(&req->internal.response,
285-
HTTP_DATA_FINAL,
286-
req->internal.user_data);
287-
}
288-
289-
/* Re-use the result buffer and start to fill it again */
290-
req->internal.response.data_len = 0;
291-
req->internal.response.body_start = NULL;
292-
}
293-
294272
return 0;
295273
}
296274

@@ -354,12 +332,6 @@ static int on_message_complete(struct http_parser *parser)
354332

355333
req->internal.response.message_complete = 1;
356334

357-
if (req->internal.response.cb) {
358-
req->internal.response.cb(&req->internal.response,
359-
HTTP_DATA_FINAL,
360-
req->internal.user_data);
361-
}
362-
363335
return 0;
364336
}
365337

@@ -416,12 +388,21 @@ static int http_wait_data(int sock, struct http_request *req)
416388

417389
do {
418390
received = zsock_recv(sock, req->internal.response.recv_buf + offset,
419-
req->internal.response.recv_buf_len - offset,
420-
0);
391+
req->internal.response.recv_buf_len - offset,
392+
0);
421393
if (received == 0) {
422394
/* Connection closed */
423395
LOG_DBG("Connection closed");
424396
ret = total_received;
397+
398+
if (req->internal.response.cb) {
399+
NET_DBG("Calling callback for closed connection");
400+
401+
req->internal.response.cb(&req->internal.response,
402+
HTTP_DATA_FINAL,
403+
req->internal.user_data);
404+
}
405+
425406
break;
426407
} else if (received < 0) {
427408
/* Socket error */
@@ -445,6 +426,35 @@ static int http_wait_data(int sock, struct http_request *req)
445426
offset = 0;
446427
}
447428

429+
if (req->internal.response.cb) {
430+
bool notify = false;
431+
enum http_final_call event;
432+
433+
if (req->internal.response.message_complete) {
434+
NET_DBG("Calling callback for %zd len data",
435+
req->internal.response.data_len);
436+
437+
notify = true;
438+
event = HTTP_DATA_FINAL;
439+
} else if (offset == 0) {
440+
NET_DBG("Calling callback for partitioned %zd len data",
441+
req->internal.response.data_len);
442+
443+
notify = true;
444+
event = HTTP_DATA_MORE;
445+
}
446+
447+
if (notify) {
448+
req->internal.response.cb(&req->internal.response,
449+
event,
450+
req->internal.user_data);
451+
452+
/* Re-use the result buffer and start to fill it again */
453+
req->internal.response.data_len = 0;
454+
req->internal.response.body_start = NULL;
455+
}
456+
}
457+
448458
if (req->internal.response.message_complete) {
449459
ret = total_received;
450460
break;

0 commit comments

Comments
 (0)