+ + This edge function has crashed +
+An unhandled error in the edge function code triggered the following message:
+ +
+
+
+ From a6aa6eee99de0bec42111e09bb1c5c67d35981fa Mon Sep 17 00:00:00 2001 From: khen <30577427+khendrikse@users.noreply.github.com> Date: Wed, 24 Aug 2022 11:18:23 +0200 Subject: [PATCH 1/8] feat: getting error page to edge functions --- src/lib/functions/synchronous.js | 5 +++-- src/utils/proxy.js | 36 +++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/lib/functions/synchronous.js b/src/lib/functions/synchronous.js index e203fbf3a2c..e7c32814284 100644 --- a/src/lib/functions/synchronous.js +++ b/src/lib/functions/synchronous.js @@ -50,6 +50,7 @@ const formatLambdaLocalError = (err, acceptsHtml) => let errorTemplateFile const renderErrorTemplate = async (errString) => { + console.log('rendererrortemplate') const regexPattern = //g const templatePath = './templates/function-error.html' @@ -64,7 +65,7 @@ const renderErrorTemplate = async (errString) => { const processRenderedResponse = async (err, request) => { const acceptsHtml = request.headers && request.headers.accept && request.headers.accept.includes('text/html') const errorString = typeof err === 'string' ? err : formatLambdaLocalError(err, acceptsHtml) - + // I think this is where we show errors? return acceptsHtml ? await renderErrorTemplate(errorString) : errorString } @@ -96,4 +97,4 @@ const validateLambdaResponse = (lambdaResponse) => { return {} } -module.exports = { handleSynchronousFunction } +module.exports = { handleSynchronousFunction, renderErrorTemplate } diff --git a/src/utils/proxy.js b/src/utils/proxy.js index 122f9b43e6d..c41e63b9db6 100644 --- a/src/utils/proxy.js +++ b/src/utils/proxy.js @@ -4,6 +4,7 @@ const { readFile } = require('fs').promises const http = require('http') const https = require('https') const path = require('path') +const { join } = require('path') const contentType = require('content-type') const cookie = require('cookie') @@ -20,6 +21,7 @@ const toReadableStream = require('to-readable-stream') const edgeFunctions = require('../lib/edge-functions') const { fileExistsAsync, isFileAsync } = require('../lib/fs') +// const { renderErrorTemplate } = require('../lib/functions/synchronous') const { NETLIFYDEVLOG, NETLIFYDEVWARN } = require('./command-helpers') const { createStreamPromise } = require('./create-stream-promise') @@ -359,10 +361,11 @@ const initializeProxy = async function ({ configPath, distDir, port, projectDir const headersRules = headersForPath(headers, requestURL.pathname) proxyRes.on('data', function onData(data) { + console.log('we get here?') responseData.push(data) }) - proxyRes.on('end', function onEnd() { + proxyRes.on('end', async function onEnd() { const responseBody = Buffer.concat(responseData) let responseStatus = req.proxyOptions.status || proxyRes.statusCode @@ -385,11 +388,21 @@ const initializeProxy = async function ({ configPath, distDir, port, projectDir Object.entries(headersRules).forEach(([key, val]) => { res.setHeader(key, val) }) - res.writeHead(responseStatus, proxyRes.headers) + console.log({ responseBody }) + console.log(Buffer.from(responseBody).toString()) + + if (responseStatus === 500 && proxyRes.headers['x-nf-uncaught-error'] === '1') { + const acceptsHtml = req.headers && req.headers.accept && req.headers.accept.includes('text/html') + console.log('something went wrong', acceptsHtml) + const errorResponse = acceptsHtml ? await renderErrorTemplate(responseBody) : responseBody + console.log({ errorResponse: typeof errorResponse, body: typeof responseBody }) + res.write(errorResponse) + } + console.log('got here?') if (responseStatus !== 304) { - res.write(responseBody) + // res.write(responseBody) } res.end() @@ -411,6 +424,23 @@ const initializeProxy = async function ({ configPath, distDir, port, projectDir return handlers } +let errorTemplateFile + +const renderErrorTemplate = async (errString) => { + console.log('rendererrortemplate') + const regexPattern = //g + const templatePath = '../lib/functions/templates/function-error.html' + console.log({ templatePath }) + try { + console.log('in try', errString) + errorTemplateFile = errorTemplateFile || (await readFile(join(__dirname, templatePath), 'utf-8')) + return errorTemplateFile.replace(regexPattern, errString) + } catch { + console.log('catching') + return errString + } +} + const onRequest = async ({ addonsUrls, edgeFunctionsProxy, functionsServer, proxy, rewriter, settings }, req, res) => { req.originalBody = ['GET', 'OPTIONS', 'HEAD'].includes(req.method) ? null From 89599efa6bdaabea3aff91a5b826ee34f27ef475 Mon Sep 17 00:00:00 2001 From: khen <30577427+khendrikse@users.noreply.github.com> Date: Fri, 9 Sep 2022 14:27:53 +0200 Subject: [PATCH 2/8] feat: set content length to have correct headers --- src/lib/functions/synchronous.js | 5 ++- src/utils/proxy.js | 52 +++++++++++++++++--------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/lib/functions/synchronous.js b/src/lib/functions/synchronous.js index e7c32814284..e203fbf3a2c 100644 --- a/src/lib/functions/synchronous.js +++ b/src/lib/functions/synchronous.js @@ -50,7 +50,6 @@ const formatLambdaLocalError = (err, acceptsHtml) => let errorTemplateFile const renderErrorTemplate = async (errString) => { - console.log('rendererrortemplate') const regexPattern = //g const templatePath = './templates/function-error.html' @@ -65,7 +64,7 @@ const renderErrorTemplate = async (errString) => { const processRenderedResponse = async (err, request) => { const acceptsHtml = request.headers && request.headers.accept && request.headers.accept.includes('text/html') const errorString = typeof err === 'string' ? err : formatLambdaLocalError(err, acceptsHtml) - // I think this is where we show errors? + return acceptsHtml ? await renderErrorTemplate(errorString) : errorString } @@ -97,4 +96,4 @@ const validateLambdaResponse = (lambdaResponse) => { return {} } -module.exports = { handleSynchronousFunction, renderErrorTemplate } +module.exports = { handleSynchronousFunction } diff --git a/src/utils/proxy.js b/src/utils/proxy.js index c41e63b9db6..0d19555c477 100644 --- a/src/utils/proxy.js +++ b/src/utils/proxy.js @@ -30,6 +30,23 @@ const { createRewriter, onChanges } = require('./rules-proxy') const shouldGenerateETag = Symbol('Internal: response should generate ETag') +let errorTemplateFile + +const renderErrorTemplate = async (errString) => { + console.log('rendererrortemplate') + const regexPattern = //g + const templatePath = '../lib/functions/templates/function-error.html' + console.log({ templatePath }) + try { + console.log('in try', errString) + errorTemplateFile = errorTemplateFile || (await readFile(join(__dirname, templatePath), 'utf-8')) + return errorTemplateFile.replace(regexPattern, errString) + } catch { + console.log('catching') + return errString + } +} + const isInternal = function (url) { return url.startsWith('/.netlify/') } @@ -388,21 +405,23 @@ const initializeProxy = async function ({ configPath, distDir, port, projectDir Object.entries(headersRules).forEach(([key, val]) => { res.setHeader(key, val) }) - res.writeHead(responseStatus, proxyRes.headers) - console.log({ responseBody }) - console.log(Buffer.from(responseBody).toString()) - if (responseStatus === 500 && proxyRes.headers['x-nf-uncaught-error'] === '1') { + const isUncaughtError = responseStatus === 500 && proxyRes.headers['x-nf-uncaught-error'] === '1' + + if (edgeFunctions.isEdgeFunctionsRequest(req) && isUncaughtError) { const acceptsHtml = req.headers && req.headers.accept && req.headers.accept.includes('text/html') - console.log('something went wrong', acceptsHtml) const errorResponse = acceptsHtml ? await renderErrorTemplate(responseBody) : responseBody - console.log({ errorResponse: typeof errorResponse, body: typeof responseBody }) + const contentLength = Buffer.from(errorResponse, 'utf8').byteLength + + res.setHeader('content-length', contentLength) res.write(errorResponse) + return res.end() } - console.log('got here?') + + res.writeHead(responseStatus, proxyRes.headers) if (responseStatus !== 304) { - // res.write(responseBody) + res.write(responseBody) } res.end() @@ -424,23 +443,6 @@ const initializeProxy = async function ({ configPath, distDir, port, projectDir return handlers } -let errorTemplateFile - -const renderErrorTemplate = async (errString) => { - console.log('rendererrortemplate') - const regexPattern = //g - const templatePath = '../lib/functions/templates/function-error.html' - console.log({ templatePath }) - try { - console.log('in try', errString) - errorTemplateFile = errorTemplateFile || (await readFile(join(__dirname, templatePath), 'utf-8')) - return errorTemplateFile.replace(regexPattern, errString) - } catch { - console.log('catching') - return errString - } -} - const onRequest = async ({ addonsUrls, edgeFunctionsProxy, functionsServer, proxy, rewriter, settings }, req, res) => { req.originalBody = ['GET', 'OPTIONS', 'HEAD'].includes(req.method) ? null From 75748aaf338a587edc41873cf877803be1c041aa Mon Sep 17 00:00:00 2001 From: khen <30577427+khendrikse@users.noreply.github.com> Date: Fri, 9 Sep 2022 15:02:05 +0200 Subject: [PATCH 3/8] feat: move render-error-template to own file --- src/lib/functions/render-error-remplate.js | 18 ++++++++++++++++++ src/lib/functions/synchronous.js | 17 +---------------- src/utils/proxy.js | 21 +-------------------- 3 files changed, 20 insertions(+), 36 deletions(-) create mode 100644 src/lib/functions/render-error-remplate.js diff --git a/src/lib/functions/render-error-remplate.js b/src/lib/functions/render-error-remplate.js new file mode 100644 index 00000000000..a2422cd6b54 --- /dev/null +++ b/src/lib/functions/render-error-remplate.js @@ -0,0 +1,18 @@ +const { readFile } = require('fs').promises +const { join } = require('path') + +let errorTemplateFile + +const renderErrorTemplate = async (errString) => { + const regexPattern = //g + const templatePath = './templates/function-error.html' + + try { + errorTemplateFile = errorTemplateFile || (await readFile(join(__dirname, templatePath), 'utf-8')) + return errorTemplateFile.replace(regexPattern, errString) + } catch { + return errString + } +} + +module.exports = renderErrorTemplate diff --git a/src/lib/functions/synchronous.js b/src/lib/functions/synchronous.js index e203fbf3a2c..9d1f0c6a7df 100644 --- a/src/lib/functions/synchronous.js +++ b/src/lib/functions/synchronous.js @@ -1,10 +1,9 @@ // @ts-check const { Buffer } = require('buffer') -const { readFile } = require('fs').promises -const { join } = require('path') const { NETLIFYDEVERR } = require('../../utils') +const renderErrorTemplate = require('./render-error-remplate') const { detectAwsSdkError } = require('./utils') const addHeaders = (headers, response) => { @@ -47,20 +46,6 @@ const formatLambdaLocalError = (err, acceptsHtml) => }) : `${err.errorType}: ${err.errorMessage}\n ${err.stackTrace.join('\n ')}` -let errorTemplateFile - -const renderErrorTemplate = async (errString) => { - const regexPattern = //g - const templatePath = './templates/function-error.html' - - try { - errorTemplateFile = errorTemplateFile || (await readFile(join(__dirname, templatePath), 'utf-8')) - return errorTemplateFile.replace(regexPattern, errString) - } catch { - return errString - } -} - const processRenderedResponse = async (err, request) => { const acceptsHtml = request.headers && request.headers.accept && request.headers.accept.includes('text/html') const errorString = typeof err === 'string' ? err : formatLambdaLocalError(err, acceptsHtml) diff --git a/src/utils/proxy.js b/src/utils/proxy.js index 0d19555c477..35732c57742 100644 --- a/src/utils/proxy.js +++ b/src/utils/proxy.js @@ -4,7 +4,6 @@ const { readFile } = require('fs').promises const http = require('http') const https = require('https') const path = require('path') -const { join } = require('path') const contentType = require('content-type') const cookie = require('cookie') @@ -21,7 +20,7 @@ const toReadableStream = require('to-readable-stream') const edgeFunctions = require('../lib/edge-functions') const { fileExistsAsync, isFileAsync } = require('../lib/fs') -// const { renderErrorTemplate } = require('../lib/functions/synchronous') +const renderErrorTemplate = require('../lib/functions/render-error-remplate') const { NETLIFYDEVLOG, NETLIFYDEVWARN } = require('./command-helpers') const { createStreamPromise } = require('./create-stream-promise') @@ -30,23 +29,6 @@ const { createRewriter, onChanges } = require('./rules-proxy') const shouldGenerateETag = Symbol('Internal: response should generate ETag') -let errorTemplateFile - -const renderErrorTemplate = async (errString) => { - console.log('rendererrortemplate') - const regexPattern = //g - const templatePath = '../lib/functions/templates/function-error.html' - console.log({ templatePath }) - try { - console.log('in try', errString) - errorTemplateFile = errorTemplateFile || (await readFile(join(__dirname, templatePath), 'utf-8')) - return errorTemplateFile.replace(regexPattern, errString) - } catch { - console.log('catching') - return errString - } -} - const isInternal = function (url) { return url.startsWith('/.netlify/') } @@ -378,7 +360,6 @@ const initializeProxy = async function ({ configPath, distDir, port, projectDir const headersRules = headersForPath(headers, requestURL.pathname) proxyRes.on('data', function onData(data) { - console.log('we get here?') responseData.push(data) }) From 07e53de7f2a98bce229154e48d35f1f7201f4044 Mon Sep 17 00:00:00 2001 From: khen <30577427+khendrikse@users.noreply.github.com> Date: Thu, 22 Sep 2022 13:22:20 +0200 Subject: [PATCH 4/8] feat: render edge function error in its own template --- src/lib/functions/render-error-remplate.js | 3 +- .../templates/edge-function-error.html | 289 ++++++++++++++++++ .../functions/templates/function-error.html | 1 + src/utils/proxy.js | 12 +- 4 files changed, 302 insertions(+), 3 deletions(-) create mode 100644 src/lib/functions/templates/edge-function-error.html diff --git a/src/lib/functions/render-error-remplate.js b/src/lib/functions/render-error-remplate.js index a2422cd6b54..fb9b573b549 100644 --- a/src/lib/functions/render-error-remplate.js +++ b/src/lib/functions/render-error-remplate.js @@ -3,9 +3,8 @@ const { join } = require('path') let errorTemplateFile -const renderErrorTemplate = async (errString) => { +const renderErrorTemplate = async (errString, templatePath = './templates/function-error.html') => { const regexPattern = //g - const templatePath = './templates/function-error.html' try { errorTemplateFile = errorTemplateFile || (await readFile(join(__dirname, templatePath), 'utf-8')) diff --git a/src/lib/functions/templates/edge-function-error.html b/src/lib/functions/templates/edge-function-error.html new file mode 100644 index 00000000000..6187cd6846c --- /dev/null +++ b/src/lib/functions/templates/edge-function-error.html @@ -0,0 +1,289 @@ + + +
+An unhandled error in the edge function code triggered the following message:
+ +
+
+
+ An unhandled error in the edge function code triggered the following message:
- -
-
-
- An unhandled error in the function code triggered the following message:
-
-
-
-
-
-
-