fix
This commit is contained in:
@@ -25,6 +25,7 @@ import { Online } from './online.js'
|
||||
import type { OnlineState } from '../src/types/online.js'
|
||||
import { PackageStore } from './package-store.js'
|
||||
import { packageMediaResponse } from './package-media.js'
|
||||
import { prepareFetchHeaders } from './response-headers.js'
|
||||
import type { HostInfo } from '../src/types/screen.js'
|
||||
|
||||
// Ozone выбирается до main.js; поздний appendSwitch смешивает Wayland и X11.
|
||||
@@ -334,6 +335,7 @@ app
|
||||
diagnostics.record('settings-error')
|
||||
hostNotice = error instanceof Error ? error.message : 'Не удалось восстановить окна'
|
||||
}
|
||||
prepareFetchHeaders(session.defaultSession)
|
||||
const fetchNetwork: typeof fetch = (input, init) =>
|
||||
net.fetch(input instanceof URL ? input.href : input, init)
|
||||
const packages = new PackageStore(join(app.getPath('userData'), 'packages'), {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { test } from 'node:test'
|
||||
import { byteStringResponseHeaders } from './response-headers.js'
|
||||
|
||||
test('заголовки с кириллицей совместимы с Headers, обычные значения сохраняются', () => {
|
||||
const original = {
|
||||
'X-Name': ['пример'],
|
||||
Location: ['https://media.test/папка/трек.mp3?name=%D0%B0'],
|
||||
'Content-Disposition': ['attachment; filename="пример.mp3"'],
|
||||
'Content-Length': ['1024'],
|
||||
'Content-Type': ['audio/wav'],
|
||||
'X-Latin': ['caf\u00e9'],
|
||||
'Set-Cookie': ['a=1', 'b=2'],
|
||||
}
|
||||
const result = byteStringResponseHeaders(original)
|
||||
const headers = new Headers(Object.fromEntries(Object.entries(result).map(([name, values]) => [name, values.join(', ')])))
|
||||
assert.equal(headers.get('x-name'), encodeURIComponent('пример'))
|
||||
assert.equal(headers.get('location'), new URL(original.Location[0]!).href)
|
||||
assert.equal(result['Content-Disposition']![0], `attachment; filename="${encodeURIComponent('пример')}.mp3"`)
|
||||
for (const name of ['Content-Length', 'Content-Type', 'X-Latin', 'Set-Cookie'] as const)
|
||||
assert.deepEqual(result[name], original[name])
|
||||
assert.equal(original['X-Name'][0], 'пример')
|
||||
assert.deepEqual(byteStringResponseHeaders(), {})
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
export function byteStringResponseHeaders(headers: Record<string, string[]> = {}) {
|
||||
return Object.fromEntries(Object.entries(headers).map(([name, values]) => [
|
||||
name,
|
||||
values.map((value) => value.replace(/[^\x00-\xff]+/gu, encodeURIComponent)),
|
||||
]))
|
||||
}
|
||||
|
||||
export function prepareFetchHeaders(target: Electron.Session) {
|
||||
// Electron net.fetch throws outside its promise when a response header contains Unicode.
|
||||
target.webRequest.onHeadersReceived((details, callback) => {
|
||||
callback({ responseHeaders: byteStringResponseHeaders(details.responseHeaders) })
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
const assert = require('node:assert/strict')
|
||||
const { createServer } = require('node:http')
|
||||
const { app, net, session } = require('electron')
|
||||
const { prepareFetchHeaders } = require('../dist-electron/electron/response-headers.js')
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
prepareFetchHeaders(session.defaultSession)
|
||||
const requests = []
|
||||
const server = createServer((request, response) => {
|
||||
requests.push(request.url)
|
||||
const headers = { 'X-Name': Buffer.from('пример').toString('latin1') }
|
||||
if (request.url === '/redirect') {
|
||||
response.writeHead(302, { ...headers, Location: `/${encodeURIComponent('пример')}` })
|
||||
response.end()
|
||||
} 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 followed = await net.fetch(`${url}/redirect`)
|
||||
assert.equal(await followed.text(), 'ok')
|
||||
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'))
|
||||
console.log('SCREEN_NETWORK_HEADERS_PASS')
|
||||
app.exit(0)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
app.exit(1)
|
||||
} finally {
|
||||
server.close()
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user