Files
EdgeSSH/tests/forwarding-mounted.test.ts
T
gdz66601 5d65b34907 feat: add selectable forwarding modes and optional preview deployment
默认使用可信同源路径转发,支持界面切换隔离预览并按需部署。
2026-09-24 20:41:44 +08:00

67 lines
3.7 KiB
TypeScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtemp, writeFile, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { build } from 'esbuild';
import { Miniflare } from 'miniflare';
import { mountCookie, mountCSS } from '../src/forwarding/mount.ts';
const root = 'https://preview.example';
const base = '/_forward/64a';
test('mounted proxy rewrites HTML/CSS through real HTMLRewriter and scopes headers', async () => {
const dir = await mkdtemp(join(tmpdir(), 'edgessh-mounted-'));
const entry = join(dir, 'worker.ts');
const output = join(dir, 'worker.js');
await writeFile(entry, `
import { proxyHTTP } from ${JSON.stringify(join(process.cwd(), 'src/forwarding/http.ts'))};
const encoder = new TextEncoder();
const html = '<!doctype html><html><head><title>x</title></head><body style="background:url(/bg.png)"><a href="/next">a</a><img src="http://127.0.0.1:8080/i.png"><form action="/go" formaction="/alt"><img srcset="/a.png 1x, data:image/png;base64,AA 2x"></form><style>@import url("/theme.css"); .x{background:url(/x.png)}</style></body></html>';
class Channel {
readable = new ReadableStream({ start(c) { c.enqueue(encoder.encode('HTTP/1.1 302 Found\\r\\nContent-Type: text/html\\r\\nContent-Length: '+new TextEncoder().encode(html).length+'\\r\\nSet-Cookie: sid=abc; Path=/; Max-Age=10; Expires=Wed, 21 Oct 2030 07:28:00 GMT\\r\\nSet-Cookie: __Host-edgessh-session=bad; Path=/\\r\\nLocation: ../login\\r\\n\\r\\n'+html)); c.close(); } });
async write() {} async close() {} abort() {}
}
export default { async fetch(request) { return proxyHTTP(new Channel(), request, 8080, '${root}', '${base}'); } };
`);
let mf: Miniflare | undefined;
try {
await build({ entryPoints: [entry], outfile: output, bundle: true, format: 'esm', platform: 'neutral', sourcemap: false });
const bundleJS = await (await import('node:fs/promises')).readFile(output, 'utf8');
mf = new Miniflare({ workers: [{ config: {
type: 'worker',
name: 'test',
compatibilityDate: '2026-07-01',
manifest: {
mainModule: 'worker.js',
modulesRoot: dir,
modules: { 'worker.js': { type: 'esm', contents: bundleJS } },
},
} }] });
const response = await mf.dispatchFetch(`${root}${base}/dir/page`, {
redirect: 'manual',
headers: { 'x-preview-path': '/dir/page' },
});
const text = await response.text();
assert.equal(response.status, 302);
assert.match(text, /href="\/_forward\/64a\/next"/);
assert.match(text, /src="https:\/\/preview\.example\/_forward\/64a\/i\.png"/);
assert.match(text, /action="\/_forward\/64a\/go"/);
assert.match(text, /formaction="\/_forward\/64a\/alt"/);
assert.match(text, /srcset="\/_forward\/64a\/a\.png 1x, data:image\/png;base64,AA 2x"/);
assert.match(text, /style="background:url\(\/_forward\/64a\/bg\.png\)"/);
assert.equal((text.match(/__edgessh\/runtime\.js/g) ?? []).length, 1);
assert.equal(response.headers.get('location'), `${root}${base}/login`);
assert.deepEqual(response.headers.getSetCookie(), [`ef_64a_sid=abc; Path=${base}/; Secure; Max-Age=10`]);
} finally {
await mf?.dispose();
await rm(dir, { recursive: true, force: true });
}
});
test('mounted CSS and cookie helpers preserve URL semantics', () => {
assert.equal(mountCSS('@import "/a.css";x{background:url(https://x.test/a)}', 8080, root, base), `@import "${base}/a.css";x{background:url(https://x.test/a)}`);
assert.match(mountCookie('sid=x; Expires=Wed, 21 Oct 2030 07:28:00 GMT', base, '/dir/page')!, new RegExp(`Path=${base}/dir;`));
assert.match(mountCookie('sid=x; Max-Age=10; Expires=Wed, 21 Oct 2030 07:28:00 GMT', base)!, /Max-Age=10/);
});