@@ -71,6 +71,51 @@ static int send_http1_409(struct http_client_ctx *client)
71
71
sizeof (conflict_response ) - 1 );
72
72
}
73
73
74
+ static void send_http1_500 (struct http_client_ctx * client , int error_code )
75
+ {
76
+ #define HTTP_500_RESPONSE_TEMPLATE \
77
+ "HTTP/1.1 500 Internal Server Error\r\n" \
78
+ "Content-Type: text/plain\r\n" \
79
+ "Content-Length: %d\r\n\r\n" \
80
+ "Internal Server Error%s%s\r\n"
81
+ #define MAX_ERROR_DESC_LEN 32
82
+
83
+ /* Placeholder for the error description. */
84
+ char error_str [] = "xxx" ;
85
+ char http_response [sizeof (HTTP_500_RESPONSE_TEMPLATE ) +
86
+ sizeof ("xx" ) + /* Content-Length */
87
+ MAX_ERROR_DESC_LEN + 1 ]; /* For the error description */
88
+ const char * error_desc ;
89
+ const char * desc_separator ;
90
+ int desc_len ;
91
+
92
+ if (IS_ENABLED (CONFIG_HTTP_SERVER_REPORT_FAILURE_REASON )) {
93
+ /* Try to fetch error description, fallback to error number if
94
+ * not available
95
+ */
96
+ error_desc = strerror (error_code );
97
+ if (strlen (error_desc ) == 0 ) {
98
+ /* Cast error value to uint8_t to avoid truncation warnings. */
99
+ (void )snprintk (error_str , sizeof (error_str ), "%u" ,
100
+ (uint8_t )error_code );
101
+ error_desc = error_str ;
102
+ }
103
+ desc_separator = ": " ;
104
+ desc_len = MIN (MAX_ERROR_DESC_LEN , strlen (error_desc ));
105
+ desc_len += 2 ; /* For ": " */
106
+ } else {
107
+ error_desc = "" ;
108
+ desc_separator = "" ;
109
+ desc_len = 0 ;
110
+ }
111
+
112
+ (void )snprintk (http_response , sizeof (http_response ),
113
+ HTTP_500_RESPONSE_TEMPLATE ,
114
+ sizeof ("Internal Server Error\r\n" ) - 1 + desc_len ,
115
+ desc_separator , error_desc );
116
+ (void )http_server_sendall (client , http_response , strlen (http_response ));
117
+ }
118
+
74
119
static int handle_http1_static_resource (
75
120
struct http_resource_detail_static * static_detail ,
76
121
struct http_client_ctx * client )
@@ -119,6 +164,8 @@ static int handle_http1_static_resource(
119
164
return ret ;
120
165
}
121
166
167
+ client -> http1_headers_sent = true;
168
+
122
169
ret = http_server_sendall (client , data , len );
123
170
if (ret < 0 ) {
124
171
return ret ;
@@ -483,6 +530,8 @@ int handle_http1_static_fs_resource(struct http_resource_detail_static_fs *stati
483
530
goto close ;
484
531
}
485
532
533
+ client -> http1_headers_sent = true;
534
+
486
535
/* read and send file */
487
536
remaining = file_size ;
488
537
while (remaining > 0 ) {
@@ -545,6 +594,7 @@ static int handle_http1_dynamic_resource(
545
594
return ret ;
546
595
}
547
596
597
+ client -> http1_headers_sent = true;
548
598
dynamic_detail -> holder = NULL ;
549
599
550
600
return 0 ;
@@ -839,12 +889,14 @@ int handle_http1_request(struct http_client_ctx *client)
839
889
840
890
if (parsed > client -> data_len ) {
841
891
LOG_ERR ("HTTP/1 parser error, too much data consumed" );
842
- return - EBADMSG ;
892
+ ret = - EBADMSG ;
893
+ goto error ;
843
894
}
844
895
845
896
if (client -> parser .http_errno != HPE_OK ) {
846
897
LOG_ERR ("HTTP/1 parsing error, %d" , client -> parser .http_errno );
847
- return - EBADMSG ;
898
+ ret = - EBADMSG ;
899
+ goto error ;
848
900
}
849
901
850
902
if (client -> parser_state < HTTP1_RECEIVED_HEADER_STATE ) {
@@ -863,7 +915,8 @@ int handle_http1_request(struct http_client_ctx *client)
863
915
size_t frag_headers_len ;
864
916
865
917
if (parsed < client -> http1_frag_data_len ) {
866
- return - EBADMSG ;
918
+ ret = - EBADMSG ;
919
+ goto error ;
867
920
}
868
921
869
922
frag_headers_len = parsed - client -> http1_frag_data_len ;
@@ -892,36 +945,49 @@ int handle_http1_request(struct http_client_ctx *client)
892
945
893
946
detail -> path_len = path_len ;
894
947
client -> current_detail = detail ;
895
- return handle_http1_to_websocket_upgrade (client );
948
+
949
+ ret = handle_http1_to_websocket_upgrade (client );
950
+ if (ret < 0 ) {
951
+ goto error ;
952
+ }
953
+
954
+ return 0 ;
896
955
}
897
956
898
957
goto upgrade_not_found ;
899
958
}
900
959
901
960
if (client -> http2_upgrade ) {
902
- return handle_http1_to_http2_upgrade (client );
961
+ ret = handle_http1_to_http2_upgrade (client );
962
+ if (ret < 0 ) {
963
+ goto error ;
964
+ }
965
+
966
+ return 0 ;
903
967
}
904
968
905
969
upgrade_not_found :
906
970
ret = http_server_sendall (client , upgrade_required ,
907
971
sizeof (upgrade_required ) - 1 );
908
972
if (ret < 0 ) {
909
973
LOG_DBG ("Cannot write to socket (%d)" , ret );
910
- return ret ;
974
+ goto error ;
911
975
}
912
976
977
+ client -> http1_headers_sent = true;
978
+
913
979
ret = http_server_sendall (client , needed_upgrade ,
914
980
strlen (needed_upgrade ));
915
981
if (ret < 0 ) {
916
982
LOG_DBG ("Cannot write to socket (%d)" , ret );
917
- return ret ;
983
+ goto error ;
918
984
}
919
985
920
986
ret = http_server_sendall (client , upgrade_msg ,
921
987
sizeof (upgrade_msg ) - 1 );
922
988
if (ret < 0 ) {
923
989
LOG_DBG ("Cannot write to socket (%d)" , ret );
924
- return ret ;
990
+ goto error ;
925
991
}
926
992
}
927
993
@@ -934,30 +1000,32 @@ int handle_http1_request(struct http_client_ctx *client)
934
1000
(struct http_resource_detail_static * )detail ,
935
1001
client );
936
1002
if (ret < 0 ) {
937
- return ret ;
1003
+ goto error ;
938
1004
}
939
1005
#if defined(CONFIG_FILE_SYSTEM )
940
1006
} else if (detail -> type == HTTP_RESOURCE_TYPE_STATIC_FS ) {
941
1007
ret = handle_http1_static_fs_resource (
942
1008
(struct http_resource_detail_static_fs * )detail , client );
943
1009
if (ret < 0 ) {
944
- return ret ;
1010
+ goto error ;
945
1011
}
946
1012
#endif
947
1013
} else if (detail -> type == HTTP_RESOURCE_TYPE_DYNAMIC ) {
948
1014
ret = handle_http1_dynamic_resource (
949
1015
(struct http_resource_detail_dynamic * )detail ,
950
1016
client );
951
1017
if (ret < 0 ) {
952
- return ret ;
1018
+ goto error ;
953
1019
}
954
1020
}
955
1021
} else {
956
1022
not_found : ; /* Add extra semicolon to make clang to compile when using label */
957
1023
ret = send_http1_404 (client );
958
1024
if (ret < 0 ) {
959
- return ret ;
1025
+ goto error ;
960
1026
}
1027
+
1028
+ client -> http1_headers_sent = true;
961
1029
}
962
1030
963
1031
client -> cursor += parsed ;
@@ -974,4 +1042,16 @@ not_found: ; /* Add extra semicolon to make clang to compile when using label */
974
1042
}
975
1043
976
1044
return 0 ;
1045
+
1046
+ error :
1047
+ /* Best effort try to send HTTP 500 Internal Server Error response in
1048
+ * case of errors. This can only be done however if we haven't sent
1049
+ * response header elsewhere (i. e. can't send another reply if the
1050
+ * error ocurred amid resource processing).
1051
+ */
1052
+ if (ret != - EAGAIN && !client -> http1_headers_sent ) {
1053
+ send_http1_500 (client , - ret );
1054
+ }
1055
+
1056
+ return ret ;
977
1057
}
0 commit comments