Skip to content

Commit 8e733b8

Browse files
committed
Add support for keylogging with HTTP/2
1 parent 3b1ece1 commit 8e733b8

File tree

2 files changed

+41
-8
lines changed

2 files changed

+41
-8
lines changed

src/rules/requests/request-step-impls.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Writable } from 'stream';
33
import * as url from 'url';
44
import type * as dns from 'dns';
55
import * as net from 'net';
6+
import * as tls from 'tls';
67
import * as http from 'http';
78
import * as https from 'https';
89

@@ -401,6 +402,9 @@ const mapOmitToUndefined = <T extends { [key: string]: any }>(
401402
: v
402403
);
403404

405+
// Only used if key logging is enabled, meaning we need to hook into http2-wrapper's TLS setup:
406+
const h2ProtocolQueue = new Map();
407+
404408
export class PassThroughStepImpl extends PassThroughStep {
405409

406410
private _trustedCACertificates: MaybePromise<Array<string> | undefined>;
@@ -697,8 +701,21 @@ export class PassThroughStepImpl extends PassThroughStep {
697701

698702
let makeRequest = (
699703
shouldTryH2Upstream
700-
? (options: any, cb: any) =>
701-
h2Client.auto(options, cb).catch((e) => {
704+
? (reqOpts: any, cb: any) =>
705+
h2Client.auto({
706+
...reqOpts,
707+
resolveProtocol: options.keyLogStream
708+
// Wrap TLS setup in key logging:
709+
? h2Client.auto.createResolveProtocol(
710+
h2Client.auto.protocolCache as any,
711+
h2ProtocolQueue,
712+
function (...args) {
713+
const socket = tls.connect(...args);
714+
socket.on('keylog', (line) => options.keyLogStream!.write(line));
715+
return socket;
716+
}
717+
) : undefined,
718+
}, cb).catch((e) => {
702719
// If an error occurs during auto detection via ALPN, that's an
703720
// TypeError implies it's an invalid HTTP/2 request that was rejected.
704721
// Anything else implies an upstream HTTP/2 issue.
@@ -1067,9 +1084,7 @@ export class PassThroughStepImpl extends PassThroughStep {
10671084
if (this.outgoingSockets.has(socket)) return;
10681085

10691086
if (options.keyLogStream) {
1070-
socket.on('keylog', (line) => {
1071-
options.keyLogStream!.write(line);
1072-
});
1087+
socket.on('keylog', (line) => options.keyLogStream!.write(line));
10731088
}
10741089

10751090
// Add this port to our list of active ports, once it's connected (before then it has no port)

test/integration/https.spec.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import * as http from 'http';
21
import * as tls from 'tls';
2+
import * as http from 'http';
33
import * as https from 'https';
4+
import * as http2 from 'http2';
45
import * as fs from 'fs/promises';
56
import * as tmp from 'tmp-promise';
67
import * as WebSocket from 'isomorphic-ws';
@@ -13,7 +14,8 @@ import {
1314
delay,
1415
openRawSocket,
1516
openRawTlsSocket,
16-
http2ProxyRequest
17+
http2ProxyRequest,
18+
getHttp2Response
1719
} from "../test-utils";
1820
import { streamToBuffer } from '../../src/util/buffer-utils';
1921

@@ -541,7 +543,23 @@ describe("When configured for HTTPS", () => {
541543
expect(keyLogContents).to.include('SERVER_TRAFFIC_SECRET_0');
542544
});
543545

544-
it("should log upstream WebSocket TLS keys to the file", async () => {
546+
it("should log upstream HTTP/2 TLS keys to the file", async () => {
547+
// Make an HTTP request, but proxy to an HTTP2-only HTTPS server:
548+
await server.forGet('/').thenForwardTo('https://http2.testserver.host');
549+
550+
const client = http2.connect(`http://localhost:${server.port}`);
551+
const req = client.request();
552+
await getHttp2Response(req);
553+
554+
const keyLogContents = await fs.readFile(keyLogFile, 'utf8');
555+
556+
expect(keyLogContents).to.include('CLIENT_HANDSHAKE_TRAFFIC_SECRET');
557+
expect(keyLogContents).to.include('SERVER_HANDSHAKE_TRAFFIC_SECRET');
558+
expect(keyLogContents).to.include('CLIENT_TRAFFIC_SECRET_0');
559+
expect(keyLogContents).to.include('SERVER_TRAFFIC_SECRET_0');
560+
});
561+
562+
it("should log upstream WebSocket HTTP/2 TLS keys to the file", async () => {
545563
await server.forAnyWebSocket().thenForwardTo(remoteNonLoggingServer.url);
546564
await remoteNonLoggingServer.forAnyWebSocket().thenEcho();
547565

0 commit comments

Comments
 (0)