mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-13 20:56:19 -08:00
Decode HTTP Content-Encoding for EPG XMLTV streams before SAX parsing and harden gzip payload handling for mislabelled providers. Validation: - pnpm nx test electron-backend --testFile=epg-stream-decoder.spec.ts - pnpm nx test electron-backend --testFile=epg-response-utils.spec.ts - pnpm nx test electron-backend - pnpm nx lint electron-backend - pnpm nx run electron-backend:build-worker
119 lines
3.6 KiB
TypeScript
119 lines
3.6 KiB
TypeScript
import {
|
|
getEpgResponseContentEncoding,
|
|
shouldGunzipEpgResponse,
|
|
} from './epg-response-utils';
|
|
|
|
describe('shouldGunzipEpgResponse', () => {
|
|
it('returns true for original .gz URLs', () => {
|
|
expect(
|
|
shouldGunzipEpgResponse('https://example.com/guide.xml.gz', {
|
|
headers: new Headers(),
|
|
url: 'https://example.com/guide.xml.gz',
|
|
})
|
|
).toBe(true);
|
|
});
|
|
|
|
it('returns true when a redirect lands on a .gz URL', () => {
|
|
expect(
|
|
shouldGunzipEpgResponse('http://epg.vcboy.com', {
|
|
headers: new Headers(),
|
|
url: 'http://iptv-worker.sapireli.workers.dev/epg.xml.gz',
|
|
})
|
|
).toBe(true);
|
|
});
|
|
|
|
it('returns false for gzip content-encoding without a gzip payload', () => {
|
|
expect(
|
|
shouldGunzipEpgResponse('https://example.com/guide', {
|
|
headers: new Headers([['content-encoding', 'gzip']]),
|
|
url: 'https://example.com/guide',
|
|
})
|
|
).toBe(false);
|
|
});
|
|
|
|
it('returns true for gzip mime types', () => {
|
|
expect(
|
|
shouldGunzipEpgResponse('https://example.com/guide', {
|
|
headers: new Headers([['content-type', 'application/gzip']]),
|
|
url: 'https://example.com/guide',
|
|
})
|
|
).toBe(true);
|
|
});
|
|
|
|
it('supports plain Axios response header objects', () => {
|
|
expect(
|
|
shouldGunzipEpgResponse('https://example.com/guide', {
|
|
headers: {
|
|
'Content-Type': 'application/gzip',
|
|
},
|
|
url: 'https://example.com/guide',
|
|
})
|
|
).toBe(true);
|
|
});
|
|
|
|
it('returns true when content-disposition advertises a .gz filename', () => {
|
|
expect(
|
|
shouldGunzipEpgResponse('https://example.com/guide', {
|
|
headers: new Headers([
|
|
[
|
|
'content-disposition',
|
|
'attachment; filename="guide.xml.gz"',
|
|
],
|
|
]),
|
|
url: 'https://example.com/guide',
|
|
})
|
|
).toBe(true);
|
|
});
|
|
|
|
it('returns false for plain XML responses', () => {
|
|
expect(
|
|
shouldGunzipEpgResponse('https://example.com/guide.xml', {
|
|
headers: new Headers([['content-type', 'application/xml']]),
|
|
url: 'https://example.com/guide.xml',
|
|
})
|
|
).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('getEpgResponseContentEncoding', () => {
|
|
it('detects Brotli transfer encoding from response headers', () => {
|
|
expect(
|
|
getEpgResponseContentEncoding({
|
|
'content-encoding': 'br',
|
|
})
|
|
).toBe('br');
|
|
});
|
|
|
|
it('detects gzip transfer encoding from response headers', () => {
|
|
expect(
|
|
getEpgResponseContentEncoding(
|
|
new Headers([['content-encoding', 'gzip']])
|
|
)
|
|
).toBe('gzip');
|
|
});
|
|
|
|
it('detects deflate transfer encoding from response headers', () => {
|
|
expect(
|
|
getEpgResponseContentEncoding({
|
|
'Content-Encoding': 'deflate',
|
|
})
|
|
).toBe('deflate');
|
|
});
|
|
|
|
it('ignores unsupported transfer encodings', () => {
|
|
expect(
|
|
getEpgResponseContentEncoding({
|
|
'content-encoding': 'zstd',
|
|
})
|
|
).toBe(null);
|
|
});
|
|
|
|
it('returns the outermost supported transfer encoding first', () => {
|
|
expect(
|
|
getEpgResponseContentEncoding({
|
|
'content-encoding': 'gzip, br',
|
|
})
|
|
).toBe('br');
|
|
});
|
|
});
|