diff --git a/gateway/handler.go b/gateway/handler.go index 45163d9b3..f077babae 100644 --- a/gateway/handler.go +++ b/gateway/handler.go @@ -181,7 +181,11 @@ func (i *handler) getOrHeadHandler(w http.ResponseWriter, r *http.Request) { return } - if requestHandled := i.handleProtocolHandlerRedirect(w, r, logger); requestHandled { + if redirectURL, err := getProtocolHandlerRedirect(r); err != nil { + i.webError(w, r, err, http.StatusBadRequest) + return + } else if redirectURL != "" { + http.Redirect(w, r, redirectURL, http.StatusMovedPermanently) return } @@ -759,16 +763,14 @@ func handleUnsupportedHeaders(r *http.Request) (err *ErrorResponse) { // via navigator.registerProtocolHandler Web API // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler // TLDR: redirect /ipfs/?uri=ipfs%3A%2F%2Fcid%3Fquery%3Dval to /ipfs/cid?query=val -func (i *handler) handleProtocolHandlerRedirect(w http.ResponseWriter, r *http.Request, logger *zap.SugaredLogger) (requestHandled bool) { +func getProtocolHandlerRedirect(r *http.Request) (string, error) { if uriParam := r.URL.Query().Get("uri"); uriParam != "" { u, err := url.Parse(uriParam) if err != nil { - i.webError(w, r, fmt.Errorf("failed to parse uri query parameter: %w", err), http.StatusBadRequest) - return true + return "", fmt.Errorf("failed to parse uri query parameter: %w", err) } if u.Scheme != "ipfs" && u.Scheme != "ipns" { - i.webError(w, r, fmt.Errorf("uri query parameter scheme must be ipfs or ipns: %w", err), http.StatusBadRequest) - return true + return "", fmt.Errorf("uri query parameter scheme must be ipfs or ipns: %w", err) } path := u.Path if u.RawQuery != "" { // preserve query if present @@ -776,12 +778,10 @@ func (i *handler) handleProtocolHandlerRedirect(w http.ResponseWriter, r *http.R } redirectURL := gopath.Join("/", u.Scheme, u.Host, path) - logger.Debugw("uri param, redirect", "to", redirectURL, "status", http.StatusMovedPermanently) - http.Redirect(w, r, redirectURL, http.StatusMovedPermanently) - return true + return redirectURL, nil } - return false + return "", nil } // Disallow Service Worker registration on namespace roots diff --git a/gateway/hostname.go b/gateway/hostname.go index 082f82074..27a1b46e4 100644 --- a/gateway/hostname.go +++ b/gateway/hostname.go @@ -25,6 +25,15 @@ func WithHostname(c Config, api IPFSBackend, next http.Handler) http.HandlerFunc return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer panicHandler(w) + // First check for protocol handler redirects. + if redirectURL, err := getProtocolHandlerRedirect(r); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } else if redirectURL != "" { + http.Redirect(w, r, redirectURL, http.StatusMovedPermanently) + return + } + // Unfortunately, many (well, ipfs.io) gateways use // DNSLink so if we blindly rewrite with DNSLink, we'll // break /ipfs links.