Skip to content

Commit 54e15e6

Browse files
committed
gateway: Turn Symbolic Links Into HTTP Redirects
License: MIT Signed-off-by: Kevin Atkinson <[email protected]>
1 parent 9e8d108 commit 54e15e6

File tree

3 files changed

+51
-4
lines changed

3 files changed

+51
-4
lines changed

core/coreapi/interface/interface.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type UnixfsAPI interface {
2525
Add(context.Context, io.Reader) (*cid.Cid, error)
2626
Cat(context.Context, string) (Reader, error)
2727
Ls(context.Context, string) ([]*Link, error)
28+
ReadSymLink(context.Context, string) (string, error) // Read symbolic link
2829
}
2930

3031
// type ObjectAPI interface {
@@ -50,5 +51,6 @@ type UnixfsAPI interface {
5051
// }
5152

5253
var ErrIsDir = errors.New("object is a directory")
54+
var ErrIsSymLink = errors.New("object is a symbolic link")
5355
var ErrIsNonDag = errors.New("not a merkledag object")
5456
var ErrOffline = errors.New("can't resolve, ipfs node is offline")

core/coreapi/unixfs.go

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ package coreapi
22

33
import (
44
"context"
5+
"errors"
56
"io"
67

78
core "github.com/ipfs/go-ipfs/core"
89
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
910
coreunix "github.com/ipfs/go-ipfs/core/coreunix"
11+
mdag "github.com/ipfs/go-ipfs/merkledag"
1012
uio "github.com/ipfs/go-ipfs/unixfs/io"
13+
ftpb "github.com/ipfs/go-ipfs/unixfs/pb"
1114

15+
proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
1216
cid "gx/ipfs/QmcTcsTvfaeEBRFo1TkFgT8sRmgi1n1LTZpecfVP8fzpGD/go-cid"
1317
)
1418

@@ -36,12 +40,14 @@ func (api *UnixfsAPI) Cat(ctx context.Context, p string) (coreiface.Reader, erro
3640
}
3741

3842
r, err := uio.NewDagReader(ctx, dagnode, api.node.DAG)
39-
if err == uio.ErrIsDir {
43+
switch err {
44+
case uio.ErrIsDir:
4045
return nil, coreiface.ErrIsDir
41-
} else if err != nil {
42-
return nil, err
46+
case uio.ErrCantReadSymlinks:
47+
return nil, coreiface.ErrIsSymLink
48+
default:
4349
}
44-
return r, nil
50+
return r, err;
4551
}
4652

4753
func (api *UnixfsAPI) Ls(ctx context.Context, p string) ([]*coreiface.Link, error) {
@@ -57,3 +63,27 @@ func (api *UnixfsAPI) Ls(ctx context.Context, p string) ([]*coreiface.Link, erro
5763
}
5864
return links, nil
5965
}
66+
67+
var NotASymLink = errors.New("not a symbolic link")
68+
69+
func (api *UnixfsAPI) ReadSymLink(ctx context.Context, p string) (string, error) {
70+
dagnode, err := resolve(ctx, api.node, p)
71+
if err != nil {
72+
return "", err
73+
}
74+
switch n := dagnode.(type) {
75+
case *mdag.ProtoNode:
76+
pb := new(ftpb.Data)
77+
if err := proto.Unmarshal(n.Data(), pb); err != nil {
78+
return "", err
79+
}
80+
switch pb.GetType() {
81+
case ftpb.Data_Symlink:
82+
return string(pb.GetData()), nil
83+
default:
84+
return "", NotASymLink
85+
}
86+
default:
87+
return "", NotASymLink
88+
}
89+
}

core/corehttp/gateway_handler.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,15 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
160160

161161
dr, err := i.api.Cat(ctx, urlPath)
162162
dir := false
163+
symLink := false
163164
switch err {
164165
case nil:
165166
// core.Resolve worked
166167
defer dr.Close()
167168
case coreiface.ErrIsDir:
168169
dir = true
170+
case coreiface.ErrIsSymLink:
171+
symLink = true
169172
case namesys.ErrResolveFailed:
170173
// Don't log that error as it is just noise
171174
w.WriteHeader(http.StatusInternalServerError)
@@ -225,6 +228,18 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
225228
modtime = time.Unix(1, 0)
226229
}
227230

231+
if symLink {
232+
link, err := i.api.ReadSymLink(ctx, urlPath)
233+
if err != nil {
234+
internalWebError(w, err)
235+
return
236+
}
237+
newPath := gopath.Join(gopath.Dir(urlPath), link);
238+
http.Redirect(w, r, newPath, 302)
239+
log.Debugf("symlink: redirect to %s", newPath)
240+
return
241+
}
242+
228243
if !dir {
229244
name := gopath.Base(urlPath)
230245
http.ServeContent(w, r, name, modtime, dr)

0 commit comments

Comments
 (0)