improved gateway directory listing for sharded nodes
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
Jeromy committed
May 4, 2017 at 17:41 UTC
5bb480b4dab0a4a7b1fd8cd0a496f84fff911a65
1 file changed
+81
-69
core/corehttp/gateway_handler.go
+81
-69
@@ -6,6 +6,7 @@ import (
6
"fmt"
7
"io"
8
"net/http"
9
+ "os"
10
gopath "path"
11
"runtime/debug"
12
"strings"
@@ -20,6 +21,7 @@ import (
21
dagutils "github.com/ipfs/go-ipfs/merkledag/utils"
22
path "github.com/ipfs/go-ipfs/path"
23
ft "github.com/ipfs/go-ipfs/unixfs"
24
+ uio "github.com/ipfs/go-ipfs/unixfs/io"
25
26
humanize "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
27
cid "gx/ipfs/QmYhQaCYEcaPPjxJX7YcPcVKkQfRy6sJ7B3XmGFk82XYdQ/go-cid"
@@ -227,92 +229,102 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
229
return
230
}
231
230
- links, err := i.api.Unixfs().Ls(ctx, resolvedPath)
232
+ nd, err := i.api.ResolveNode(ctx, resolvedPath)
233
if err != nil {
234
internalWebError(w, err)
235
return
236
}
237
236
- // storage for directory listing
237
- var dirListing []directoryItem
238
- // loop through files
239
- foundIndex := false
240
- for _, link := range links {
241
- if link.Name == "index.html" {
242
- log.Debugf("found index.html link for %s", urlPath)
243
- foundIndex = true
244
-
245
- if urlPath[len(urlPath)-1] != '/' {
246
- // See comment above where originalUrlPath is declared.
247
- http.Redirect(w, r, originalUrlPath+"/", 302)
248
- log.Debugf("redirect to %s", originalUrlPath+"/")
249
- return
250
- }
238
+ dirr, err := uio.NewDirectoryFromNode(i.node.DAG, nd)
239
+ if err != nil {
240
+ internalWebError(w, err)
241
+ return
242
+ }
243
252
- dr, err := i.api.Unixfs().Cat(ctx, coreapi.ParseCid(link.Cid))
253
- if err != nil {
254
- internalWebError(w, err)
255
- return
256
- }
257
- defer dr.Close()
244
+ ixnd, err := dirr.Find(ctx, "index.html")
245
+ switch {
246
+ case err == nil:
247
+ log.Debugf("found index.html link for %s", urlPath)
248
+
249
+ if urlPath[len(urlPath)-1] != '/' {
250
+ // See comment above where originalUrlPath is declared.
251
+ http.Redirect(w, r, originalUrlPath+"/", 302)
252
+ log.Debugf("redirect to %s", originalUrlPath+"/")
253
+ return
254
+ }
255
259
- // write to request
260
- http.ServeContent(w, r, "index.html", modtime, dr)
261
- break
256
+ dr, err := i.api.Unixfs().Cat(ctx, coreapi.ParseCid(ixnd.Cid()))
257
+ if err != nil {
258
+ internalWebError(w, err)
259
+ return
260
}
261
+ defer dr.Close()
262
263
+ // write to request
264
+ http.ServeContent(w, r, "index.html", modtime, dr)
265
+ return
266
+ default:
267
+ internalWebError(w, err)
268
+ return
269
+ case os.IsNotExist(err):
270
+ }
271
+
272
+ if r.Method == "HEAD" {
273
+ return
274
+ }
275
+
276
+ // storage for directory listing
277
+ var dirListing []directoryItem
278
+ dirr.ForEachLink(ctx, func(link *node.Link) error {
279
// See comment above where originalUrlPath is declared.
280
di := directoryItem{humanize.Bytes(link.Size), link.Name, gopath.Join(originalUrlPath, link.Name)}
281
dirListing = append(dirListing, di)
267
- }
282
+ return nil
283
+ })
284
269
- if !foundIndex {
270
- if r.Method != "HEAD" {
271
- // construct the correct back link
272
- // https://github.com/ipfs/go-ipfs/issues/1365
273
- var backLink string = prefix + urlPath
274
-
275
- // don't go further up than /ipfs/$hash/
276
- pathSplit := path.SplitList(backLink)
277
- switch {
278
- // keep backlink
279
- case len(pathSplit) == 3: // url: /ipfs/$hash
280
-
281
- // keep backlink
282
- case len(pathSplit) == 4 && pathSplit[3] == "": // url: /ipfs/$hash/
283
-
284
- // add the correct link depending on wether the path ends with a slash
285
- default:
286
- if strings.HasSuffix(backLink, "/") {
287
- backLink += "./.."
288
- } else {
289
- backLink += "/.."
290
- }
291
- }
285
+ // construct the correct back link
286
+ // https://github.com/ipfs/go-ipfs/issues/1365
287
+ var backLink string = prefix + urlPath
288
293
- // strip /ipfs/$hash from backlink if IPNSHostnameOption touched the path.
294
- if ipnsHostname {
295
- backLink = prefix + "/"
296
- if len(pathSplit) > 5 {
297
- // also strip the trailing segment, because it's a backlink
298
- backLinkParts := pathSplit[3 : len(pathSplit)-2]
299
- backLink += path.Join(backLinkParts) + "/"
300
- }
301
- }
289
+ // don't go further up than /ipfs/$hash/
290
+ pathSplit := path.SplitList(backLink)
291
+ switch {
292
+ // keep backlink
293
+ case len(pathSplit) == 3: // url: /ipfs/$hash
294
303
- // See comment above where originalUrlPath is declared.
304
- tplData := listingTemplateData{
305
- Listing: dirListing,
306
- Path: originalUrlPath,
307
- BackLink: backLink,
308
- }
309
- err := listingTemplate.Execute(w, tplData)
310
- if err != nil {
311
- internalWebError(w, err)
312
- return
313
- }
295
+ // keep backlink
296
+ case len(pathSplit) == 4 && pathSplit[3] == "": // url: /ipfs/$hash/
297
+
298
+ // add the correct link depending on wether the path ends with a slash
299
+ default:
300
+ if strings.HasSuffix(backLink, "/") {
301
+ backLink += "./.."
302
+ } else {
303
+ backLink += "/.."
304
}
305
}
306
+
307
+ // strip /ipfs/$hash from backlink if IPNSHostnameOption touched the path.
308
+ if ipnsHostname {
309
+ backLink = prefix + "/"
310
+ if len(pathSplit) > 5 {
311
+ // also strip the trailing segment, because it's a backlink
312
+ backLinkParts := pathSplit[3 : len(pathSplit)-2]
313
+ backLink += path.Join(backLinkParts) + "/"
314
+ }
315
+ }
316
+
317
+ // See comment above where originalUrlPath is declared.
318
+ tplData := listingTemplateData{
319
+ Listing: dirListing,
320
+ Path: originalUrlPath,
321
+ BackLink: backLink,
322
+ }
323
+ err = listingTemplate.Execute(w, tplData)
324
+ if err != nil {
325
+ internalWebError(w, err)
326
+ return
327
+ }
328
}
329
330
func (i *gatewayHandler) postHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {