Skip to content

Commit 79cb4e2

Browse files
authored
gateway: tests for simpler superfluous namespace handling (#572)
1 parent 89bceff commit 79cb4e2

File tree

2 files changed

+87
-35
lines changed

2 files changed

+87
-35
lines changed

gateway/gateway_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,92 @@ func TestRedirects(t *testing.T) {
577577
do(http.MethodGet)
578578
do(http.MethodHead)
579579
})
580+
581+
t.Run("Superfluous namespace", func(t *testing.T) {
582+
t.Parallel()
583+
584+
backend, root := newMockBackend(t, "fixtures.car")
585+
backend.namesys["/ipns/dnslink-gateway.com"] = newMockNamesysItem(path.FromCid(root), 0)
586+
backend.namesys["/ipns/dnslink-website.com"] = newMockNamesysItem(path.FromCid(root), 0)
587+
588+
ts := newTestServerWithConfig(t, backend, Config{
589+
NoDNSLink: false,
590+
PublicGateways: map[string]*PublicGateway{
591+
"dnslink-gateway.com": {
592+
Paths: []string{"/ipfs", "/ipns"},
593+
NoDNSLink: false,
594+
DeserializedResponses: true,
595+
},
596+
"dnslink-website.com": {
597+
Paths: []string{},
598+
NoDNSLink: false,
599+
DeserializedResponses: true,
600+
},
601+
"gateway.com": {
602+
Paths: []string{"/ipfs"},
603+
UseSubdomains: false,
604+
NoDNSLink: true,
605+
DeserializedResponses: true,
606+
},
607+
"subdomain-gateway.com": {
608+
Paths: []string{"/ipfs", "/ipns"},
609+
UseSubdomains: true,
610+
NoDNSLink: true,
611+
DeserializedResponses: true,
612+
},
613+
},
614+
DeserializedResponses: true,
615+
})
616+
617+
for _, test := range []struct {
618+
host string
619+
path string
620+
status int
621+
location string
622+
}{
623+
// Barebones gateway
624+
{"", "/ipfs/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR", http.StatusMovedPermanently, "/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"},
625+
{"", "/ipfs/ipns/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR", http.StatusMovedPermanently, "/ipns/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"},
626+
{"", "/ipfs/ipns/dnslink.com", http.StatusMovedPermanently, "/ipns/dnslink.com"},
627+
628+
// DNSLink Gateway with /ipfs and /ipns enabled
629+
{"dnslink-gateway.com", "/ipfs/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR", http.StatusMovedPermanently, "/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"},
630+
{"dnslink-gateway.com", "/ipfs/ipns/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR", http.StatusMovedPermanently, "/ipns/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"},
631+
{"dnslink-gateway.com", "/ipfs/ipns/dnslink.com", http.StatusMovedPermanently, "/ipns/dnslink.com"},
632+
633+
// DNSLink Gateway without /ipfs and /ipns
634+
{"dnslink-website.com", "/ipfs/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR", http.StatusNotFound, ""},
635+
{"dnslink-website.com", "/ipfs/ipns/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR", http.StatusNotFound, ""},
636+
{"dnslink-website.com", "/ipfs/ipns/dnslink.com", http.StatusNotFound, ""},
637+
638+
// Public gateway
639+
{"gateway.com", "/ipfs/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR", http.StatusMovedPermanently, "/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"},
640+
{"gateway.com", "/ipfs/ipns/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR", http.StatusMovedPermanently, "/ipns/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"},
641+
{"gateway.com", "/ipfs/ipns/dnslink.com", http.StatusMovedPermanently, "/ipns/dnslink.com"},
642+
643+
// Subdomain gateway
644+
{"subdomain-gateway.com", "/ipfs/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR", http.StatusMovedPermanently, "/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"},
645+
{"subdomain-gateway.com", "/ipfs/ipns/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR", http.StatusMovedPermanently, "/ipns/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"},
646+
{"subdomain-gateway.com", "/ipfs/ipns/dnslink.com", http.StatusMovedPermanently, "/ipns/dnslink.com"},
647+
} {
648+
testName := ts.URL + test.path
649+
if test.host != "" {
650+
testName += " " + test.host
651+
}
652+
653+
t.Run(testName, func(t *testing.T) {
654+
req := mustNewRequest(t, http.MethodGet, ts.URL+test.path, nil)
655+
req.Header.Set("Accept", "text/html")
656+
if test.host != "" {
657+
req.Host = test.host
658+
}
659+
resp := mustDoWithoutRedirect(t, req)
660+
defer resp.Body.Close()
661+
require.Equal(t, test.status, resp.StatusCode)
662+
require.Equal(t, test.location, resp.Header.Get("Location"))
663+
})
664+
}
665+
})
580666
}
581667

582668
func TestDeserializedResponses(t *testing.T) {

gateway/handler.go

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"html/template"
87
"io"
98
"mime"
109
"net/http"
@@ -43,26 +42,6 @@ var (
4342
noModtime = time.Unix(0, 0) // disables Last-Modified header if passed as modtime
4443
)
4544

46-
// HTML-based redirect for errors which can be recovered from, but we want
47-
// to provide hint to people that they should fix things on their end.
48-
var redirectTemplate = template.Must(template.New("redirect").Parse(`<!DOCTYPE html>
49-
<html>
50-
<head>
51-
<meta charset="utf-8">
52-
<meta http-equiv="refresh" content="10;url={{.RedirectURL}}" />
53-
<link rel="canonical" href="{{.RedirectURL}}" />
54-
</head>
55-
<body>
56-
<pre>{{.ErrorMsg}}</pre><pre>(if a redirect does not happen in 10 seconds, use "{{.SuggestedPath}}" instead)</pre>
57-
</body>
58-
</html>`))
59-
60-
type redirectTemplateData struct {
61-
RedirectURL string
62-
SuggestedPath string
63-
ErrorMsg string
64-
}
65-
6645
// handler is a HTTP handler that serves IPFS objects (accessible by default at /ipfs/<path>)
6746
// (it serves requests like GET /ipfs/QmVRzPKPzNtSrEzBFm2UZfxmPAgnaLke4DMcerbsGGSaFe/link)
6847
type handler struct {
@@ -903,21 +882,8 @@ func (i *handler) handleSuperfluousNamespace(w http.ResponseWriter, r *http.Requ
903882
q, _ := url.ParseQuery(r.URL.RawQuery)
904883
intendedURL = intendedURL + "?" + q.Encode()
905884
}
906-
// return HTTP 400 (Bad Request) with HTML error page that:
907-
// - points at correct canonical path via <link> header
908-
// - displays human-readable error
909-
// - redirects to intendedURL after a short delay
910-
911-
w.WriteHeader(http.StatusBadRequest)
912-
err = redirectTemplate.Execute(w, redirectTemplateData{
913-
RedirectURL: intendedURL,
914-
SuggestedPath: intendedPath.String(),
915-
ErrorMsg: fmt.Sprintf("invalid path: %q should be %q", r.URL.Path, intendedPath.String()),
916-
})
917-
if err != nil {
918-
_, _ = w.Write([]byte(fmt.Sprintf("error during body generation: %v", err)))
919-
}
920885

886+
http.Redirect(w, r, intendedURL, http.StatusMovedPermanently)
921887
return true
922888
}
923889

0 commit comments

Comments
 (0)