@@ -14,17 +14,16 @@ import (
14
14
"strings"
15
15
"time"
16
16
17
- "github.com/dustin/go-humanize"
17
+ humanize "github.com/dustin/go-humanize"
18
18
"github.com/ipfs/go-cid"
19
19
files "github.com/ipfs/go-ipfs-files"
20
20
dag "github.com/ipfs/go-merkledag"
21
- "github.com/ipfs/go-mfs"
22
- "github.com/ipfs/go-path"
21
+ mfs "github.com/ipfs/go-mfs"
22
+ path "github.com/ipfs/go-path"
23
23
"github.com/ipfs/go-path/resolver"
24
24
coreiface "github.com/ipfs/interface-go-ipfs-core"
25
25
ipath "github.com/ipfs/interface-go-ipfs-core/path"
26
26
routing "github.com/libp2p/go-libp2p-core/routing"
27
- "github.com/multiformats/go-multibase"
28
27
)
29
28
30
29
const (
@@ -39,6 +38,25 @@ type gatewayHandler struct {
39
38
api coreiface.CoreAPI
40
39
}
41
40
41
+ // StatusResponseWriter enables us to override HTTP Status Code passed to
42
+ // WriteHeader function inside of http.ServeContent. Decision is based on
43
+ // presence of HTTP Headers such as Location.
44
+ type statusResponseWriter struct {
45
+ http.ResponseWriter
46
+ }
47
+
48
+ func (sw * statusResponseWriter ) WriteHeader (code int ) {
49
+ // Check if we need to adjust Status Code to account for scheduled redirect
50
+ // This enables us to return payload along with HTTP 301
51
+ // for subdomain redirect in web browsers while also returning body for cli
52
+ // tools which do not follow redirects by default (curl, wget).
53
+ redirect := sw .ResponseWriter .Header ().Get ("Location" )
54
+ if redirect != "" && code == http .StatusOK {
55
+ code = http .StatusMovedPermanently
56
+ }
57
+ sw .ResponseWriter .WriteHeader (code )
58
+ }
59
+
42
60
func newGatewayHandler (c GatewayConfig , api coreiface.CoreAPI ) * gatewayHandler {
43
61
i := & gatewayHandler {
44
62
config : c ,
@@ -143,17 +161,17 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
143
161
}
144
162
}
145
163
146
- // IPNSHostnameOption might have constructed an IPNS path using the Host header.
164
+ // HostnameOption might have constructed an IPNS/IPFS path using the Host header.
147
165
// In this case, we need the original path for constructing redirects
148
166
// and links that match the requested URL.
149
167
// For example, http://example.net would become /ipns/example.net, and
150
168
// the redirects and links would end up as http://example.net/ipns/example.net
151
- originalUrlPath := prefix + urlPath
152
- ipnsHostname := false
153
- if hdr := r .Header .Get ("X-Ipns-Original-Path" ); len (hdr ) > 0 {
154
- originalUrlPath = prefix + hdr
155
- ipnsHostname = true
169
+ requestURI , err := url .ParseRequestURI (r .RequestURI )
170
+ if err != nil {
171
+ webError (w , "failed to parse request path" , err , http .StatusInternalServerError )
172
+ return
156
173
}
174
+ originalUrlPath := prefix + requestURI .Path
157
175
158
176
// Service Worker registration request
159
177
if r .Header .Get ("Service-Worker" ) == "script" {
@@ -206,39 +224,6 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
206
224
w .Header ().Set ("X-IPFS-Path" , urlPath )
207
225
w .Header ().Set ("Etag" , etag )
208
226
209
- // Suborigin header, sandboxes apps from each other in the browser (even
210
- // though they are served from the same gateway domain).
211
- //
212
- // Omitted if the path was treated by IPNSHostnameOption(), for example
213
- // a request for http://example.net/ would be changed to /ipns/example.net/,
214
- // which would turn into an incorrect Suborigin header.
215
- // In this case the correct thing to do is omit the header because it is already
216
- // handled correctly without a Suborigin.
217
- //
218
- // NOTE: This is not yet widely supported by browsers.
219
- if ! ipnsHostname {
220
- // e.g.: 1="ipfs", 2="QmYuNaKwY...", ...
221
- pathComponents := strings .SplitN (urlPath , "/" , 4 )
222
-
223
- var suboriginRaw []byte
224
- cidDecoded , err := cid .Decode (pathComponents [2 ])
225
- if err != nil {
226
- // component 2 doesn't decode with cid, so it must be a hostname
227
- suboriginRaw = []byte (strings .ToLower (pathComponents [2 ]))
228
- } else {
229
- suboriginRaw = cidDecoded .Bytes ()
230
- }
231
-
232
- base32Encoded , err := multibase .Encode (multibase .Base32 , suboriginRaw )
233
- if err != nil {
234
- internalWebError (w , err )
235
- return
236
- }
237
-
238
- suborigin := pathComponents [1 ] + "000" + strings .ToLower (base32Encoded )
239
- w .Header ().Set ("Suborigin" , suborigin )
240
- }
241
-
242
227
// set these headers _after_ the error, for we may just not have it
243
228
// and dont want the client to cache a 500 response...
244
229
// and only if it's /ipfs!
@@ -322,10 +307,10 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
322
307
323
308
// construct the correct back link
324
309
// https://github.com/ipfs/go-ipfs/issues/1365
325
- var backLink string = prefix + urlPath
310
+ var backLink string = originalUrlPath
326
311
327
312
// don't go further up than /ipfs/$hash/
328
- pathSplit := path .SplitList (backLink )
313
+ pathSplit := path .SplitList (urlPath )
329
314
switch {
330
315
// keep backlink
331
316
case len (pathSplit ) == 3 : // url: /ipfs/$hash
@@ -342,18 +327,8 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
342
327
}
343
328
}
344
329
345
- // strip /ipfs/$hash from backlink if IPNSHostnameOption touched the path.
346
- if ipnsHostname {
347
- backLink = prefix + "/"
348
- if len (pathSplit ) > 5 {
349
- // also strip the trailing segment, because it's a backlink
350
- backLinkParts := pathSplit [3 : len (pathSplit )- 2 ]
351
- backLink += path .Join (backLinkParts ) + "/"
352
- }
353
- }
354
-
355
330
var hash string
356
- if ! strings .HasPrefix (originalUrlPath , ipfsPathPrefix ) {
331
+ if ! strings .HasPrefix (urlPath , ipfsPathPrefix ) {
357
332
hash = resolvedPath .Cid ().String ()
358
333
}
359
334
@@ -410,6 +385,7 @@ func (i *gatewayHandler) serveFile(w http.ResponseWriter, req *http.Request, nam
410
385
}
411
386
w .Header ().Set ("Content-Type" , ctype )
412
387
388
+ w = & statusResponseWriter {w }
413
389
http .ServeContent (w , req , name , modtime , content )
414
390
}
415
391
0 commit comments