Skip to content

Commit

Permalink
Gateway renders pretty 404 pages if available
Browse files Browse the repository at this point in the history
In the same way that an `index.html` file is rendered, if one is present, when a
path requested of the gateway is a directory, a `404.html` file is rendered if
the requested file is not present within the specified IPFS object.

`404.html` files are looked for in the directory of the requested path and each
parent until one is found, falling back on the previous error message.

License: MIT
Signed-off-by: JP Hastings-Spital <jphastings@gmail.com>
  • Loading branch information
jphastings committed Sep 16, 2017
1 parent 4453b89 commit 5df5fee
Showing 1 changed file with 31 additions and 3 deletions.
34 changes: 31 additions & 3 deletions core/corehttp/gateway_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
return
}

preventCache := false

// Resolve path to the final DAG node for the ETag
resolvedPath, err := i.api.ResolvePath(ctx, parsedPath)
switch err {
Expand All @@ -179,8 +181,16 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
}
fallthrough
default:
webError(w, "ipfs resolve -r "+escapedURLPath, err, http.StatusNotFound)
return
// Look for a pretty 404 page in any parent folder of the requested file
resolved404Path, err404 := findPretty404(ctx, parsedPath, i)
if err404 != nil {
webError(w, "ipfs resolve -r "+escapedURLPath, err, http.StatusNotFound)
return
}

preventCache = true
resolvedPath = resolved404Path
log.Debugf("using pretty 404.html link for %s", escapedURLPath)
}

dr, err := i.api.Unixfs().Cat(ctx, resolvedPath)
Expand All @@ -191,6 +201,7 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
defer dr.Close()
case coreiface.ErrIsDir:
dir = true
preventCache = true
default:
webError(w, "ipfs cat "+escapedURLPath, err, http.StatusNotFound)
return
Expand Down Expand Up @@ -259,7 +270,7 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
// TODO: break this out when we split /ipfs /ipns routes.
modtime := time.Now()

if strings.HasPrefix(urlPath, ipfsPathPrefix) && !dir {
if strings.HasPrefix(urlPath, ipfsPathPrefix) && !preventCache {
w.Header().Set("Cache-Control", "public, max-age=29030400, immutable")

// set modtime to a really long time ago, since files are immutable and should stay cached
Expand Down Expand Up @@ -598,3 +609,20 @@ func webErrorWithCode(w http.ResponseWriter, message string, err error, code int
func internalWebError(w http.ResponseWriter, err error) {
webErrorWithCode(w, "internalWebError", err, http.StatusInternalServerError)
}

func findPretty404(ctx context.Context, parsedPath coreiface.Path, i *gatewayHandler) (coreiface.Path, error) {
pathComponents := strings.SplitAfter(gopath.Dir(parsedPath.String()), "/")

for idx := len(pathComponents); idx >= 3; idx-- {
pretty404 := gopath.Join(append(pathComponents[0:idx], "404.html")...)
parsedPath, err := coreapi.ParsePath(pretty404)
if err == nil {
resolvedPath, err := i.api.ResolvePath(ctx, parsedPath)
if err == nil {
return resolvedPath, nil
}
}
}

return nil, errors.New("No pretty 404 in any parent folder")
}

0 comments on commit 5df5fee

Please sign in to comment.