Skip to content

Commit 0c61bdd

Browse files
net.http: reject END_STREAM on a 1xx response in H2Conn.read_response
A 1xx informational response is not final and must not end the stream (RFC 9113 §8.1). The synchronous client discarded a 1xx HEADERS frame with a bare `continue`, skipping the `if frame.end_stream { break }` handling, so a 1xx carrying END_STREAM made read_response loop back to next_frame() and wait forever for a final response the stream could no longer send — a malformed server could hang the request instead of getting an error. Reject END_STREAM in the 1xx interim branch, matching the mux path (H2MuxConn.on_response_headers), which already rejects it. Found by Codex on #27413. Co-Authored-By: WOZCODE <contact@withwoz.com>
1 parent a6884ce commit 0c61bdd

1 file changed

Lines changed: 9 additions & 0 deletions

File tree

vlib/net/http/h2_conn.v

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,15 @@ fn (mut c H2Conn) read_response(stream_id u32, req H2ClientRequest) !H2ClientRes
216216
if status >= 100 && status < 200 {
217217
// 1xx informational: discard and continue waiting for the
218218
// final HEADERS block. Do not set got_headers here.
219+
// A 1xx is not a final response and must not end the stream
220+
// (RFC 9113 §8.1); END_STREAM here is malformed. Fail rather
221+
// than loop forever waiting for a final response the stream can
222+
// no longer send. (The mux path rejects this as a stream-level
223+
// PROTOCOL_ERROR; the synchronous client has no other stream to
224+
// keep alive, so a connection-level error is appropriate here.)
225+
if frame.end_stream {
226+
return error('h2: server set END_STREAM on a 1xx informational response')
227+
}
219228
continue
220229
}
221230
// Second pass: populate the response. Skip pseudo-headers.

0 commit comments

Comments
 (0)