From 9cb582111483c667e0a8da26f688c9fb5dd7a21e Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Sat, 27 Feb 2021 00:48:12 +0100 Subject: [PATCH] refactor: show error, delay redirect This implements error page that does not hide the problem, but still redirects to a valid path after short delay: https://github.com/ipfs/go-ipfs/pull/7930#issuecomment-786882748 This commit was moved from ipfs/kubo@dae7387584ed15beebac70e32b878113cdb904b6 --- gateway/core/corehttp/gateway_handler.go | 34 ++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/gateway/core/corehttp/gateway_handler.go b/gateway/core/corehttp/gateway_handler.go index cf5acf209..289fdd725 100644 --- a/gateway/core/corehttp/gateway_handler.go +++ b/gateway/core/corehttp/gateway_handler.go @@ -3,6 +3,7 @@ package corehttp import ( "context" "fmt" + "html/template" "io" "mime" "net/http" @@ -36,6 +37,16 @@ const ( var onlyAscii = regexp.MustCompile("[[:^ascii:]]") +// HTML-based redirect for errors which can be recovered from, but we want +// to provide hint to people that they should fix things on their end. +var redirectTemplate = template.Must(template.New("redirect").Parse(`
{{.ErrorMsg}}
(if a redirect does not happen in 10 seconds, use "{{.SuggestedPath}}" instead)
`)) + +type redirectTemplateData struct { + RedirectURL string + SuggestedPath string + ErrorMsg string +} + // gatewayHandler is a HTTP handler that serves IPFS objects (accessible by default at /ipfs/) // (it serves requests like GET /ipfs/QmVRzPKPzNtSrEzBFm2UZfxmPAgnaLke4DMcerbsGGSaFe/link) type gatewayHandler struct { @@ -216,19 +227,32 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request } parsedPath := ipath.New(urlPath) - if err := parsedPath.IsValid(); err != nil { - // Attempt to fix redundant /ipfs/ namespace as long resulting + if pathErr := parsedPath.IsValid(); pathErr != nil { + // Attempt to fix redundant /ipfs/ namespace as long as resulting // 'intended' path is valid. This is in case gremlins were tickled // wrong way and user ended up at /ipfs/ipfs/{cid} or /ipfs/ipns/{id} // like in bafybeien3m7mdn6imm425vc2s22erzyhbvk5n3ofzgikkhmdkh5cuqbpbq // :^)) intendedPath := ipath.New(strings.TrimPrefix(urlPath, "/ipfs")) - if err2 := intendedPath.IsValid(); err2 == nil { + if err := intendedPath.IsValid(); err == nil { intendedURL := strings.Replace(r.URL.String(), urlPath, intendedPath.String(), 1) - http.Redirect(w, r, intendedURL, http.StatusMovedPermanently) + // return HTML that + // - points at correct canonical path via header + // - displays error + // - redirects to intendedURL after a delay + err = redirectTemplate.Execute(w, redirectTemplateData{ + RedirectURL: intendedURL, + SuggestedPath: intendedPath.String(), + ErrorMsg: pathErr.Error(), + }) + if err != nil { + internalWebError(w, err) + return + } return } - webError(w, "invalid ipfs path", err, http.StatusBadRequest) + // unable to fix path, returning error + webError(w, "invalid ipfs path", pathErr, http.StatusBadRequest) return }