Skip to content

Commit e9bedcc

Browse files
rluboskartben
authored andcommitted
net: http_server: Add support for generic HTTP2 500 response
In case of errors during HTTP2 request processing (or after the HTTP1 upgrade response was sent), send 500 Internal Server Error response before shutting down the connection. Signed-off-by: Robert Lubos <[email protected]>
1 parent 143c4e0 commit e9bedcc

File tree

1 file changed

+85
-17
lines changed

1 file changed

+85
-17
lines changed

subsys/net/lib/http/http_server_http2.c

Lines changed: 85 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,46 @@ static int send_http2_409(struct http_client_ctx *client,
369369
return ret;
370370
}
371371

372+
static void send_http2_500(struct http_client_ctx *client,
373+
struct http2_frame *frame, int error_code)
374+
{
375+
#define HTTP_500_RESPONSE_TEMPLATE "Internal Server Error%s%s"
376+
#define MAX_ERROR_DESC_LEN 32
377+
378+
char error_str[] = "xxx";
379+
char http_response[sizeof(HTTP_500_RESPONSE_TEMPLATE) +
380+
MAX_ERROR_DESC_LEN + 1]; /* For the error description */
381+
const char *error_desc;
382+
const char *desc_separator;
383+
384+
if (IS_ENABLED(CONFIG_HTTP_SERVER_REPORT_FAILURE_REASON)) {
385+
/* Try to fetch error description, fallback to error number if
386+
* not available
387+
*/
388+
error_desc = strerror(error_code);
389+
if (strlen(error_desc) == 0) {
390+
/* Cast error value to uint8_t to avoid truncation warnings. */
391+
(void)snprintk(error_str, sizeof(error_str), "%u",
392+
(uint8_t)error_code);
393+
error_desc = error_str;
394+
}
395+
desc_separator = ": ";
396+
} else {
397+
error_desc = "";
398+
desc_separator = "";
399+
}
400+
401+
if (send_headers_frame(client, HTTP_500_INTERNAL_SERVER_ERROR,
402+
frame->stream_identifier, NULL, 0, NULL, 0) < 0) {
403+
return;
404+
}
405+
406+
(void)snprintk(http_response, sizeof(http_response),
407+
HTTP_500_RESPONSE_TEMPLATE, desc_separator, error_desc);
408+
(void)send_data_frame(client, http_response, strlen(http_response),
409+
frame->stream_identifier, HTTP2_FLAG_END_STREAM);
410+
}
411+
372412
static int handle_http2_static_resource(
373413
struct http_resource_detail_static *static_detail,
374414
struct http2_frame *frame, struct http_client_ctx *client)
@@ -1027,7 +1067,7 @@ int handle_http1_to_http2_upgrade(struct http_client_ctx *client)
10271067
ret = http_server_sendall(client, switching_protocols,
10281068
sizeof(switching_protocols) - 1);
10291069
if (ret < 0) {
1030-
goto error;
1070+
return ret;
10311071
}
10321072

10331073
client->http1_headers_sent = true;
@@ -1101,6 +1141,11 @@ int handle_http1_to_http2_upgrade(struct http_client_ctx *client)
11011141
return 0;
11021142

11031143
error:
1144+
if (ret != -EAGAIN && client->current_stream &&
1145+
!client->current_stream->headers_sent) {
1146+
send_http2_500(client, frame, -ret);
1147+
}
1148+
11041149
return ret;
11051150
}
11061151

@@ -1169,13 +1214,14 @@ int handle_http_frame_data(struct http_client_ctx *client)
11691214
/* There is no handler */
11701215
LOG_DBG("No dynamic handler found.");
11711216
(void)send_http2_404(client, frame);
1172-
return -ENOENT;
1217+
ret = -ENOENT;
1218+
goto error;
11731219
}
11741220

11751221
if (is_header_flag_set(frame->flags, HTTP2_FLAG_PADDED)) {
11761222
ret = parse_http_frame_padded_field(client);
11771223
if (ret < 0) {
1178-
return ret;
1224+
goto error;
11791225
}
11801226
}
11811227

@@ -1187,7 +1233,7 @@ int handle_http_frame_data(struct http_client_ctx *client)
11871233
}
11881234

11891235
if (ret < 0) {
1190-
return ret;
1236+
goto error;
11911237
}
11921238

11931239
if (frame->length == 0) {
@@ -1197,17 +1243,18 @@ int handle_http_frame_data(struct http_client_ctx *client)
11971243
if (stream == NULL) {
11981244
LOG_DBG("No stream context found for ID %d",
11991245
frame->stream_identifier);
1200-
return -EBADMSG;
1246+
ret = -EBADMSG;
1247+
goto error;
12011248
}
12021249

12031250
ret = send_window_update_frame(client, stream);
12041251
if (ret < 0) {
1205-
return ret;
1252+
goto error;
12061253
}
12071254

12081255
ret = send_window_update_frame(client, NULL);
12091256
if (ret < 0) {
1210-
return ret;
1257+
goto error;
12111258
}
12121259

12131260
if (is_header_flag_set(frame->flags, HTTP2_FLAG_END_STREAM)) {
@@ -1224,6 +1271,14 @@ int handle_http_frame_data(struct http_client_ctx *client)
12241271
}
12251272

12261273
return 0;
1274+
1275+
error:
1276+
if (ret != -EAGAIN && client->current_stream &&
1277+
!client->current_stream->headers_sent) {
1278+
send_http2_500(client, frame, -ret);
1279+
}
1280+
1281+
return ret;
12271282
}
12281283

12291284
static void check_user_request_headers_http2(struct http_header_capture_ctx *ctx,
@@ -1473,14 +1528,14 @@ int handle_http_frame_headers(struct http_client_ctx *client)
14731528
if (is_header_flag_set(frame->flags, HTTP2_FLAG_PADDED)) {
14741529
ret = parse_http_frame_padded_field(client);
14751530
if (ret < 0) {
1476-
return ret;
1531+
goto error;
14771532
}
14781533
}
14791534

14801535
if (is_header_flag_set(frame->flags, HTTP2_FLAG_PRIORITY)) {
14811536
ret = parse_http_frame_priority_field(client);
14821537
if (ret < 0) {
1483-
return ret;
1538+
goto error;
14841539
}
14851540
}
14861541

@@ -1496,12 +1551,17 @@ int handle_http_frame_headers(struct http_client_ctx *client)
14961551
ret = -EBADMSG;
14971552
}
14981553

1499-
return ret;
1554+
if (ret < 0) {
1555+
goto error;
1556+
}
1557+
1558+
return 0;
15001559
}
15011560

15021561
if (ret > frame->length) {
15031562
LOG_ERR("Protocol error, frame length exceeded");
1504-
return -EBADMSG;
1563+
ret = -EBADMSG;
1564+
goto error;
15051565
}
15061566

15071567
frame->length -= ret;
@@ -1513,7 +1573,7 @@ int handle_http_frame_headers(struct http_client_ctx *client)
15131573

15141574
ret = process_header(client, header);
15151575
if (ret < 0) {
1516-
return ret;
1576+
goto error;
15171577
}
15181578
}
15191579

@@ -1532,34 +1592,34 @@ int handle_http_frame_headers(struct http_client_ctx *client)
15321592
(struct http_resource_detail_static *)detail,
15331593
frame, client);
15341594
if (ret < 0) {
1535-
return ret;
1595+
goto error;
15361596
}
15371597
} else if (detail->type == HTTP_RESOURCE_TYPE_STATIC_FS) {
15381598
ret = handle_http2_static_fs_resource(
15391599
(struct http_resource_detail_static_fs *)detail, frame, client);
15401600
if (ret < 0) {
1541-
return ret;
1601+
goto error;
15421602
}
15431603
} else if (detail->type == HTTP_RESOURCE_TYPE_DYNAMIC) {
15441604
ret = handle_http2_dynamic_resource(
15451605
(struct http_resource_detail_dynamic *)detail,
15461606
frame, client);
15471607
if (ret < 0) {
1548-
return ret;
1608+
goto error;
15491609
}
15501610
}
15511611

15521612
} else {
15531613
ret = send_http2_404(client, frame);
15541614
if (ret < 0) {
1555-
return ret;
1615+
goto error;
15561616
}
15571617
}
15581618

15591619
if (is_header_flag_set(frame->flags, HTTP2_FLAG_END_STREAM)) {
15601620
ret = handle_http_frame_headers_end_stream(client);
15611621
if (ret < 0) {
1562-
return ret;
1622+
goto error;
15631623
}
15641624
}
15651625

@@ -1570,6 +1630,14 @@ int handle_http_frame_headers(struct http_client_ctx *client)
15701630
}
15711631

15721632
return 0;
1633+
1634+
error:
1635+
if (ret != -EAGAIN && client->current_stream &&
1636+
!client->current_stream->headers_sent) {
1637+
send_http2_500(client, frame, -ret);
1638+
}
1639+
1640+
return ret;
15731641
}
15741642

15751643
int handle_http_frame_priority(struct http_client_ctx *client)

0 commit comments

Comments
 (0)