Fix HTTP/2 implementation issues: concurrency, stream management, frame validation, memory safety, and interface improvements

This commit is contained in:
Nick Peng
2025-12-14 18:42:57 +08:00
parent 7bb2ddfcdc
commit a4f170ba10
6 changed files with 444 additions and 215 deletions

View File

@@ -69,7 +69,7 @@ static int _dns_client_send_http2_stream(struct dns_server_info *server_info, st
{"content-length", content_length},
{NULL, NULL}};
if (http2_stream_set_request(http2_stream, "POST", https_flag->path, headers) < 0) {
if (http2_stream_set_request(http2_stream, "POST", https_flag->path, NULL, headers) < 0) {
goto errout;
}

View File

@@ -337,6 +337,11 @@ int http_head_parse_http1_1(struct http_head *http_head, const uint8_t *data, in
return -2;
}
/* Check buffer space */
if (http_head->buff_len + process_data_len + chunk_len >= http_head->buff_size) {
return -3;
}
memcpy(buff_end, data, chunk_len);
body_data_len += chunk_len;
buff_end += chunk_len;

File diff suppressed because it is too large Load Diff

View File

@@ -600,6 +600,14 @@ int http_head_parse_http3_0(struct http_head *http_head, const uint8_t *data, in
http_head->buff_len = 0;
return -3;
}
/* Check buffer space before memcpy */
if ((uint64_t)http_head->buff_len + frame_len > (uint64_t)http_head->buff_size) {
http_head->code_msg = "Receive Buffer Insufficient";
http_head->code = 500;
http_head->data_len = 0;
http_head->buff_len = 0;
return -3;
}
memcpy(http_head->buff + http_head->buff_len, data + offset, frame_len);
http_head->data_len += frame_len;
}
@@ -624,31 +632,52 @@ int http_head_serialize_http3_0(struct http_head *http_head, uint8_t *buffer, in
{
int offset = 0;
int offset_ret = 0;
uint8_t header_data[1024];
uint8_t *header_data = NULL;
int header_data_size = 1024;
int header_data_len = 0;
int result = -1;
header_data = malloc(header_data_size);
if (!header_data) {
goto cleanup;
}
/* serialize header frame. */
header_data_len = _http3_build_headers_payload(http_head, header_data, sizeof(header_data));
header_data_len = _http3_build_headers_payload(http_head, header_data, header_data_size);
if (header_data_len < 0) {
return -1;
goto cleanup;
}
/* If header_data_len > header_data_size, realloc */
if (header_data_len > header_data_size) {
uint8_t *new_header_data = realloc(header_data, header_data_len);
if (!new_header_data) {
goto cleanup;
}
header_data = new_header_data;
header_data_size = header_data_len;
header_data_len = _http3_build_headers_payload(http_head, header_data, header_data_size);
if (header_data_len < 0) {
goto cleanup;
}
}
/* Frame Type: Header*/
offset_ret = _quicvarint_encode(HTTP3_HEADER_FRAME, buffer + offset, buffer_len - offset);
if (offset_ret < 0) {
return -1;
goto cleanup;
}
offset += offset_ret;
/* Header Frmae Length */
/* Header Frame Length */
offset_ret = _quicvarint_encode(header_data_len, buffer + offset, buffer_len - offset);
if (offset_ret < 0) {
return -1;
goto cleanup;
}
offset += offset_ret;
if (buffer_len - offset < header_data_len) {
return -1;
goto cleanup;
}
memcpy(buffer + offset, header_data, header_data_len);
offset += header_data_len;
@@ -658,17 +687,23 @@ int http_head_serialize_http3_0(struct http_head *http_head, uint8_t *buffer, in
/* Data Frame Length */
offset_ret = _quicvarint_encode(HTTP3_DATA_FRAME, buffer + offset, buffer_len - offset);
if (offset_ret < 0) {
return -1;
goto cleanup;
}
offset += offset_ret;
offset_ret =
http3_build_body_payload(http_head->data, http_head->data_len, buffer + offset, buffer_len - offset);
if (offset_ret < 0) {
return -1;
goto cleanup;
}
offset += offset_ret;
}
return offset;
result = offset;
cleanup:
if (header_data) {
free(header_data);
}
return result;
}

View File

@@ -215,11 +215,12 @@ struct http2_header_pair {
* @param stream Stream
* @param method HTTP method (e.g., "GET", "POST")
* @param path Request path
* @param scheme Scheme (e.g., "https"), if NULL defaults to "https"
* @param headers Array of additional headers (NULL-terminated, last element must have name=NULL)
* @return 0 on success, -1 on error
*/
int http2_stream_set_request(struct http2_stream *stream, const char *method, const char *path,
const struct http2_header_pair *headers);
const char *scheme, const struct http2_header_pair *headers);
/**
* Server: Set response headers

View File

@@ -170,7 +170,7 @@ TEST_F(LIBHTTP2, Integrated)
// Send request
struct http2_header_pair headers[] = {
{"content-type", "application/json"}, {"content-length", "27"}, {NULL, NULL}};
http2_stream_set_request(stream, "POST", "/echo", headers);
http2_stream_set_request(stream, "POST", "/echo", NULL, headers);
const char *request_body = "{\"message\":\"Hello Echo!\"}";
http2_stream_write_body(stream, (const uint8_t *)request_body, strlen(request_body), 1);
@@ -316,7 +316,7 @@ TEST_F(LIBHTTP2, MultiStream)
struct http2_header_pair headers[] = {
{"content-type", "text/plain"}, {"content-length", content_length}, {NULL, NULL}};
http2_stream_set_request(streams[i], "POST", path, headers);
http2_stream_set_request(streams[i], "POST", path, NULL, headers);
http2_stream_write_body(streams[i], (const uint8_t *)body, body_len, 1);
}
@@ -451,7 +451,7 @@ TEST_F(LIBHTTP2, EarlyStreamCreation)
// Send request immediately (before handshake)
struct http2_header_pair headers[] = {{"user-agent", "test-client"}, {NULL, NULL}};
int ret = http2_stream_set_request(stream, "POST", "/early-test", headers);
int ret = http2_stream_set_request(stream, "POST", "/early-test", NULL, headers);
EXPECT_EQ(ret, 0) << "Failed to set request";
const char *request_body = "test echo";
http2_stream_write_body(stream, (const uint8_t *)request_body, strlen(request_body), 1);
@@ -612,7 +612,7 @@ TEST_F(LIBHTTP2, ServerLoopTerminationOnDisconnect)
ASSERT_NE(stream, nullptr);
struct http2_header_pair headers[] = {{"content-type", "text/plain"}, {NULL, NULL}};
http2_stream_set_request(stream, "POST", "/test", headers);
http2_stream_set_request(stream, "POST", "/test", NULL, headers);
http2_stream_write_body(stream, (const uint8_t *)"test", 4, 1);
http2_stream_close(stream);
http2_ctx_close(ctx);
@@ -699,7 +699,7 @@ TEST_F(LIBHTTP2, StreamClose)
ASSERT_NE(stream, nullptr);
// Send request
http2_stream_set_request(stream, "GET", "/test", NULL);
http2_stream_set_request(stream, "GET", "/test", NULL, NULL);
http2_stream_write_body(stream, NULL, 0, 1);
// Wait for response
@@ -918,7 +918,7 @@ TEST_F(LIBHTTP2, StressTest)
int body_len = snprintf(body, sizeof(body), "Req %d", i);
struct http2_header_pair headers[] = {{"content-type", "text/plain"}, {NULL, NULL}};
http2_stream_set_request(stream, "POST", path, headers);
http2_stream_set_request(stream, "POST", path, NULL, headers);
http2_stream_write_body(stream, (const uint8_t *)body, body_len, 1);
}