Skip to content

Commit

Permalink
fix: prevent infinite loop when error occurs if default error page is…
Browse files Browse the repository at this point in the history
… missing in custom builds

The default error page is now inlined so that it works even in custom builds of functions (e.g. webpack). Fixes #109.
  • Loading branch information
activescott committed Sep 26, 2021
1 parent aa963a6 commit 84cc787
Show file tree
Hide file tree
Showing 14 changed files with 28,683 additions and 24 deletions.
3 changes: 2 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
.nyc_output/
coverage/
node_modules/
.serverless/
.serverless/
.webpack/
42 changes: 30 additions & 12 deletions src/StaticFileHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,24 +174,42 @@ class StaticFileHandler {
* @param {*string} errorText The error to add to the page.
*/
async responseAsError(errorText, statusCode) {
let filePath
let customErrorPagePathIsValid
const context = {
errorText: errorText,
}
if (this.customErrorPagePath) {
filePath = path.join(this.clientFilesPath, this.customErrorPagePath)
let filePath = path.join(this.clientFilesPath, this.customErrorPagePath)
try {
await accessAsync(filePath, fs.constants.R_OK)
customErrorPagePathIsValid = true
return this.readFileAsResponse(filePath, context, statusCode)
} catch (err) {
customErrorPagePathIsValid = false
console.warn(
"serverless-aws-static-file-handler: Error using customErrorPagePath",
this.customErrorPagePath,
". Using fallback error HTML."
)
}
}
if (!customErrorPagePathIsValid) {
filePath = path.join(__dirname, "error.html")
}
const viewData = {
errorText: errorText,
}
return this.readFileAsResponse(filePath, viewData, statusCode)

const DEFAULT_ERROR_HTML = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Error</title>
</head>
<body>
{errorText}
</body>
</html>
`
return StaticFileHandler.readStringAsResponse(
DEFAULT_ERROR_HTML,
context,
statusCode,
"text/html",
false
)
}

/**
Expand Down
11 changes: 0 additions & 11 deletions src/error.html

This file was deleted.

16 changes: 16 additions & 0 deletions test-files/webpack-project/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"comments": false,
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "12"
}
}
]
],
"plugins": [
"source-map-support"
]
}
1 change: 1 addition & 0 deletions test-files/webpack-project/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.webpack/
4 changes: 4 additions & 0 deletions test-files/webpack-project/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# webpack example for serverless-aws-static-file-handler

Things can be a bit different when packed such as paths to files as noted in [issue #109](https://github.com/activescott/serverless-aws-static-file-handler/issues/109). This example/test is a repro of essentially that issue.
Shamelessly stolen from https://github.com/serverless-heaven/serverless-webpack/tree/master/examples/babel-webpack-4 and ever-so-slightly modified to include serverless-aws-static-file-handler.
67 changes: 67 additions & 0 deletions test-files/webpack-project/data-files/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
</head>

<div id="valid" style="border: 1px solid gray;">
These should all load and either be a valid image or a font:
</div>

<script lang="javascript">
const validPaths = [
"png",
]

main()

async function main() {
await addPathsToList(validPaths, document.querySelector("#valid"))
}

async function addPathsToList(paths, parentElm) {
let ul = document.createElement("ul")
parentElm.appendChild(ul)
paths.forEach(async path => {
console.log("adding path:", path)
let contentType
let response
let lastError
try {
response = await fetch(path)
contentType = response.headers.get("Content-type")
if (!response.ok)
throw new Error(`Error response status: ${response.status}: ${response.statusText}`)
} catch (err) {
lastError = err
console.error("Error fetching path", path, ":", err)
contentType = `ERROR/${err.message}`
}
let blob = null
try {
if (response)
blob = await response.blob()
} catch (err) {
lastError = err
console.error("Error getting blob for path", path, ":", err)
}

const li = document.createElement("li")
li.style.color = !lastError ? "currentColor" : "red"
const img = document.createElement("img")
img.style.cssText = "border: 1px solid orange; display:inline-block; width: 32px; height: 32px"
if (blob) {
img.src = URL.createObjectURL(blob)
}

li.appendChild(img)
li.append(` ${path}`)
const span = document.createElement("span")

span.append(` (Content-Type: ${contentType})`)
li.appendChild(span)
ul.appendChild(li)
})
}
</script>
</html>
Binary file added test-files/webpack-project/data-files/png.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions test-files/webpack-project/event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"resource": null,
"httpMethod": "GET",
"headers": {},
"multiValueHeaders": {},
"queryStringParameters": null,
"multiValueQueryStringParameters": null,
"pathParameters": null,
"stageVariables": null,
"requestContext": {},
"body": null,
"isBase64Encoded": false
}
23 changes: 23 additions & 0 deletions test-files/webpack-project/handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use strict"
const path = require("path")
const StaticFileHandler = require("serverless-aws-static-file-handler")
const clientFilesPath = path.join(__dirname, "./data-files/")
const fileHandler = new StaticFileHandler(clientFilesPath)

// require.context triggers file-loader to copy the data-files directory. see https://webpack.js.org/guides/dependency-management/#requirecontext
require.context("./data-files")

export const html = async (event, context) => {
event.path = "index.html" // forcing a specific page for this handler; ignore requested path
return fileHandler.get(event, context)
}

export const png = async (event, context) => {
event.path = "png.png"
return fileHandler.get(event, context)
}

export const notfound = async (event, context) => {
event.path = "notfound.html"
return fileHandler.get(event, context)
}
Loading

0 comments on commit 84cc787

Please sign in to comment.