Skip to content

Commit

Permalink
feat: remove support for legacy ipfs-404.html
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Nov 7, 2023
1 parent a966a74 commit f1442f7
Show file tree
Hide file tree
Showing 5 changed files with 1 addition and 120 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
40 changes: 0 additions & 40 deletions gateway/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
10 changes: 0 additions & 10 deletions gateway/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 0 additions & 70 deletions gateway/handler_unixfs__redirects.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Binary file removed gateway/testdata/pretty-404.car
Binary file not shown.

0 comments on commit f1442f7

Please sign in to comment.