Skip to content

Commit 42cffd9

Browse files
committed
refactor(rsc-mf): share safe proxy response helper
1 parent b3ea214 commit 42cffd9

4 files changed

Lines changed: 61 additions & 24 deletions

File tree

tests/integration/rsc-mf/host/server/modern.server.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
isExposeAssetRequestPath,
1111
resolveManifestFallbackAssetPath,
1212
} from '../../shared/manifestFallback';
13+
import { createSafeProxyResponse } from '../../shared/proxyResponse';
1314

1415
const REMOTE_MANIFEST_PATH = '/static/mf-manifest.json';
1516

@@ -99,17 +100,6 @@ const shouldProxyRemoteAsset = (pathname: string) => {
99100
return false;
100101
};
101102

102-
const createProxyResponse = (upstream: Response) => {
103-
const headers = new Headers(upstream.headers);
104-
headers.delete('content-length');
105-
headers.delete('content-encoding');
106-
headers.delete('transfer-encoding');
107-
return new Response(upstream.body, {
108-
status: upstream.status,
109-
headers,
110-
});
111-
};
112-
113103
const proxyRemoteFederationAsset: MiddlewareHandler = async (c, next) => {
114104
const requestHeaders = c.req.headers;
115105
const isInternalFallbackFetch =
@@ -151,7 +141,7 @@ const proxyRemoteFederationAsset: MiddlewareHandler = async (c, next) => {
151141
return;
152142
}
153143

154-
c.res = createProxyResponse(resolvedUpstream);
144+
c.res = createSafeProxyResponse(resolvedUpstream);
155145
};
156146

157147
export default defineServerConfig({

tests/integration/rsc-mf/remote/server/modern.server.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,10 @@ import {
1010
isExposeAssetRequestPath,
1111
resolveManifestFallbackAssetPath,
1212
} from '../../shared/manifestFallback';
13+
import { createSafeProxyResponse } from '../../shared/proxyResponse';
1314

1415
const REMOTE_MANIFEST_PATH = '/static/mf-manifest.json';
1516

16-
const createProxyResponse = (upstream: Response) => {
17-
const headers = new Headers(upstream.headers);
18-
headers.delete('content-length');
19-
headers.delete('content-encoding');
20-
headers.delete('transfer-encoding');
21-
return new Response(upstream.body, {
22-
status: upstream.status,
23-
headers,
24-
});
25-
};
26-
2717
const recoverRemoteExposeAssetMiddleware: MiddlewareHandler = async (
2818
c,
2919
next,
@@ -96,7 +86,7 @@ const recoverRemoteExposeAssetMiddleware: MiddlewareHandler = async (
9686
return;
9787
}
9888

99-
c.res = createProxyResponse(fallbackAssetResponse);
89+
c.res = createSafeProxyResponse(fallbackAssetResponse);
10090
};
10191

10292
export default defineServerConfig({
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const HOP_BY_HOP_RESPONSE_HEADERS = [
2+
'content-length',
3+
'content-encoding',
4+
'transfer-encoding',
5+
];
6+
7+
export const createSafeProxyResponse = (upstream: Response) => {
8+
const headers = new Headers(upstream.headers);
9+
for (const headerName of HOP_BY_HOP_RESPONSE_HEADERS) {
10+
headers.delete(headerName);
11+
}
12+
return new Response(upstream.body, {
13+
status: upstream.status,
14+
headers,
15+
});
16+
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { createSafeProxyResponse } from '../shared/proxyResponse';
2+
3+
describe('rsc-mf proxy response helper', () => {
4+
it('removes hop-by-hop response headers while preserving payload', async () => {
5+
const upstream = new Response('proxied-body', {
6+
status: 202,
7+
headers: {
8+
'content-type': 'application/javascript',
9+
'content-length': '999',
10+
'content-encoding': 'gzip',
11+
'transfer-encoding': 'chunked',
12+
},
13+
});
14+
15+
const proxied = createSafeProxyResponse(upstream);
16+
17+
expect(proxied.status).toBe(202);
18+
expect(proxied.headers.get('content-type')).toBe('application/javascript');
19+
expect(proxied.headers.get('content-length')).toBeNull();
20+
expect(proxied.headers.get('content-encoding')).toBeNull();
21+
expect(proxied.headers.get('transfer-encoding')).toBeNull();
22+
await expect(proxied.text()).resolves.toBe('proxied-body');
23+
});
24+
25+
it('keeps unrelated response headers intact', () => {
26+
const upstream = new Response('ok', {
27+
status: 200,
28+
headers: {
29+
'cache-control': 'public,max-age=31536000',
30+
etag: '"abc123"',
31+
},
32+
});
33+
34+
const proxied = createSafeProxyResponse(upstream);
35+
36+
expect(proxied.headers.get('cache-control')).toBe(
37+
'public,max-age=31536000',
38+
);
39+
expect(proxied.headers.get('etag')).toBe('"abc123"');
40+
});
41+
});

0 commit comments

Comments
 (0)