Skip to content

Commit 89754a1

Browse files
fix: ensure edge functions work with HTTPS mode (#5409)
* fix: communicate with Deno server over HTTP * chore: define complications * refactor: small optimisation
1 parent 7e27e7a commit 89754a1

File tree

3 files changed

+29
-18
lines changed

3 files changed

+29
-18
lines changed

src/lib/edge-functions/headers.mjs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
const headers = {
22
ForwardedHost: 'x-forwarded-host',
3-
ForwardedProtocol: 'x-forwarded-proto',
43
Functions: 'x-nf-edge-functions',
54
Geo: 'x-nf-geo',
65
Passthrough: 'x-nf-passthrough',

src/lib/edge-functions/proxy.mjs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,21 @@ export const initializeProxy = async ({
6262
geolocationMode,
6363
getUpdatedConfig,
6464
inspectSettings,
65+
mainPort,
6566
offline,
67+
passthroughPort,
6668
projectDir,
67-
settings,
6869
siteInfo,
6970
state,
7071
}) => {
7172
const { functions: internalFunctions, importMap, path: internalFunctionsPath } = await getInternalFunctions()
72-
const { port: mainPort } = settings
7373
const userFunctionsPath = config.build.edge_functions
7474
const isolatePort = await getAvailablePort()
7575

7676
// Initializes the server, bootstrapping the Deno CLI and downloading it from
7777
// the network if needed. We don't want to wait for that to be completed, or
7878
// the command will be left hanging.
7979
const server = prepareServer({
80-
certificatePath: settings.https ? settings.https.certFilePath : undefined,
8180
config,
8281
configPath,
8382
directories: [internalFunctionsPath, userFunctionsPath].filter(Boolean),
@@ -132,7 +131,7 @@ export const initializeProxy = async ({
132131

133132
req[headersSymbol] = {
134133
[headers.Functions]: functionNames.join(','),
135-
[headers.ForwardedHost]: `localhost:${mainPort}`,
134+
[headers.ForwardedHost]: `localhost:${passthroughPort}`,
136135
[headers.Passthrough]: 'passthrough',
137136
[headers.RequestID]: generateUUID(),
138137
[headers.IP]: LOCAL_HOST,
@@ -142,18 +141,13 @@ export const initializeProxy = async ({
142141
req[headersSymbol][headers.DebugLogging] = '1'
143142
}
144143

145-
if (settings.https) {
146-
req[headersSymbol][headers.ForwardedProtocol] = 'https'
147-
}
148-
149144
return `http://${LOCAL_HOST}:${isolatePort}`
150145
}
151146
}
152147

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

155150
const prepareServer = async ({
156-
certificatePath,
157151
config,
158152
configPath,
159153
directories,
@@ -173,7 +167,6 @@ const prepareServer = async ({
173167
const distImportMapPath = getPathInProject([DIST_IMPORT_MAP_PATH])
174168
const runIsolate = await bundler.serve({
175169
...getDownloadUpdateFunctions(),
176-
certificatePath,
177170
debug: env.NETLIFY_DENO_DEBUG === 'true',
178171
distImportMapPath,
179172
formatExportTypeError: (name) =>

src/utils/proxy.mjs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import contentType from 'content-type'
1313
import cookie from 'cookie'
1414
import { get } from 'dot-prop'
1515
import generateETag from 'etag'
16+
import getAvailablePort from 'get-port'
1617
import httpProxy from 'http-proxy'
1718
import { createProxyMiddleware } from 'http-proxy-middleware'
1819
import jwtDecode from 'jwt-decode'
@@ -545,6 +546,7 @@ export const startProxy = async function ({
545546
siteInfo,
546547
state,
547548
}) {
549+
const secondaryServerPort = settings.https ? await getAvailablePort() : null
548550
const functionsServer = settings.functionsPort ? `http://127.0.0.1:${settings.functionsPort}` : null
549551
const edgeFunctionsProxy = await initializeEdgeFunctionsProxy({
550552
config,
@@ -555,9 +557,10 @@ export const startProxy = async function ({
555557
geoCountry,
556558
getUpdatedConfig,
557559
inspectSettings,
560+
mainPort: settings.port,
558561
offline,
562+
passthroughPort: secondaryServerPort || settings.port,
559563
projectDir,
560-
settings,
561564
siteInfo,
562565
state,
563566
})
@@ -586,16 +589,32 @@ export const startProxy = async function ({
586589
functionsServer,
587590
edgeFunctionsProxy,
588591
})
589-
const server = settings.https
592+
const primaryServer = settings.https
590593
? https.createServer({ cert: settings.https.cert, key: settings.https.key }, onRequestWithOptions)
591594
: http.createServer(onRequestWithOptions)
592-
593-
server.on('upgrade', function onUpgrade(req, socket, head) {
595+
const onUpgrade = function onUpgrade(req, socket, head) {
594596
proxy.ws(req, socket, head)
595-
})
597+
}
598+
599+
primaryServer.on('upgrade', onUpgrade)
600+
primaryServer.listen({ port: settings.port })
601+
602+
const eventQueue = [once(primaryServer, 'listening')]
603+
604+
// If we're running the main server on HTTPS, we need to start a secondary
605+
// server on HTTP for receiving passthrough requests from edge functions.
606+
// This lets us run the Deno server on HTTP and avoid the complications of
607+
// Deno talking to Node on HTTPS with potentially untrusted certificates.
608+
if (secondaryServerPort) {
609+
const secondaryServer = http.createServer(onRequestWithOptions)
610+
611+
secondaryServer.on('upgrade', onUpgrade)
612+
secondaryServer.listen({ port: secondaryServerPort })
613+
614+
eventQueue.push(once(secondaryServer, 'listening'))
615+
}
596616

597-
server.listen({ port: settings.port })
598-
await once(server, 'listening')
617+
await Promise.all(eventQueue)
599618

600619
const scheme = settings.https ? 'https' : 'http'
601620
return `${scheme}://localhost:${settings.port}`

0 commit comments

Comments
 (0)