Skip to content

Commit 0e01ebd

Browse files
committed
Handle framing automatically when downgrading proxied H2 traffic to H1
If you send an HTTP/2 request that likely has a body (we can't tell initially) with no framing headers, we enable chunked encoding to ensure any received body can be handled as expected. This might be subtly breaking in some cases but should be semantically identical to the existing behaviour for all valid requests.
1 parent e45d023 commit 0e01ebd

File tree

2 files changed

+14
-2
lines changed

2 files changed

+14
-2
lines changed

src/rules/requests/request-handlers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ export class PassThroughHandler extends PassThroughHandlerDefinition {
738738
MODIFIABLE_PSEUDOHEADERS.includes(key.toLowerCase() as any)
739739
);
740740
} else if (isH2Downstream && !shouldTryH2Upstream) {
741-
rawHeaders = h2HeadersToH1(rawHeaders);
741+
rawHeaders = h2HeadersToH1(rawHeaders, method);
742742
}
743743

744744
let serverReq: http.ClientRequest;

src/util/header-utils.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ export function updateRawHeaders(
218218

219219
// See https://httptoolkit.com/blog/translating-http-2-into-http-1/ for details on the
220220
// transformations required between H2 & H1 when proxying.
221-
export function h2HeadersToH1(h2Headers: RawHeaders): RawHeaders {
221+
export function h2HeadersToH1(h2Headers: RawHeaders, method: string): RawHeaders {
222222
let h1Headers = h2Headers.filter(([key]) => key[0] !== ':');
223223

224224
if (!findRawHeader(h1Headers, 'host') && findRawHeader(h2Headers, ':authority')) {
@@ -233,6 +233,18 @@ export function h2HeadersToH1(h2Headers: RawHeaders): RawHeaders {
233233
h1Headers.push(['Cookie', cookieHeaders.join('; ')]);
234234
}
235235

236+
// We don't know if the request has a body yet - but just in case, we ensure it could:
237+
if (
238+
// If the request is a method that probably has a body
239+
method !== 'GET' &&
240+
method !== 'HEAD' &&
241+
!( // And you haven't set any kind of framing headers:
242+
findRawHeader(h1Headers, 'content-length') ||
243+
findRawHeader(h1Headers, 'transfer-encoding')?.includes('chunked'))
244+
) { // Add transfer-encoding chunked, which should support all possible cases:
245+
h1Headers.push(['Transfer-Encoding', 'chunked']);
246+
}
247+
236248
return h1Headers;
237249
}
238250

0 commit comments

Comments
 (0)