Skip to content

Commit 93c2309

Browse files
committedNov 20, 2015
Merge pull request #1971 from ipfs/gateway-url-rewrites
gateway: add path prefix for directory listings
2 parents b9e8c00 + 021ef43 commit 93c2309

File tree

3 files changed

+72
-9
lines changed

3 files changed

+72
-9
lines changed
 

‎core/corehttp/gateway_handler.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,24 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
9292

9393
urlPath := r.URL.Path
9494

95+
// If the gateway is behind a reverse proxy and mounted at a sub-path,
96+
// the prefix header can be set to signal this sub-path.
97+
// It will be prepended to links in directory listings and the index.html redirect.
98+
prefix := ""
99+
if prefixHdr := r.Header["X-Ipfs-Gateway-Prefix"]; len(prefixHdr) > 0 {
100+
log.Debugf("X-Ipfs-Gateway-Prefix: %s", prefixHdr[0])
101+
prefix = prefixHdr[0]
102+
}
103+
95104
// IPNSHostnameOption might have constructed an IPNS path using the Host header.
96105
// In this case, we need the original path for constructing redirects
97106
// and links that match the requested URL.
98107
// For example, http://example.net would become /ipns/example.net, and
99108
// the redirects and links would end up as http://example.net/ipns/example.net
100-
originalUrlPath := urlPath
109+
originalUrlPath := prefix + urlPath
101110
ipnsHostname := false
102-
hdr := r.Header["X-IPNS-Original-Path"]
103-
if len(hdr) > 0 {
104-
originalUrlPath = hdr[0]
111+
if hdr := r.Header["X-Ipns-Original-Path"]; len(hdr) > 0 {
112+
originalUrlPath = prefix + hdr[0]
105113
ipnsHostname = true
106114
}
107115

@@ -211,7 +219,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
211219
if r.Method != "HEAD" {
212220
// construct the correct back link
213221
// https://github.com/ipfs/go-ipfs/issues/1365
214-
var backLink string = urlPath
222+
var backLink string = prefix + urlPath
215223

216224
// don't go further up than /ipfs/$hash/
217225
pathSplit := strings.Split(backLink, "/")
@@ -233,7 +241,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
233241

234242
// strip /ipfs/$hash from backlink if IPNSHostnameOption touched the path.
235243
if ipnsHostname {
236-
backLink = "/"
244+
backLink = prefix + "/"
237245
if len(pathSplit) > 5 {
238246
// also strip the trailing segment, because it's a backlink
239247
backLinkParts := pathSplit[3 : len(pathSplit)-2]

‎core/corehttp/gateway_test.go

+57-2
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,30 @@ func TestIPNSHostnameRedirect(t *testing.T) {
213213
} else if hdr[0] != "/foo/" {
214214
t.Errorf("location header is %v, expected /foo/", hdr[0])
215215
}
216+
217+
// make request with prefix to directory containing index.html
218+
req, err = http.NewRequest("GET", ts.URL+"/foo", nil)
219+
if err != nil {
220+
t.Fatal(err)
221+
}
222+
req.Host = "example.net"
223+
req.Header.Set("X-Ipfs-Gateway-Prefix", "/prefix")
224+
225+
res, err = doWithoutRedirect(req)
226+
if err != nil {
227+
t.Fatal(err)
228+
}
229+
230+
// expect 302 redirect to same path, but with prefix and trailing slash
231+
if res.StatusCode != 302 {
232+
t.Errorf("status is %d, expected 302", res.StatusCode)
233+
}
234+
hdr = res.Header["Location"]
235+
if len(hdr) < 1 {
236+
t.Errorf("location header not present")
237+
} else if hdr[0] != "/prefix/foo/" {
238+
t.Errorf("location header is %v, expected /prefix/foo/", hdr[0])
239+
}
216240
}
217241

218242
func TestIPNSHostnameBacklinks(t *testing.T) {
@@ -282,7 +306,7 @@ func TestIPNSHostnameBacklinks(t *testing.T) {
282306
t.Fatalf("expected file in directory listing")
283307
}
284308

285-
// make request to directory listing
309+
// make request to directory listing at root
286310
req, err = http.NewRequest("GET", ts.URL, nil)
287311
if err != nil {
288312
t.Fatal(err)
@@ -294,7 +318,7 @@ func TestIPNSHostnameBacklinks(t *testing.T) {
294318
t.Fatal(err)
295319
}
296320

297-
// expect correct backlinks
321+
// expect correct backlinks at root
298322
body, err = ioutil.ReadAll(res.Body)
299323
if err != nil {
300324
t.Fatalf("error reading response: %s", err)
@@ -341,4 +365,35 @@ func TestIPNSHostnameBacklinks(t *testing.T) {
341365
if !strings.Contains(s, "<a href=\"/foo/bar/file.txt\">") {
342366
t.Fatalf("expected file in directory listing")
343367
}
368+
369+
// make request to directory listing with prefix
370+
req, err = http.NewRequest("GET", ts.URL, nil)
371+
if err != nil {
372+
t.Fatal(err)
373+
}
374+
req.Host = "example.net"
375+
req.Header.Set("X-Ipfs-Gateway-Prefix", "/prefix")
376+
377+
res, err = doWithoutRedirect(req)
378+
if err != nil {
379+
t.Fatal(err)
380+
}
381+
382+
// expect correct backlinks with prefix
383+
body, err = ioutil.ReadAll(res.Body)
384+
if err != nil {
385+
t.Fatalf("error reading response: %s", err)
386+
}
387+
s = string(body)
388+
t.Logf("body: %s\n", string(body))
389+
390+
if !strings.Contains(s, "Index of /prefix") {
391+
t.Fatalf("expected a path in directory listing")
392+
}
393+
if !strings.Contains(s, "<a href=\"/prefix/\">") {
394+
t.Fatalf("expected backlink in directory listing")
395+
}
396+
if !strings.Contains(s, "<a href=\"/prefix/file.txt\">") {
397+
t.Fatalf("expected file in directory listing")
398+
}
344399
}

‎core/corehttp/ipns_hostname.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func IPNSHostnameOption() ServeOption {
2424
if len(host) > 0 && isd.IsDomain(host) {
2525
name := "/ipns/" + host
2626
if _, err := n.Namesys.Resolve(ctx, name); err == nil {
27-
r.Header["X-IPNS-Original-Path"] = []string{r.URL.Path}
27+
r.Header["X-Ipns-Original-Path"] = []string{r.URL.Path}
2828
r.URL.Path = name + r.URL.Path
2929
}
3030
}

0 commit comments

Comments
 (0)
Please sign in to comment.