Skip to content

Commit 0e1c0a7

Browse files
rlubosnashif
authored andcommitted
net: lib: http_server: Fix trailing headers frame processing
In case client decides to send a trailing headers frame, the last data frame will not carry END_STREAM flag. In result, with current logic server would not include END_STREAM flag either, causing the connection to stall. This commit fixes this logic, so that the server replies accordingly in case END_STREAM flag is present in the trailing headers frame. Signed-off-by: Robert Lubos <[email protected]>
1 parent b4cfee0 commit 0e1c0a7

File tree

2 files changed

+87
-1
lines changed

2 files changed

+87
-1
lines changed

include/zephyr/net/http/server.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,9 +360,13 @@ struct http_client_ctx {
360360
IF_ENABLED(CONFIG_WEBSOCKET, (uint8_t ws_sec_key[HTTP_SERVER_WS_MAX_SEC_KEY_LEN]));
361361
/** @endcond */
362362

363+
/* TODO those two are stream-specific, move them. */
363364
/** Flag indicating that headers were sent in the reply. */
364365
bool headers_sent : 1;
365366

367+
/** Flag indicating that END_STREAM flag was sent. */
368+
bool end_stream_sent : 1;
369+
366370
/** Flag indicating that HTTP2 preface was sent. */
367371
bool preface_sent : 1;
368372

subsys/net/lib/http/http_server_http2.c

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ static int handle_http2_static_resource(
349349
goto out;
350350
}
351351

352+
client->headers_sent = true;
353+
352354
ret = send_data_frame(client, content_200, content_len,
353355
frame->stream_identifier,
354356
HTTP2_FLAG_END_STREAM);
@@ -357,6 +359,8 @@ static int handle_http2_static_resource(
357359
goto out;
358360
}
359361

362+
client->end_stream_sent = true;
363+
360364
out:
361365
return ret;
362366
}
@@ -375,6 +379,8 @@ static int dynamic_get_req_v2(struct http_resource_detail_dynamic *dynamic_detai
375379
return ret;
376380
}
377381

382+
client->headers_sent = true;
383+
378384
remaining = strlen(&client->url_buffer[dynamic_detail->common.path_len]);
379385

380386
/* Pass URL to the client */
@@ -422,6 +428,8 @@ static int dynamic_get_req_v2(struct http_resource_detail_dynamic *dynamic_detai
422428
LOG_DBG("Cannot send last frame (%d)", ret);
423429
}
424430

431+
client->end_stream_sent = true;
432+
425433
dynamic_detail->holder = NULL;
426434

427435
break;
@@ -491,6 +499,7 @@ static int dynamic_post_req_v2(struct http_resource_detail_dynamic *dynamic_deta
491499
if (frame->length == 0 &&
492500
is_header_flag_set(frame->flags, HTTP2_FLAG_END_STREAM)) {
493501
flags = HTTP2_FLAG_END_STREAM;
502+
client->end_stream_sent = true;
494503
}
495504

496505
ret = send_data_frame(client,
@@ -523,6 +532,7 @@ static int dynamic_post_req_v2(struct http_resource_detail_dynamic *dynamic_deta
523532
}
524533

525534
client->headers_sent = true;
535+
client->end_stream_sent = true;
526536
}
527537

528538
dynamic_detail->holder = NULL;
@@ -1102,6 +1112,75 @@ static int handle_incomplete_http_header(struct http_client_ctx *client)
11021112
return enter_http_frame_continuation_state(client);
11031113
}
11041114

1115+
static int handle_http_frame_headers_end_stream(struct http_client_ctx *client)
1116+
{
1117+
struct http2_frame *frame = &client->current_frame;
1118+
int ret = 0;
1119+
1120+
if (client->current_detail == NULL) {
1121+
goto out;
1122+
}
1123+
1124+
if (client->current_detail->type == HTTP_RESOURCE_TYPE_DYNAMIC) {
1125+
struct http_resource_detail_dynamic *dynamic_detail =
1126+
(struct http_resource_detail_dynamic *)client->current_detail;
1127+
int send_len;
1128+
1129+
send_len = dynamic_detail->cb(client, HTTP_SERVER_DATA_FINAL,
1130+
dynamic_detail->data_buffer, 0,
1131+
dynamic_detail->user_data);
1132+
if (send_len > 0) {
1133+
if (!client->headers_sent) {
1134+
ret = send_headers_frame(
1135+
client, HTTP_200_OK, frame->stream_identifier,
1136+
client->current_detail, 0);
1137+
if (ret < 0) {
1138+
LOG_DBG("Cannot write to socket (%d)", ret);
1139+
goto out;
1140+
}
1141+
1142+
client->headers_sent = true;
1143+
}
1144+
1145+
ret = send_data_frame(client,
1146+
dynamic_detail->data_buffer,
1147+
send_len, frame->stream_identifier,
1148+
HTTP2_FLAG_END_STREAM);
1149+
if (ret < 0) {
1150+
LOG_DBG("Cannot send data frame (%d)", ret);
1151+
goto out;
1152+
}
1153+
1154+
client->end_stream_sent = true;
1155+
}
1156+
1157+
dynamic_detail->holder = NULL;
1158+
}
1159+
1160+
if (!client->headers_sent) {
1161+
ret = send_headers_frame(
1162+
client, HTTP_200_OK, frame->stream_identifier,
1163+
client->current_detail, HTTP2_FLAG_END_STREAM);
1164+
if (ret < 0) {
1165+
LOG_DBG("Cannot write to socket (%d)", ret);
1166+
goto out;
1167+
}
1168+
} else if (!client->end_stream_sent) {
1169+
ret = send_data_frame(client, NULL, 0, frame->stream_identifier,
1170+
HTTP2_FLAG_END_STREAM);
1171+
if (ret < 0) {
1172+
LOG_DBG("Cannot send last frame (%d)", ret);
1173+
}
1174+
}
1175+
1176+
client->current_detail = NULL;
1177+
1178+
out:
1179+
release_http_stream_context(client, frame->stream_identifier);
1180+
1181+
return ret;
1182+
}
1183+
11051184
int handle_http_frame_headers(struct http_client_ctx *client)
11061185
{
11071186
struct http2_frame *frame = &client->current_frame;
@@ -1191,7 +1270,10 @@ int handle_http_frame_headers(struct http_client_ctx *client)
11911270
}
11921271

11931272
if (is_header_flag_set(frame->flags, HTTP2_FLAG_END_STREAM)) {
1194-
release_http_stream_context(client, frame->stream_identifier);
1273+
ret = handle_http_frame_headers_end_stream(client);
1274+
if (ret < 0) {
1275+
return ret;
1276+
}
11951277
}
11961278

11971279
if (frame->padding_len > 0) {

0 commit comments

Comments
 (0)