Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ function fastifyCompress (fastify, opts, next) {
// Manage compression options
if (routeOptions.compress !== undefined) {
if (typeof routeOptions.compress === 'object') {
const mergedCompressParams = Object.assign(
{}, globalCompressParams, processCompressParams(routeOptions.compress)
)
// Merge raw user options first so that route options that are *partial*
// do not silently overwrite globally-defined fields with `undefined`.
// See https://github.com/fastify/fastify-compress/issues/340
const mergedCompressParams = processCompressParams({ ...opts, ...routeOptions.compress })

// if the current endpoint has a custom compress configuration ...
buildRouteCompress(fastify, mergedCompressParams, routeOptions)
Expand All @@ -86,10 +87,10 @@ function fastifyCompress (fastify, opts, next) {
// Manage decompression options
if (routeOptions.decompress !== undefined) {
if (typeof routeOptions.decompress === 'object') {
// if the current endpoint has a custom compress configuration ...
const mergedDecompressParams = Object.assign(
{}, globalDecompressParams, processDecompressParams(routeOptions.decompress)
)
// Merge raw user options first so that route options that are *partial*
// do not silently overwrite globally-defined fields with `undefined`.
// See https://github.com/fastify/fastify-compress/issues/340
const mergedDecompressParams = processDecompressParams({ ...opts, ...routeOptions.decompress })

buildRouteDecompress(fastify, mergedDecompressParams, routeOptions)
} else if (routeOptions.decompress === false) {
Expand Down
38 changes: 38 additions & 0 deletions test/routes-compress.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -470,3 +470,41 @@ test('reply.compress should handle Web ReadableStream', async (t) => {
const res = await fastify.inject({ url: '/', method: 'GET', headers: { 'accept-encoding': 'gzip' } })
t.assert.equal(zlib.gunzipSync(res.rawPayload).toString('utf8'), 'from webstream')
})

describe('When routes `compress` options are partial — issue #340 :', async () => {
test('it should fall back to global `onUnsupportedEncoding` when the route only sets `threshold`', async (t) => {
t.plan(2)

let globalUnsupportedCalled = false

const fastify = Fastify()
await fastify.register(compressPlugin, {
global: true,
threshold: 0,
onUnsupportedEncoding (encoding, _req, reply) {
globalUnsupportedCalled = true
reply.code(406)
return `global handler saw ${encoding}`
}
})

// Route only sets `threshold` — global `onUnsupportedEncoding` must still apply.
fastify.get('/', {
compress: {
threshold: 0
}
}, (_req, reply) => {
reply.header('content-type', 'text/plain')
reply.send('hello world')
})

const response = await fastify.inject({
url: '/',
method: 'GET',
headers: { 'accept-encoding': 'whatever' }
})

t.assert.equal(globalUnsupportedCalled, true)
t.assert.equal(response.payload, 'global handler saw whatever')
})
})
118 changes: 118 additions & 0 deletions test/routes-decompress.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,121 @@ describe('When using the old routes `{ config: decompress }` option :', async ()
}
})
})

describe('When routes `decompress` options are partial — issue #340 :', async () => {
test('it should fall back to global `onInvalidRequestPayload` when the route only sets `onUnsupportedRequestEncoding`', async (t) => {
t.plan(2)

let globalInvalidCalled = false

const fastify = Fastify()
await fastify.register(compressPlugin, {
global: true,
onInvalidRequestPayload (encoding, _request, error) {
globalInvalidCalled = true
return {
statusCode: 400,
code: 'GLOBAL_INVALID',
error: 'Bad Request',
message: `global handler saw ${encoding} ${error.message}`
}
},
onUnsupportedRequestEncoding (encoding) {
return {
statusCode: 415,
code: 'GLOBAL_UNSUPPORTED',
error: 'Unsupported Media Type',
message: `global unsupported ${encoding}`
}
}
})

// Route only sets `onUnsupportedRequestEncoding`. The global
// `onInvalidRequestPayload` should still apply for this route — instead
// the bug overwrites the global hook with `undefined`.
fastify.post('/', {
decompress: {
onUnsupportedRequestEncoding (encoding) {
return {
statusCode: 415,
code: 'ROUTE_UNSUPPORTED',
error: 'Unsupported Media Type',
message: `route unsupported ${encoding}`
}
}
}
}, (request, reply) => {
reply.send(request.body.name)
})

// Send a gzip body but advertise deflate -> triggers onInvalidRequestPayload
const response = await fastify.inject({
url: '/',
method: 'POST',
headers: {
'content-type': 'application/json',
'content-encoding': 'deflate'
},
payload: createPayload(zlib.createGzip)
})

t.assert.equal(globalInvalidCalled, true)
t.assert.equal(response.json().code, 'GLOBAL_INVALID')
})

test('it should fall back to global `onUnsupportedRequestEncoding` when the route only sets `onInvalidRequestPayload`', async (t) => {
t.plan(2)

let globalUnsupportedCalled = false

const fastify = Fastify()
await fastify.register(compressPlugin, {
global: true,
onUnsupportedRequestEncoding (encoding) {
globalUnsupportedCalled = true
return {
statusCode: 415,
code: 'GLOBAL_UNSUPPORTED',
error: 'Unsupported Media Type',
message: `global unsupported ${encoding}`
}
},
onInvalidRequestPayload (encoding, _req, error) {
return {
statusCode: 400,
code: 'GLOBAL_INVALID',
error: 'Bad Request',
message: `global invalid ${encoding} ${error.message}`
}
}
})

fastify.post('/', {
decompress: {
onInvalidRequestPayload (encoding, _req, error) {
return {
statusCode: 400,
code: 'ROUTE_INVALID',
error: 'Bad Request',
message: `route invalid ${encoding} ${error.message}`
}
}
}
}, (request, reply) => {
reply.send(request.body.name)
})

const response = await fastify.inject({
url: '/',
method: 'POST',
headers: {
'content-type': 'application/json',
'content-encoding': 'whatever'
},
payload: createPayload(zlib.createDeflate)
})

t.assert.equal(globalUnsupportedCalled, true)
t.assert.equal(response.json().code, 'GLOBAL_UNSUPPORTED')
})
})