tangled
alpha
login
or
join now
mokkenstorm.dev
/
openapi-ts
0
fork
atom
fork of hey-api/openapi-ts because I need some additional things
0
fork
atom
overview
issues
pulls
pipelines
fix: handle CLRF and CR line endings in SSE parser
Nacho García
3 months ago
5511bf53
271a0a20
+62
2 changed files
expand all
collapse all
unified
split
packages
openapi-ts
src
plugins
@hey-api
client-core
__tests__
serverSentEvents.test.ts
bundle
serverSentEvents.ts
+60
packages/openapi-ts/src/plugins/@hey-api/client-core/__tests__/serverSentEvents.test.ts
···
629
629
expect(validator).not.toHaveBeenCalled();
630
630
expect(transformer).not.toHaveBeenCalled();
631
631
});
632
632
+
633
633
+
it('handles CRLF line endings', async () => {
634
634
+
fetchMock.mockResolvedValue({
635
635
+
body: makeStream(['id: 1\r\nevent: test\r\ndata: {"foo":"bar"}\r\n\r\n']),
636
636
+
ok: true,
637
637
+
});
638
638
+
639
639
+
const onEvent = vi.fn();
640
640
+
const { stream } = createSseClient({
641
641
+
onSseEvent: onEvent,
642
642
+
url: 'http://localhost/sse',
643
643
+
});
644
644
+
645
645
+
const result: any[] = [];
646
646
+
for await (const ev of stream) result.push(ev);
647
647
+
648
648
+
expect(result).toEqual([{ foo: 'bar' }]);
649
649
+
expect(onEvent).toHaveBeenCalledWith({
650
650
+
data: { foo: 'bar' },
651
651
+
event: 'test',
652
652
+
id: '1',
653
653
+
retry: 3000,
654
654
+
});
655
655
+
});
656
656
+
657
657
+
it('handles CR-only line endings', async () => {
658
658
+
fetchMock.mockResolvedValue({
659
659
+
body: makeStream(['id: 2\revent: test\rdata: {"baz":"qux"}\r\r']),
660
660
+
ok: true,
661
661
+
});
662
662
+
663
663
+
const onEvent = vi.fn();
664
664
+
const { stream } = createSseClient({
665
665
+
onSseEvent: onEvent,
666
666
+
url: 'http://localhost/sse',
667
667
+
});
668
668
+
669
669
+
const result: any[] = [];
670
670
+
for await (const ev of stream) result.push(ev);
671
671
+
672
672
+
expect(result).toEqual([{ baz: 'qux' }]);
673
673
+
expect(onEvent).toHaveBeenCalledWith({
674
674
+
data: { baz: 'qux' },
675
675
+
event: 'test',
676
676
+
id: '2',
677
677
+
retry: 3000,
678
678
+
});
679
679
+
});
680
680
+
681
681
+
it('handles mixed line endings in a single stream', async () => {
682
682
+
fetchMock.mockResolvedValue({
683
683
+
body: makeStream(['data: 1\n\n', 'data: 2\r\n\r\n', 'data: 3\r\r']),
684
684
+
ok: true,
685
685
+
});
686
686
+
687
687
+
const { stream } = createSseClient({ url: 'http://localhost/sse' });
688
688
+
const result: any[] = [];
689
689
+
for await (const ev of stream) result.push(ev);
690
690
+
expect(result).toEqual([1, 2, 3]);
691
691
+
});
632
692
});
+2
packages/openapi-ts/src/plugins/@hey-api/client-core/bundle/serverSentEvents.ts
···
167
167
const { done, value } = await reader.read();
168
168
if (done) break;
169
169
buffer += value;
170
170
+
// Normalize line endings: CRLF -> LF, then CR -> LF
171
171
+
buffer = buffer.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
170
172
171
173
const chunks = buffer.split('\n\n');
172
174
buffer = chunks.pop() ?? '';