diff --git a/index.js b/index.js index 12110ee4..59f91e5e 100644 --- a/index.js +++ b/index.js @@ -250,11 +250,13 @@ const fastifyReplyFrom = fp(function from (fastify, opts, next) { function getQueryString (search, reqUrl, opts, request) { if (typeof opts.queryString === 'function') { - return '?' + opts.queryString(search, reqUrl, request) + const qs = opts.queryString(search, reqUrl, request) + return qs ? '?' + qs : '' } if (opts.queryString) { - return '?' + querystring.stringify(opts.queryString) + const qs = querystring.stringify(opts.queryString) + return qs ? '?' + qs : '' } if (search.length > 0) { diff --git a/test/full-querystring-rewrite-option-empty-object.test.js b/test/full-querystring-rewrite-option-empty-object.test.js new file mode 100644 index 00000000..4cf54e0b --- /dev/null +++ b/test/full-querystring-rewrite-option-empty-object.test.js @@ -0,0 +1,41 @@ +'use strict' + +const t = require('node:test') +const Fastify = require('fastify') +const { request } = require('undici') +const From = require('..') +const http = require('node:http') + +const instance = Fastify() + +t.test('queryString empty object should not append trailing ?', async (t) => { + t.plan(4) + t.after(() => instance.close()) + + const target = http.createServer((req, res) => { + t.assert.ok('request proxied') + t.assert.strictEqual(req.url, '/world') + res.statusCode = 200 + res.setHeader('Content-Type', 'text/plain') + res.end('hello world') + }) + + instance.get('/hello', (_request, reply) => { + reply.from(`http://localhost:${target.address().port}/world`, { + queryString: {} + }) + }) + + t.after(() => target.close()) + + await new Promise(resolve => target.listen({ port: 0 }, resolve)) + + instance.register(From) + + await new Promise(resolve => instance.listen({ port: 0 }, resolve)) + + const result = await request(`http://localhost:${instance.server.address().port}/hello`) + + t.assert.strictEqual(result.statusCode, 200) + t.assert.strictEqual(await result.body.text(), 'hello world') +}) diff --git a/test/full-querystring-rewrite-option-function-empty.test.js b/test/full-querystring-rewrite-option-function-empty.test.js new file mode 100644 index 00000000..308f79ac --- /dev/null +++ b/test/full-querystring-rewrite-option-function-empty.test.js @@ -0,0 +1,43 @@ +'use strict' + +const t = require('node:test') +const Fastify = require('fastify') +const { request } = require('undici') +const From = require('..') +const http = require('node:http') + +const instance = Fastify() + +t.test('queryString function returning empty string should not append trailing ?', async (t) => { + t.plan(4) + t.after(() => instance.close()) + + const target = http.createServer((req, res) => { + t.assert.ok('request proxied') + t.assert.strictEqual(req.url, '/world') + res.statusCode = 200 + res.setHeader('Content-Type', 'text/plain') + res.end('hello world') + }) + + instance.get('/hello', (_request, reply) => { + reply.from(`http://localhost:${target.address().port}/world`, { + queryString () { + return '' + } + }) + }) + + t.after(() => target.close()) + + await new Promise(resolve => target.listen({ port: 0 }, resolve)) + + instance.register(From) + + await new Promise(resolve => instance.listen({ port: 0 }, resolve)) + + const result = await request(`http://localhost:${instance.server.address().port}/hello`) + + t.assert.strictEqual(result.statusCode, 200) + t.assert.strictEqual(await result.body.text(), 'hello world') +})