@cryptotaxi247 / kubo / commits / 5bb480b4d

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) {