File size: 3,383 Bytes
dcedb25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import { describe, it, expect } from 'vitest';
import { validateHeaderValue } from 'node:http';
import { safeHeaderValue, routedViaValue } from '../../lib/header-value.js';

// #619: relay model ids are arbitrary text. Whatever comes out of here has to
// be something Node will actually put on the wire, or an already-successful
// upstream call dies while the response is being written.
describe('safeHeaderValue', () => {
  it('leaves an ordinary provider/model pair byte-identical', () => {
    expect(safeHeaderValue('groq/llama-3.3-70b-versatile')).toBe('groq/llama-3.3-70b-versatile');
    expect(safeHeaderValue('openrouter/meta-llama/llama-4-scout:free')).toBe('openrouter/meta-llama/llama-4-scout:free');
  });

  it('percent-encodes non-ASCII so the value survives as something decodable', () => {
    const encoded = safeHeaderValue('custom/ζˆ‘ηš„ζ¨‘εž‹[test] v2');
    expect(encoded).toBe('custom/%E6%88%91%E7%9A%84%E6%A8%A1%E5%9E%8B[test] v2');
    expect(decodeURIComponent(encoded)).toBe('custom/ζˆ‘ηš„ζ¨‘εž‹[test] v2');
  });

  it('encodes control characters, so a model id cannot inject a header line', () => {
    const encoded = safeHeaderValue('custom/evil\r\nX-Admin: yes');
    expect(encoded).toBe('custom/evil%0D%0AX-Admin: yes');
    expect(encoded).not.toContain('\r');
    expect(encoded).not.toContain('\n');
  });

  it('escapes a literal % so the encoding round-trips unambiguously', () => {
    expect(safeHeaderValue('custom/100%-free')).toBe('custom/100%25-free');
    expect(decodeURIComponent(safeHeaderValue('custom/100%-free'))).toBe('custom/100%-free');
  });

  it('encodes astral code points as one UTF-8 sequence, not broken halves', () => {
    expect(decodeURIComponent(safeHeaderValue('custom/πŸš€-turbo'))).toBe('custom/πŸš€-turbo');
  });

  it('survives a lone surrogate instead of throwing', () => {
    const encoded = safeHeaderValue('custom/\uD800-model');
    expect(() => validateHeaderValue('X-Routed-Via', encoded)).not.toThrow();
    expect(encoded).toContain('-model');
  });

  it('caps the length without ever cutting an escape sequence in half', () => {
    const capped = safeHeaderValue(`${'a'.repeat(255)}ζˆ‘`, 256);
    expect(capped).toBe('a'.repeat(255));
    expect(safeHeaderValue('a'.repeat(1000)).length).toBe(256);
    expect(safeHeaderValue('a'.repeat(1000), 1024).length).toBe(1000);
  });

  it('returns an empty string for empty or missing input', () => {
    expect(safeHeaderValue('')).toBe('');
    expect(safeHeaderValue(undefined as unknown as string)).toBe('');
  });

  it('produces a value Node accepts for every hostile shape', () => {
    const hostile = [
      'ζˆ‘ηš„ζ¨‘εž‹[test] v2',
      'модСль/тСст',
      'model\u0000null',
      'model\u007Fdel',
      'tab\there',
      'a'.repeat(4000),
      'ζ—₯本θͺžγƒ’γƒ‡γƒ«οΌˆι«˜ι€ŸοΌ‰',
      'emoji πŸš€ model',
      '%not-an-escape',
    ];
    for (const raw of hostile) {
      const value = safeHeaderValue(`custom/${raw}`);
      expect(() => validateHeaderValue('X-Routed-Via', value)).not.toThrow();
      expect(value).toMatch(/^[\x20-\x7e]*$/);
    }
  });

  it('composes the routed-via value from platform and model', () => {
    expect(routedViaValue('groq', 'llama-3.3-70b')).toBe('groq/llama-3.3-70b');
    expect(decodeURIComponent(routedViaValue('custom', 'ζˆ‘ηš„ζ¨‘εž‹'))).toBe('custom/ζˆ‘ηš„ζ¨‘εž‹');
  });
});