Skip to content

Commit

Permalink
Include :status in HTTP/2 response event subscription data
Browse files Browse the repository at this point in the history
  • Loading branch information
pimterry committed Apr 30, 2024
1 parent 6283b1e commit 02752e5
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/util/request-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,10 @@ export function trackResponse(
writtenHeaders = objectHeadersToRaw(headersArg ?? {});
}

if (isHttp2(trackedResponse)) {
writtenHeaders.unshift([':status', args[0].toString()]);
}

// Headers might also have been set with setHeader before. They'll be combined, with headers
// here taking precendence. We simulate this by pulling in all values from getHeaders() and
// remembering any of those that we're not about to override.
Expand Down
55 changes: 54 additions & 1 deletion test/integration/http2.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as semver from 'semver';
import * as fs from 'fs';
import * as portfinder from 'portfinder';

import { CompletedRequest, getLocal } from "../..";
import { CompletedRequest, CompletedResponse, getLocal } from "../..";
import {
expect,
nodeOnly,
Expand Down Expand Up @@ -461,6 +461,59 @@ nodeOnly(() => {
await cleanup(proxiedClient, client);
});

it("should include should metadata in events for proxied HTTP/2 responses", async function() {
if (!semver.satisfies(process.version, H2_TLS_ON_TLS_SUPPORTED)) this.skip();

let seenResponsePromise = getDeferred<CompletedResponse>();
await server.on('response', (r) => seenResponsePromise.resolve(r));

await server.forGet('https://example.com/mocked-endpoint')
.thenReply(200, "Proxied HTTP2 response!", {
'TEST-header': 'value'
});

const client = http2.connect(server.url);

const req = client.request({
':method': 'CONNECT',
':authority': 'example.com:443'
});

// Initial response, the proxy has set up our tunnel:
const responseHeaders = await getHttp2Response(req);
expect(responseHeaders[':status']).to.equal(200);

// We can now read/write to req as a raw TCP socket to example.com:
const proxiedClient = http2.connect('https://example.com', {
// Tunnel this request through the proxy stream
createConnection: () => tls.connect({
socket: req as any,
ALPNProtocols: ['h2']
})
});

const proxiedRequest = proxiedClient.request({
':path': '/mocked-endpoint'
});
await getHttp2Response(proxiedRequest);
await getHttp2Body(proxiedRequest)

const seenResponse = await seenResponsePromise;
expect(seenResponse.statusCode).to.equal(200);
expect(seenResponse.statusMessage).to.equal('');
expect(seenResponse.headers).to.deep.equal({
':status': '200',
'test-header': 'value'
});
expect(seenResponse.rawHeaders).to.deep.equal([
[':status', '200'],
['TEST-header', 'value']
]);
expect(await seenResponse.body.getText()).to.equal('Proxied HTTP2 response!');

await cleanup(proxiedClient, client);
});

it("can respond to HTTP1-proxied HTTP/2 requests", async function() {
if (!semver.satisfies(process.version, H2_TLS_ON_TLS_SUPPORTED)) this.skip();

Expand Down

0 comments on commit 02752e5

Please sign in to comment.