Files
evening_detective_screen/scripts/network-headers-smoke.cjs
T
2026-10-19 00:03:48 +07:00

119 lines
6.2 KiB
JavaScript

const assert = require('node:assert/strict')
const { createServer } = require('node:http')
const { app, net, session } = require('electron')
const { mkdtemp, rm } = require('node:fs/promises')
const { join } = require('node:path')
const { tmpdir } = require('node:os')
const { fetchNetwork } = require('../dist-electron/electron/network-fetch.js')
const { PackageStore } = require('../dist-electron/electron/package-store.js')
const { buildScreenPackage } = require('../dist-electron/electron/screen-package.js')
const { prepareFetchHeaders } = require('../dist-electron/electron/response-headers.js')
app.whenReady().then(async () => {
prepareFetchHeaders(session.defaultSession)
const requests = []
const bytes = Buffer.from('RIFFtest-WAVE')
const directory = await mkdtemp(join(tmpdir(), 'screen-network-'))
const server = createServer((request, response) => {
requests.push(request.url)
const headers = { 'X-Name': Buffer.from('пример').toString('latin1') }
const path = new URL(request.url, 'http://localhost').pathname
assert.equal(request.headers.authorization, undefined)
assert.equal(request.headers.cookie, undefined)
if (path === '/api/echo') {
const parts = []
request.on('data', (chunk) => parts.push(chunk))
request.on('end', () => {
response.writeHead(200, { 'Content-Type': 'application/json' })
response.end(Buffer.concat(parts))
})
} else if (path === '/redirect') {
response.writeHead(302, { ...headers, Location: `/${encodeURIComponent('пример')}` })
response.end()
} else if (path === '/absolute') {
response.writeHead(307, { Location: `http://127.0.0.1:${server.address().port}/file.wav` })
response.end()
} else if (path === '/unsafe') {
response.writeHead(302, { Location: 'file:///tmp/secret.wav' })
response.end()
} else if (path === '/waiting') {
return
} else if (path === '/stream') {
response.writeHead(200, { 'Content-Type': 'audio/wav' })
response.write(bytes)
} else if (path === '/broken') {
response.writeHead(200, { 'Content-Type': 'audio/wav' })
response.write(bytes)
setTimeout(() => response.destroy(), 20)
} else if (path === '/file.wav' || path.startsWith('/%')) {
response.writeHead(200, { 'Content-Type': 'audio/wav' })
response.end(bytes)
} else if (path === '/status') {
response.writeHead(200, Buffer.from('Привет').toString('latin1'), { 'Content-Type': 'text/plain' })
response.end('ok')
} else {
response.writeHead(200, { ...headers, 'Content-Type': 'text/plain' })
response.end('ok')
}
})
try {
await new Promise((resolve, reject) => {
server.once('error', reject)
server.listen(0, '127.0.0.1', resolve)
})
const url = `http://127.0.0.1:${server.address().port}`
const response = await net.fetch(url)
assert.equal(response.headers.get('x-name'), encodeURIComponent('пример'))
assert.equal(response.headers.get('content-type'), 'text/plain')
assert.equal(await response.text(), 'ok')
const echo = await fetchNetwork(`${url}/api/echo`, { method: 'POST', body: JSON.stringify({ text: 'Привет' }), headers: { 'Content-Type': 'application/json' }, redirect: 'error', credentials: 'omit' })
assert.deepEqual(await echo.json(), { text: 'Привет' })
const followed = await net.fetch(`${url}/redirect`)
assert.deepEqual(Buffer.from(await followed.arrayBuffer()), bytes)
const unicodeStatus = await fetchNetwork(`${url}/status`)
assert.equal(unicodeStatus.status, 200)
assert.equal(await unicodeStatus.text(), 'ok')
const manual = await fetchNetwork(`${url}/redirect`, { redirect: 'manual', credentials: 'omit' })
assert.equal(manual.status, 302)
assert.ok(manual.headers.get('location').endsWith(encodeURIComponent('пример')))
const store = new PackageStore(directory, { fetch: fetchNetwork, wait: async () => {} })
await store.initialize()
const description = (base, name) => buildScreenPackage(base, 7, { game: { game: { ID: 7, name: 'Network smoke', scenario: { story: { introduction: { audio: `${base}/${name}` } } } } }, plan: { plan: { steps: [] } }, music: {} })
for (const name of ['redirect', 'absolute']) {
const pkg = await store.download(description(url, name))
assert.equal(pkg.files.length, 1)
assert.equal(pkg.files[0].size, bytes.length)
}
await assert.rejects(store.download(description(url, 'unsafe')), /адрес|редирект/)
const aborted = new AbortController()
aborted.abort()
await assert.rejects(fetchNetwork(`${url}/waiting`, { redirect: 'manual', credentials: 'omit', signal: aborted.signal }))
await assert.rejects(fetchNetwork(`${url}/waiting`, { redirect: 'manual', credentials: 'omit', signal: AbortSignal.timeout(30) }))
const streamingAbort = new AbortController()
const streaming = await fetchNetwork(`${url}/stream`, { redirect: 'manual', credentials: 'omit', signal: streamingAbort.signal })
const reader = streaming.body.getReader()
assert.deepEqual(Buffer.from((await reader.read()).value), bytes)
streamingAbort.abort()
await assert.rejects(reader.read())
const brokenTimeout = AbortSignal.timeout(1000)
const broken = await fetchNetwork(`${url}/broken`, { redirect: 'manual', credentials: 'omit', signal: brokenTimeout })
await assert.rejects(broken.arrayBuffer())
assert.equal(brokenTimeout.aborted, false)
await session.defaultSession.setProxy({ proxyRules: `http=127.0.0.1:${server.address().port}`, proxyBypassRules: '<-loopback>' })
const proxied = await net.fetch('http://headers-proxy.invalid/example')
assert.equal(await proxied.text(), 'ok')
assert.ok(requests.includes('http://headers-proxy.invalid/example'))
const proxiedPackage = await store.download(description('http://headers-proxy.invalid', 'redirect'))
assert.equal(proxiedPackage.files[0].size, bytes.length)
assert.ok(requests.includes('http://headers-proxy.invalid/redirect'))
await rm(directory, { recursive: true, force: true })
console.log('SCREEN_NETWORK_HEADERS_PASS')
app.exit(0)
} catch (error) {
console.error(error)
app.exit(1)
} finally {
server.close()
}
})