From e2ed59fc41a23b9833bcb92335e1476859aa6213 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 7 Nov 2023 11:17:08 +0100 Subject: [PATCH] feat: remove support for legacy ipfs-404.html --- CHANGELOG.md | 1 + gateway/gateway_test.go | 40 --------------- gateway/handler.go | 10 ---- gateway/handler_unixfs__redirects.go | 70 --------------------------- gateway/testdata/pretty-404.car | Bin 405 -> 0 bytes 5 files changed, 1 insertion(+), 120 deletions(-) delete mode 100644 gateway/testdata/pretty-404.car diff --git a/CHANGELOG.md b/CHANGELOG.md index fa8defac6..68b2072a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ The following emojis are used to highlight certain changes: ### Changed ### Removed +* 🛠 `boxo/gateway`: removed support for undocumented legacy `ipfs-404.html`. Use [`_redirects`](https://specs.ipfs.tech/http-gateways/web-redirects-file/) instead. ### Fixed diff --git a/gateway/gateway_test.go b/gateway/gateway_test.go index e9cb1c150..53f19ca08 100644 --- a/gateway/gateway_test.go +++ b/gateway/gateway_test.go @@ -93,46 +93,6 @@ func TestGatewayGet(t *testing.T) { } } -func TestPretty404(t *testing.T) { - ts, backend, root := newTestServerAndNode(t, nil, "pretty-404.car") - t.Logf("test server url: %s", ts.URL) - - host := "example.net" - backend.namesys["/ipns/"+host] = newMockNamesysItem(path.FromCid(root), 0) - - for _, test := range []struct { - path string - accept string - status int - text string - }{ - {"/ipfs-404.html", "text/html", http.StatusOK, "Custom 404"}, - {"/nope", "text/html", http.StatusNotFound, "Custom 404"}, - {"/nope", "text/*", http.StatusNotFound, "Custom 404"}, - {"/nope", "*/*", http.StatusNotFound, "Custom 404"}, - {"/nope", "application/json", http.StatusNotFound, fmt.Sprintf("failed to resolve /ipns/example.net/nope: no link named \"nope\" under %s\n", root.String())}, - {"/deeper/nope", "text/html", http.StatusNotFound, "Deep custom 404"}, - {"/deeper/", "text/html", http.StatusOK, ""}, - {"/deeper", "text/html", http.StatusOK, ""}, - {"/nope/nope", "text/html", http.StatusNotFound, "Custom 404"}, - } { - testName := fmt.Sprintf("%s %s", test.path, test.accept) - t.Run(testName, func(t *testing.T) { - req := mustNewRequest(t, "GET", ts.URL+test.path, nil) - req.Header.Add("Accept", test.accept) - req.Host = host - resp := mustDo(t, req) - defer resp.Body.Close() - require.Equal(t, test.status, resp.StatusCode) - body, err := io.ReadAll(resp.Body) - require.NoError(t, err) - if test.text != "" { - require.Equal(t, test.text, string(body)) - } - }) - } -} - func TestHeaders(t *testing.T) { t.Parallel() diff --git a/gateway/handler.go b/gateway/handler.go index 44218975f..ab9b46ebd 100644 --- a/gateway/handler.go +++ b/gateway/handler.go @@ -770,16 +770,6 @@ func (i *handler) handleWebRequestErrors(w http.ResponseWriter, r *http.Request, } } - // if Accept is text/html, see if ipfs-404.html is present - // This logic isn't documented and will likely be removed at some point. - // Any 404 logic in _redirects above will have already run by this time, so it's really an extra fall back - // PLEASE do not use this for new websites, - // follow https://docs.ipfs.tech/how-to/websites-on-ipfs/redirects-and-custom-404s/ instead. - if i.serveLegacy404IfPresent(w, r, immutableContentPath, logger) { - logger.Debugw("served legacy 404") - return path.ImmutablePath{}, false - } - err = fmt.Errorf("failed to resolve %s: %w", debugStr(contentPath.String()), err) i.webError(w, r, err, http.StatusInternalServerError) return path.ImmutablePath{}, false diff --git a/gateway/handler_unixfs__redirects.go b/gateway/handler_unixfs__redirects.go index 0cd4d3c71..a6fe24826 100644 --- a/gateway/handler_unixfs__redirects.go +++ b/gateway/handler_unixfs__redirects.go @@ -240,73 +240,3 @@ func hasOriginIsolation(r *http.Request) bool { return false } - -// Deprecated: legacy ipfs-404.html files are superseded by _redirects file -// This is provided only for backward-compatibility, until websites migrate -// to 404s managed via _redirects file (https://github.com/ipfs/specs/pull/290) -func (i *handler) serveLegacy404IfPresent(w http.ResponseWriter, r *http.Request, imPath path.ImmutablePath, logger *zap.SugaredLogger) bool { - resolved404File, resolved404FileSize, ctype, err := i.searchUpTreeFor404(r, imPath) - if err != nil { - return false - } - defer resolved404File.Close() - - logger.Debugw("using pretty 404 file", "path", imPath) - w.Header().Set("Content-Type", ctype) - w.Header().Set("Content-Length", strconv.FormatInt(resolved404FileSize, 10)) - w.WriteHeader(http.StatusNotFound) - _, err = io.CopyN(w, resolved404File, resolved404FileSize) - return err == nil -} - -func (i *handler) searchUpTreeFor404(r *http.Request, imPath path.ImmutablePath) (io.ReadCloser, int64, string, error) { - filename404, ctype, err := preferred404Filename(r.Header.Values("Accept")) - if err != nil { - return nil, 0, "", err - } - - pathComponents := strings.Split(imPath.String(), "/") - - for idx := len(pathComponents); idx >= 3; idx-- { - pretty404 := gopath.Join(append(pathComponents[0:idx], filename404)...) - parsed404Path, err := path.NewPath("/" + pretty404) - if err != nil { - break - } - imparsed404Path, err := path.NewImmutablePath(parsed404Path) - if err != nil { - break - } - - _, getResp, err := i.backend.Get(r.Context(), imparsed404Path) - if err != nil { - continue - } - if getResp.bytes == nil { - // Close the response here if not returning bytes, otherwise it's the caller's responsibility to close the io.ReadCloser - getResp.Close() - return nil, 0, "", fmt.Errorf("found a pretty 404 but it was not a file") - } - return getResp.bytes, getResp.bytesSize, ctype, nil - } - - return nil, 0, "", fmt.Errorf("no pretty 404 in any parent folder") -} - -func preferred404Filename(acceptHeaders []string) (string, string, error) { - // If we ever want to offer a 404 file for a different content type - // then this function will need to parse q weightings, but for now - // the presence of anything matching HTML is enough. - for _, acceptHeader := range acceptHeaders { - accepted := strings.Split(acceptHeader, ",") - for _, spec := range accepted { - contentType := strings.SplitN(spec, ";", 1)[0] - switch contentType { - case "*/*", "text/*", "text/html": - return "ipfs-404.html", "text/html", nil - } - } - } - - return "", "", fmt.Errorf("there is no 404 file for the requested content types") -} diff --git a/gateway/testdata/pretty-404.car b/gateway/testdata/pretty-404.car deleted file mode 100644 index 3adec2904505b235636f71f1e39424cd18559b19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 405 zcmcColvHW(gI(VAk2&I})&3ib zyJX4;v8AM@7NizQ_z0N;b%Y8j{Hcx1xU=Td?beB&9;{|hv+r(B&nXUk(|kA~GC_2; zw}cRHWc*