From 73b95bc8119c69a09d05e2ae564e33b6cd42c832 Mon Sep 17 00:00:00 2001 From: dnalborczyk Date: Mon, 31 Oct 2022 12:25:33 -0400 Subject: [PATCH] fix: path access with trailing slash (#1606) --- src/events/http/HttpServer.js | 3 + src/events/websocket/HttpServer.js | 3 + .../optionParameters/optionParameters.test.js | 117 +++++++++++++++++- .../optionParameters/src/serverless.yml | 7 ++ 4 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/events/http/HttpServer.js b/src/events/http/HttpServer.js index a9f36a1a8..fe8076381 100644 --- a/src/events/http/HttpServer.js +++ b/src/events/http/HttpServer.js @@ -74,6 +74,9 @@ export default class HttpServer { const serverOptions = { host, port: httpPort, + router: { + stripTrailingSlash: true, + }, state: enforceSecureCookies ? { isHttpOnly: true, diff --git a/src/events/websocket/HttpServer.js b/src/events/websocket/HttpServer.js index bfff53ff7..4e241f2da 100644 --- a/src/events/websocket/HttpServer.js +++ b/src/events/websocket/HttpServer.js @@ -35,6 +35,9 @@ export default class HttpServer { const serverOptions = { host, port: websocketPort, + router: { + stripTrailingSlash: true, + }, // https support ...(httpsProtocol != null && { tls: await this.#loadCerts(httpsProtocol), diff --git a/tests/endToEnd/optionParameters/optionParameters.test.js b/tests/endToEnd/optionParameters/optionParameters.test.js index f6e1c1f7f..d9f99a4c8 100644 --- a/tests/endToEnd/optionParameters/optionParameters.test.js +++ b/tests/endToEnd/optionParameters/optionParameters.test.js @@ -16,7 +16,7 @@ describe('noPrependStageInUrl option', function desc() { afterEach(() => teardown()) - describe('when --noPrependStageInUrl is used, and the stage is not in the url', () => { + describe('when --noPrependStageInUrl is used', () => { it('it should return a payload', async () => { const url = new URL('/hello', BASE_URL) const response = await fetch(url) @@ -26,10 +26,28 @@ describe('noPrependStageInUrl option', function desc() { foo: 'bar', }) }) - }) - describe('when --noPrependStageInUrl is used, and the stage is not in the url', () => { - it('noPrependStageInUrl 2', async () => { + it('it should return a payload with no path', async () => { + const url = new URL('/', BASE_URL) + const response = await fetch(url) + const json = await response.json() + + assert.deepEqual(json, { + foo: 'bar', + }) + }) + + it('it should return a payload when accessed with trailing slash', async () => { + const url = new URL('/hello/', BASE_URL) + const response = await fetch(url) + const json = await response.json() + + assert.deepEqual(json, { + foo: 'bar', + }) + }) + + it('when --noPrependStageInUrl is used it should return a 404', async () => { const url = new URL('/dev/hello', BASE_URL) const response = await fetch(url) const json = await response.json() @@ -59,5 +77,96 @@ describe('prefix option', function desc() { foo: 'bar', }) }) + + it('the prefixed path should return a payload when accessed with trailing slash', async () => { + const url = new URL('/someprefix/dev/hello/', BASE_URL) + const response = await fetch(url) + const json = await response.json() + + assert.deepEqual(json, { + foo: 'bar', + }) + }) + + it('the prefixed path should return a payload with no path', async () => { + const url = new URL('/someprefix/dev', BASE_URL) + const response = await fetch(url) + const json = await response.json() + + assert.deepEqual(json, { + foo: 'bar', + }) + }) + + it('the prefixed path should return a payload with no path and trailing slash', async () => { + const url = new URL('/someprefix/dev/', BASE_URL) + const response = await fetch(url) + const json = await response.json() + + assert.deepEqual(json, { + foo: 'bar', + }) + }) + }) +}) + +describe('noPrependStageInUrl option with prefix option', function desc() { + beforeEach(() => + setup({ + args: ['--noPrependStageInUrl', '--prefix', 'someprefix'], + servicePath: resolve(__dirname, 'src'), + }), + ) + + afterEach(() => teardown()) + + describe('when --noPrependStageInUrl and --prefix is used', () => { + it('it should return a payload', async () => { + const url = new URL('/someprefix/hello', BASE_URL) + const response = await fetch(url) + const json = await response.json() + + assert.deepEqual(json, { + foo: 'bar', + }) + }) + + it('it should return a payload with no path', async () => { + const url = new URL('/someprefix', BASE_URL) + const response = await fetch(url) + const json = await response.json() + + assert.deepEqual(json, { + foo: 'bar', + }) + }) + + it('it should return a payload with no path and trailing slash', async () => { + const url = new URL('/someprefix/', BASE_URL) + const response = await fetch(url) + const json = await response.json() + + assert.deepEqual(json, { + foo: 'bar', + }) + }) + + it('it should return a payload when accessed with trailing slash', async () => { + const url = new URL('/someprefix/hello/', BASE_URL) + const response = await fetch(url) + const json = await response.json() + + assert.deepEqual(json, { + foo: 'bar', + }) + }) + + it('when --noPrependStageInUrl is used it should return a 404', async () => { + const url = new URL('/someprefix/dev/hello', BASE_URL) + const response = await fetch(url) + const json = await response.json() + + assert.equal(json.statusCode, 404) + }) }) }) diff --git a/tests/endToEnd/optionParameters/src/serverless.yml b/tests/endToEnd/optionParameters/src/serverless.yml index 365708722..d47e50761 100644 --- a/tests/endToEnd/optionParameters/src/serverless.yml +++ b/tests/endToEnd/optionParameters/src/serverless.yml @@ -23,3 +23,10 @@ functions: method: get path: /hello handler: handler.hello + + foobar: + events: + - http: + method: get + path: '/' + handler: handler.hello