Skip to content

Commit

Permalink
feat: add HTTPS support for Edge Functions in Netlify Dev (#4567)
Browse files Browse the repository at this point in the history
* feat: add https support for Edge Functions

* refactor: use `x-forwarded` headers

* chore: update cert generation

* refactor: change certs script

* chore: fix cert generation on Windows

* chore: fix cert generation on Windows

* chore: fix cert generation on Windows

* chore: omg

* chore: move self generation to integration tests

* chore: add cert generation to test:dev script

* chore: update @netlify/edge-bundler to v1.0.0
  • Loading branch information
eduardoboucas authored May 3, 2022
1 parent 6695113 commit f51066e
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 60 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ jobs:
if_true: 'npm run test:affected ${{ github.event.pull_request.base.sha }}' # on pull requests test with the project graph only the affected tests
if_false: 'npm run test:ci:ava:integration' # on the base branch run all the tests as security measure
if: '${{ !steps.release-check.outputs.IS_RELEASE }}'
- name: Generate self-signed certificates
run: npm run certs
if: '${{!steps.release-check.outputs.IS_RELEASE}}'
shell: bash
- name: Prepare tests
run: npm run test:init
if: '${{ !steps.release-check.outputs.IS_RELEASE }}'
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@ tests/integration/hugo-site/resources
tests/integration/hugo-site/out
tests/integration/hugo-site/.hugo_build.lock
_test_out/**
*.crt
*.key

8 changes: 8 additions & 0 deletions certconf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[dn]
CN=localhost
[req]
distinguished_name = dn
[EXT]
subjectAltName=DNS:localhost
keyUsage=digitalSignature
extendedKeyUsage=serverAuth
128 changes: 121 additions & 7 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@
"format:check-fix:prettier": "run-e format:check:prettier format:fix:prettier",
"format:check:prettier": "cross-env-shell prettier --check $npm_package_config_prettier",
"format:fix:prettier": "cross-env-shell prettier --write $npm_package_config_prettier",
"test:dev": "run-s test:init:* test:dev:*",
"test:dev": "run-s certs test:init:* test:dev:*",
"test:init": "run-s test:init:*",
"test:init:cli-version": "npm run start -- --version",
"test:init:cli-help": "npm run start -- --help",
Expand All @@ -200,7 +200,8 @@
"site:build": "run-s site:build:*",
"site:build:install": "cd site && npm ci --no-audit",
"site:build:assets": "cd site && npm run build",
"postinstall": "node ./scripts/postinstall.js"
"postinstall": "node ./scripts/postinstall.js",
"certs": "openssl req -x509 -out localhost.crt -keyout localhost.key -newkey rsa:2048 -nodes -sha256 -subj \"/CN=localhost\" -extensions EXT -config certconf"
},
"config": {
"eslint": "--ignore-path .gitignore --cache --format=codeframe --max-warnings=0 \"{src,scripts,site,tests,.github}/**/*.{mjs,cjs,js,md,html}\" \"*.{mjs,cjs,js,md,html}\" \".*.{mjs,cjs,js,md,html}\"",
Expand All @@ -209,7 +210,7 @@
"dependencies": {
"@netlify/build": "^27.0.1",
"@netlify/config": "^18.0.0",
"@netlify/edge-bundler": "^0.12.0",
"@netlify/edge-bundler": "^1.0.0",
"@netlify/framework-info": "^9.0.2",
"@netlify/local-functions-proxy": "^1.1.1",
"@netlify/plugins-list": "^6.19.0",
Expand Down
3 changes: 2 additions & 1 deletion src/lib/edge-functions/headers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module.exports = {
ForwardedHost: 'x-forwarded-host',
ForwardedProtocol: 'x-forwarded-proto',
Functions: 'x-deno-functions',
Geo: 'x-nf-geo',
PassHost: 'X-NF-Pass-Host',
Passthrough: 'x-deno-pass',
RequestID: 'X-NF-Request-ID',
}
9 changes: 8 additions & 1 deletion src/lib/edge-functions/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const initializeProxy = async ({ config, configPath, geolocationMode, getUpdated
// the network if needed. We don't want to wait for that to be completed, or
// the command will be left hanging.
const server = prepareServer({
certificatePath: settings.https ? settings.https.certFilePath : undefined,
config,
configPath,
directories: [internalFunctionsPath, userFunctionsPath].filter(Boolean),
Expand Down Expand Up @@ -100,18 +101,23 @@ const initializeProxy = async ({ config, configPath, geolocationMode, getUpdated

req[headersSymbol] = {
[headers.Functions]: functionNames.join(','),
[headers.PassHost]: `${LOCAL_HOST}:${mainPort}`,
[headers.ForwardedHost]: `localhost:${mainPort}`,
[headers.Passthrough]: 'passthrough',
[headers.RequestID]: generateUUID(),
}

if (settings.https) {
req[headersSymbol][headers.ForwardedProtocol] = 'https'
}

return `http://${LOCAL_HOST}:${isolatePort}`
}
}

const isEdgeFunctionsRequest = (req) => req[headersSymbol] !== undefined

const prepareServer = async ({
certificatePath,
config,
configPath,
directories,
Expand All @@ -124,6 +130,7 @@ const prepareServer = async ({
const distImportMapPath = getPathInProject([DIST_IMPORT_MAP_PATH])
const runIsolate = await bundler.serve({
...getDownloadUpdateFunctions(),
certificatePath,
debug: env.NETLIFY_DENO_DEBUG === 'true',
distImportMapPath,
formatExportTypeError: (name) =>
Expand Down
2 changes: 1 addition & 1 deletion src/utils/detect-server-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const readHttpsSettings = async (options) => {
throw new Error(`Error reading certificate file: ${certError.message}`)
}

return { key, cert }
return { key, cert, keyFilePath: path.resolve(keyFile), certFilePath: path.resolve(certFile) }
}

const validateStringProperty = ({ devConfig, property }) => {
Expand Down
28 changes: 25 additions & 3 deletions tests/integration/200.command.dev.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const path = require('path')
// eslint-disable-next-line ava/use-test
const avaTest = require('ava')
const { isCI } = require('ci-info')
const { Response } = require('node-fetch')

const { curl } = require('./utils/curl')
const { withDevServer } = require('./utils/dev-server')
Expand Down Expand Up @@ -194,7 +195,13 @@ export const handler = async function () {
config: {
build: { publish: 'public' },
functions: { directory: 'functions' },
dev: { https: { certFile: 'cert.pem', keyFile: 'key.pem' } },
dev: { https: { certFile: 'localhost.crt', keyFile: 'localhost.key' } },
edge_functions: [
{
function: 'hello',
path: '/',
},
],
},
})
.withContentFile({
Expand All @@ -211,15 +218,30 @@ export const handler = async function () {
body: 'Hello World',
}),
})
.withEdgeFunction({
handler: async (req, { next }) => {
if (!req.url.includes('?ef=true')) {
return
}

// eslint-disable-next-line n/callback-return
const res = await next()
const text = await res.text()

return new Response(text.toUpperCase(), res)
},
name: 'hello',
})
.buildAsync()

await Promise.all([
copyFile(`${__dirname}/assets/cert.pem`, `${builder.directory}/cert.pem`),
copyFile(`${__dirname}/assets/key.pem`, `${builder.directory}/key.pem`),
copyFile(`${__dirname}/../../localhost.crt`, `${builder.directory}/localhost.crt`),
copyFile(`${__dirname}/../../localhost.key`, `${builder.directory}/localhost.key`),
])
await withDevServer({ cwd: builder.directory, args }, async ({ port }) => {
const options = { https: { rejectUnauthorized: false } }
t.is(await got(`https://localhost:${port}`, options).text(), 'index')
t.is(await got(`https://localhost:${port}?ef=true`, options).text(), 'INDEX')
t.is(await got(`https://localhost:${port}/api/hello`, options).text(), 'Hello World')
})
})
Expand Down
Loading

1 comment on commit f51066e

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📊 Benchmark results

Package size: 274 MB

Please sign in to comment.