diff --git a/.vscode/settings.json b/.vscode/settings.json index 0989be2..35116db 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,6 +11,7 @@ 128 ], + // --------------------------------------------------------------------------------------------------------------------------- // Files // --------------------------------------------------------------------------------------------------------------------------- @@ -32,12 +33,28 @@ "typescript.tsdk": "node_modules/typescript/lib", + // --------------------------------------------------------------------------------------------------------------------------- + // Extensions + // --------------------------------------------------------------------------------------------------------------------------- + // ESLint + "eslint.autoFixOnSave": true, + "eslint.validate": [ + { "language": "javascript", "autoFix": true }, + { "language": "javascriptreact", "autoFix": true }, + { "language": "typescript", "autoFix": true }, + { "language": "typescriptreact", "autoFix": true } + ], + + // --------------------------------------------------------------------------------------------------------------------------- // Language Setings // --------------------------------------------------------------------------------------------------------------------------- "[javascript]": { "editor.formatOnSave": true }, + "[javascriptreact]": { + "editor.formatOnSave": true + }, "[typescript]": { "editor.formatOnSave": true }, diff --git a/CHANGELOG.md b/CHANGELOG.md index 3629dcd..20eb1d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # Changelog +## 1.0.1 (2019-12-13) +- Fix setting headers after sending #10 - [@jagaapple](https://github.com/jagaapple) +- Improve development environment + - Enable automatic code formatting for VS Code #8 - [@jagaapple](https://github.com/jagaapple) + ## 1.0.0 (2019-12-04) - Initial public release - [@jagaapple](https://github.com/jagaapple) diff --git a/example/pages/redirector.tsx b/example/pages/redirector.tsx new file mode 100644 index 0000000..5560b31 --- /dev/null +++ b/example/pages/redirector.tsx @@ -0,0 +1,19 @@ +import { ServerResponse } from "http"; +import { NextPage } from "next"; + +const moveToTop = (res: ServerResponse) => { + res.writeHead(302, { Location: "/" }); + res.end(); +}; + +const Page: NextPage = () => null; + +Page.getInitialProps = async ({ res }) => { + if (res == undefined) return {}; + + moveToTop(res); + + return {}; +}; + +export default Page; diff --git a/package-lock.json b/package-lock.json index 57d625f..abac5a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "next-secure-headers", - "version": "1.0.0", + "version": "1.0.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 26af595..2d8c72c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next-secure-headers", - "version": "1.0.0", + "version": "1.0.1", "description": "Sets secure response headers for Next.js.", "keywords": [ "Next.js", diff --git a/src/index.spec.ts b/src/index.spec.ts index 8437ceb..eed0e94 100644 --- a/src/index.spec.ts +++ b/src/index.spec.ts @@ -1,7 +1,7 @@ import * as React from "react"; import * as rules from "./rules"; -import { default as withSecureHeaders, createHeadersObject } from "./index"; +import { createHeadersObject, default as withSecureHeaders } from "./index"; describe("createHeadersObject", () => { let contentSecurityPolicyHeaderCreatorSpy: jest.SpyInstance< @@ -188,5 +188,28 @@ describe("withSecureHeaders", () => { await expect(ComponentWithSecureHeaders.getInitialProps!(dummyContext)).resolves.toEqual(dummyInitialProps); }); }); + + context('when "headersSent" property of "res" is true', () => { + it('should not call "context.ctx.res.setHeader()"', async () => { + const DummyComponent = () => React.createElement("div"); + const ComponentWithSecureHeaders = withSecureHeaders()(DummyComponent); + + const resSetHeeaderSpy = jest.fn(); + const dummyContext: any = { ctx: { res: { setHeader: resSetHeeaderSpy, headersSent: true } } }; + await ComponentWithSecureHeaders.getInitialProps!(dummyContext); + + expect(resSetHeeaderSpy).not.toBeCalled(); + }); + + it('should return the returned value from "getInitialProps"', async () => { + const DummyComponent = () => React.createElement("div"); + const dummyInitialProps = { dummy: "dummy" }; + DummyComponent.getInitialProps = async () => dummyInitialProps; + const ComponentWithSecureHeaders = withSecureHeaders()(DummyComponent); + + const dummyContext: any = { ctx: { res: { setHeader: jest.fn(), headersSent: true } } }; + await expect(ComponentWithSecureHeaders.getInitialProps!(dummyContext)).resolves.toEqual(dummyInitialProps); + }); + }); }); }); diff --git a/src/index.ts b/src/index.ts index f14cda4..647066f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -90,6 +90,7 @@ export default (options: Options = {}) => (ChildComponent: NextComponent) => { const initialProps = (await ChildComponent.getInitialProps?.(context)) ?? {}; const res = context.res ?? context.ctx?.res; if (res == undefined) return initialProps; + if (res.headersSent) return initialProps; const headers = createHeadersObject(options); Object.entries(headers).forEach(([name, value]) => res.setHeader(name, value));