提交 0fe423c6 作者: Kevin Atkinson

gateway: Turn Symbolic Links Into HTTP Redirects

License: MIT
Signed-off-by: 's avatarKevin Atkinson <k@kevina.org>
上级 139d6240
......@@ -3,6 +3,7 @@ package iface
import "errors"
var (
ErrIsDir = errors.New("object is a directory")
ErrOffline = errors.New("can't resolve, ipfs node is offline")
ErrIsDir = errors.New("object is a directory")
ErrOffline = errors.New("can't resolve, ipfs node is offline")
ErrIsSymLink = errors.New("object is a symbolic link")
)
......@@ -17,4 +17,7 @@ type UnixfsAPI interface {
// Ls returns the list of links in a directory
Ls(context.Context, Path) ([]*ipld.Link, error)
// ReadSymLink returns the contents of a symbolic link
ReadSymLink(context.Context, Path) (string, error)
}
......@@ -2,12 +2,16 @@ package coreapi
import (
"context"
"errors"
"io"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
coreunix "github.com/ipfs/go-ipfs/core/coreunix"
mdag "github.com/ipfs/go-ipfs/merkledag"
uio "github.com/ipfs/go-ipfs/unixfs/io"
ftpb "github.com/ipfs/go-ipfs/unixfs/pb"
proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
cid "gx/ipfs/QmcZfnkapfECQGcLZaf9B79NRg7cRa9EnZh4LSbkCzwNvY/go-cid"
ipld "gx/ipfs/Qme5bWv7wtjUNGsK2BNGVUFPKiuxWrsqrtvYwCLRw8YFES/go-ipld-format"
)
......@@ -38,12 +42,14 @@ func (api *UnixfsAPI) Cat(ctx context.Context, p coreiface.Path) (coreiface.Read
}
r, err := uio.NewDagReader(ctx, dagnode, dget)
if err == uio.ErrIsDir {
switch err {
case uio.ErrIsDir:
return nil, coreiface.ErrIsDir
} else if err != nil {
return nil, err
case uio.ErrCantReadSymlinks:
return nil, coreiface.ErrIsSymLink
default:
}
return r, nil
return r, err
}
// Ls returns the contents of an IPFS or IPNS object(s) at path p, with the format:
......@@ -76,6 +82,30 @@ func (api *UnixfsAPI) Ls(ctx context.Context, p coreiface.Path) ([]*ipld.Link, e
return links, nil
}
var NotASymLink = errors.New("not a symbolic link")
func (api *UnixfsAPI) ReadSymLink(ctx context.Context, p coreiface.Path) (string, error) {
dagnode, err := api.core().ResolveNode(ctx, p)
if err != nil {
return "", err
}
switch n := dagnode.(type) {
case *mdag.ProtoNode:
pb := new(ftpb.Data)
if err := proto.Unmarshal(n.Data(), pb); err != nil {
return "", err
}
switch pb.GetType() {
case ftpb.Data_Symlink:
return string(pb.GetData()), nil
default:
return "", NotASymLink
}
default:
return "", NotASymLink
}
}
func (api *UnixfsAPI) core() coreiface.CoreAPI {
return (*CoreAPI)(api)
}
......@@ -185,12 +185,15 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
dr, err := i.api.Unixfs().Cat(ctx, resolvedPath)
dir := false
symLink := false
switch err {
case nil:
// Cat() worked
defer dr.Close()
case coreiface.ErrIsDir:
dir = true
case coreiface.ErrIsSymLink:
symLink = true
default:
webError(w, "ipfs cat "+escapedURLPath, err, http.StatusNotFound)
return
......@@ -266,6 +269,18 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
modtime = time.Unix(1, 0)
}
if symLink {
link, err := i.api.Unixfs().ReadSymLink(ctx, resolvedPath)
if err != nil {
internalWebError(w, err)
return
}
newPath := gopath.Join(gopath.Dir(urlPath), link)
http.Redirect(w, r, newPath, 302)
log.Debugf("symlink: redirect to %s", newPath)
return
}
if !dir {
name := gopath.Base(urlPath)
i.serveFile(w, r, name, modtime, dr)
......
......@@ -193,6 +193,46 @@ test_expect_success "GET compact blocks succeeds" '
test_cmp expected actual
'
#
#
#
test_expect_success "create dir with symbolic links" '
mkdir dirwlinks/ &&
( cd dirwlinks &&
echo "A Simple File" > afile &&
ln -s afile linktofile &&
mkdir adir &&
echo "Another File" > adir/bfile &&
ln -s adir linktodir
)
'
test_expect_success "add dir with symbolic links" '
DIRHASH=$(ipfs add -Q -r dirwlinks)
echo $DIRHASH
'
test_expect_success "getting afile works" '
curl -L -o actual "http://127.0.0.1:$port/ipfs/$DIRHASH/afile" &&
test_cmp dirwlinks/afile actual
'
test_expect_success "getting linktofile works" '
curl -L -o actual "http://127.0.0.1:$port/ipfs/$DIRHASH/linktofile" &&
test_cmp dirwlinks/afile actual
'
test_expect_success "getting adir/bfile works" '
curl -L -o actual "http://127.0.0.1:$port/ipfs/$DIRHASH/adir/bfile" &&
test_cmp dirwlinks/adir/bfile actual
'
test_expect_failure "getting linktodir/bfile works" '
curl -L -o actual "http://127.0.0.1:$port/ipfs/$DIRHASH/linktodir/bfile" &&
test_cmp dirwlinks/adir/bfile actual
'
test_kill_ipfs_daemon
test_done
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论