Skip to content

Commit 79ff1d2

Browse files
authored
Add test for text/event-stream proxying with custom parser (#438)
* verify if @fastify/multipart is registerd by checking with hasPlugin Signed-off-by: Matteo Collina <[email protected]> * Add test and docs for multipart proxying with custom parser * fixup Signed-off-by: Matteo Collina <[email protected]> * Add test for text/event-stream proxying with custom parser * fixup Signed-off-by: Matteo Collina <[email protected]> --------- Signed-off-by: Matteo Collina <[email protected]>
1 parent bb232f5 commit 79ff1d2

File tree

2 files changed

+81
-5
lines changed

2 files changed

+81
-5
lines changed

README.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -524,26 +524,34 @@ This is due to the fact that `@fastify/multipart` consumes the multipart content
524524

525525
However, the two plugins may be used within the same fastify instance, at the condition that they belong to disjoint branches of the fastify plugins hierarchy tree.
526526

527-
### Proxying multipart/form-data without @fastify/multipart
527+
### Proxying specific content types without parsing
528528

529-
If you need to proxy `multipart/form-data` requests without parsing them, you can use a custom content type parser instead of `@fastify/multipart`:
529+
If you need to proxy certain content types (like `multipart/form-data` or `text/event-stream`) without parsing them, you can use custom content type parsers:
530530

531531
```js
532-
// Register a custom content type parser for multipart/form-data
533-
// This passes the raw body through without parsing
532+
// Register custom content type parsers that pass raw body through
534533
fastify.addContentTypeParser('multipart/form-data', function (req, body, done) {
535534
done(null, body)
536535
})
537536

537+
fastify.addContentTypeParser('text/event-stream', function (req, body, done) {
538+
done(null, body)
539+
})
540+
538541
fastify.register(require('@fastify/reply-from'))
539542

540543
fastify.post('/upload', (request, reply) => {
541544
// The multipart data will be proxied as-is to the upstream server
542545
reply.from('http://upstream-server.com/upload')
543546
})
547+
548+
fastify.post('/events', (request, reply) => {
549+
// The SSE data will be proxied as-is to the upstream server
550+
reply.from('http://upstream-server.com/events')
551+
})
544552
```
545553

546-
This approach allows `multipart/form-data` to be proxied correctly while avoiding the incompatibility with `@fastify/multipart`.
554+
This approach allows these content types to be proxied correctly while avoiding parsing that would consume the request body.
547555

548556
## License
549557

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
'use strict'
2+
3+
const t = require('node:test')
4+
const Fastify = require('fastify')
5+
const { request } = require('undici')
6+
const From = require('..')
7+
const http = require('node:http')
8+
9+
t.test('text/event-stream proxying with custom content type parser', async (t) => {
10+
t.plan(6)
11+
12+
// Target server that sends SSE data
13+
const target = http.createServer((req, res) => {
14+
t.assert.ok('request proxied')
15+
t.assert.strictEqual(req.method, 'POST')
16+
t.assert.match(req.headers['content-type'], /^text\/event-stream/)
17+
18+
let data = ''
19+
req.setEncoding('utf8')
20+
req.on('data', (chunk) => {
21+
data += chunk
22+
})
23+
req.on('end', () => {
24+
// Verify the SSE data is received
25+
t.assert.match(data, /data: test message/)
26+
t.assert.match(data, /event: custom/)
27+
28+
res.setHeader('content-type', 'application/json')
29+
res.statusCode = 200
30+
res.end(JSON.stringify({ received: 'sse data' }))
31+
})
32+
})
33+
34+
// Fastify instance with custom text/event-stream parser
35+
const fastify = Fastify()
36+
37+
// Register custom content type parser for text/event-stream
38+
// This allows the raw body to be passed through without parsing
39+
fastify.addContentTypeParser('text/event-stream', function (req, body, done) {
40+
done(null, body)
41+
})
42+
43+
fastify.register(From)
44+
45+
fastify.post('/', (request, reply) => {
46+
reply.from(`http://localhost:${target.address().port}`)
47+
})
48+
49+
t.after(() => fastify.close())
50+
t.after(() => target.close())
51+
52+
await fastify.listen({ port: 0 })
53+
await target.listen({ port: 0 })
54+
55+
// Create SSE-like data
56+
const sseData = 'data: test message\nevent: custom\ndata: another line\n\n'
57+
58+
// Send request with SSE data
59+
const result = await request(`http://localhost:${fastify.server.address().port}`, {
60+
method: 'POST',
61+
headers: {
62+
'content-type': 'text/event-stream'
63+
},
64+
body: sseData
65+
})
66+
67+
t.assert.deepStrictEqual(await result.body.json(), { received: 'sse data' })
68+
})

0 commit comments

Comments
 (0)