core: add context.Context param to core.Resolve()
commands/object: remove objectData() and objectLinks() helpers resolver: added context parameters sharness: $HASH carried the \r from the http protocol with sharness: write curl output to individual files http gw: break PUT handler until PR#1191
Henry committed
May 1, 2015 at 17:33 UTC
f640ba00891489361947b49dd5ce05b3349f154a
15 files changed
+134
-128
commands/http/handler.go
+22
-5
@@ -9,6 +9,7 @@ import (
9
"strings"
10
11
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
12
+
13
cmds "github.com/ipfs/go-ipfs/commands"
14
u "github.com/ipfs/go-ipfs/util"
15
)
@@ -48,11 +49,6 @@ func NewHandler(ctx cmds.Context, root *cmds.Command, origin string) *Handler {
49
}
50
51
func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
51
- // create a context.Context to pass into the commands.
52
- ctx, cancel := context.WithCancel(context.TODO())
53
- defer cancel()
54
- i.ctx.Context = ctx
55
-
52
log.Debug("Incoming API request: ", r.URL)
53
54
// error on external referers (to prevent CSRF attacks)
@@ -84,6 +80,27 @@ func (i Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
80
w.Write([]byte(err.Error()))
81
return
82
}
83
+
84
+ // get the node's context to pass into the commands.
85
+ node, err := i.ctx.GetNode()
86
+ if err != nil {
87
+ err = fmt.Errorf("cmds/http: couldn't GetNode(): %s", err)
88
+ http.Error(w, err.Error(), http.StatusInternalServerError)
89
+ return
90
+ }
91
+ ctx, cancel := context.WithCancel(node.Context())
92
+ defer cancel()
93
+ /*
94
+ TODO(cryptix): the next line looks very fishy to me..
95
+ It looks like the the context for the command request beeing prepared here is shared across all incoming requests..
96
+
97
+ I assume it really isn't because ServeHTTP() doesn't take a pointer receiver, but it's really subtule..
98
+
99
+ Shouldn't the context be just put on the command request?
100
+
101
+ ps: take note of the name clash - commands.Context != context.Context
102
+ */
103
+ i.ctx.Context = ctx
104
req.SetContext(i.ctx)
105
106
// call the command
core/commands/cat.go
+1
-1
@@ -62,7 +62,7 @@ func cat(ctx context.Context, node *core.IpfsNode, paths []string) ([]io.Reader,
62
readers := make([]io.Reader, 0, len(paths))
63
length := uint64(0)
64
for _, fpath := range paths {
65
- dagnode, err := core.Resolve(node, path.Path(fpath))
65
+ dagnode, err := core.Resolve(ctx, node, path.Path(fpath))
66
if err != nil {
67
return nil, 0, err
68
}
core/commands/get.go
+6
-5
@@ -9,13 +9,14 @@ import (
9
gopath "path"
10
"strings"
11
12
+ "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/cheggaaa/pb"
13
+ context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
14
+
15
cmds "github.com/ipfs/go-ipfs/commands"
16
core "github.com/ipfs/go-ipfs/core"
17
path "github.com/ipfs/go-ipfs/path"
18
tar "github.com/ipfs/go-ipfs/thirdparty/tar"
19
utar "github.com/ipfs/go-ipfs/unixfs/tar"
17
-
18
- "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/cheggaaa/pb"
20
)
21
22
var ErrInvalidCompressionLevel = errors.New("Compression level must be between 1 and 9")
@@ -62,7 +63,7 @@ may also specify the level of compression by specifying '-l=<1-9>'.
63
return
64
}
65
65
- reader, err := get(node, req.Arguments()[0], cmplvl)
66
+ reader, err := get(req.Context().Context, node, req.Arguments()[0], cmplvl)
67
if err != nil {
68
res.SetError(err, cmds.ErrNormal)
69
return
@@ -165,9 +166,9 @@ func getCompressOptions(req cmds.Request) (int, error) {
166
return gzip.NoCompression, nil
167
}
168
168
-func get(node *core.IpfsNode, p string, compression int) (io.Reader, error) {
169
+func get(ctx context.Context, node *core.IpfsNode, p string, compression int) (io.Reader, error) {
170
pathToResolve := path.Path(p)
170
- dagnode, err := core.Resolve(node, pathToResolve)
171
+ dagnode, err := core.Resolve(ctx, node, pathToResolve)
172
if err != nil {
173
return nil, err
174
}
core/commands/ls.go
+1
-1
@@ -66,7 +66,7 @@ it contains, with the following format:
66
67
dagnodes := make([]*merkledag.Node, 0)
68
for _, fpath := range paths {
69
- dagnode, err := core.Resolve(node, path.Path(fpath))
69
+ dagnode, err := core.Resolve(req.Context().Context, node, path.Path(fpath))
70
if err != nil {
71
res.SetError(err, cmds.ErrNormal)
72
return
core/commands/object.go
+10
-41
@@ -91,12 +91,12 @@ output is the raw data of the object.
91
}
92
93
fpath := path.Path(req.Arguments()[0])
94
- output, err := objectData(n, fpath)
94
+ node, err := core.Resolve(req.Context().Context, n, fpath)
95
if err != nil {
96
res.SetError(err, cmds.ErrNormal)
97
return
98
}
99
- res.SetOutput(output)
99
+ res.SetOutput(bytes.NewReader(node.Data))
100
},
101
}
102
@@ -121,7 +121,12 @@ multihash.
121
}
122
123
fpath := path.Path(req.Arguments()[0])
124
- output, err := objectLinks(n, fpath)
124
+ node, err := core.Resolve(req.Context().Context, n, fpath)
125
+ if err != nil {
126
+ res.SetError(err, cmds.ErrNormal)
127
+ return
128
+ }
129
+ output, err := getOutput(node)
130
if err != nil {
131
res.SetError(err, cmds.ErrNormal)
132
return
@@ -176,7 +181,7 @@ This command outputs data in the following encodings:
181
182
fpath := path.Path(req.Arguments()[0])
183
179
- object, err := objectGet(n, fpath)
184
+ object, err := core.Resolve(req.Context().Context, n, fpath)
185
if err != nil {
186
res.SetError(err, cmds.ErrNormal)
187
return
@@ -242,7 +247,7 @@ var objectStatCmd = &cmds.Command{
247
248
fpath := path.Path(req.Arguments()[0])
249
245
- object, err := objectGet(n, fpath)
250
+ object, err := core.Resolve(req.Context().Context, n, fpath)
251
if err != nil {
252
res.SetError(err, cmds.ErrNormal)
253
return
@@ -343,42 +348,6 @@ Data should be in the format specified by the --inputenc flag.
348
Type: Object{},
349
}
350
346
-// objectData takes a key string and writes out the raw bytes of that node (if there is one)
347
-func objectData(n *core.IpfsNode, fpath path.Path) (io.Reader, error) {
348
- dagnode, err := core.Resolve(n, fpath)
349
- if err != nil {
350
- return nil, err
351
- }
352
-
353
- log.Debugf("objectData: found dagnode %s (# of bytes: %d - # links: %d)", fpath, len(dagnode.Data), len(dagnode.Links))
354
-
355
- return bytes.NewReader(dagnode.Data), nil
356
-}
357
-
358
-// objectLinks takes a key string and lists the links it points to
359
-func objectLinks(n *core.IpfsNode, fpath path.Path) (*Object, error) {
360
- dagnode, err := core.Resolve(n, fpath)
361
- if err != nil {
362
- return nil, err
363
- }
364
-
365
- log.Debugf("objectLinks: found dagnode %s (# of bytes: %d - # links: %d)", fpath, len(dagnode.Data), len(dagnode.Links))
366
-
367
- return getOutput(dagnode)
368
-}
369
-
370
-// objectGet takes a key string from args and a format option and serializes the dagnode to that format
371
-func objectGet(n *core.IpfsNode, fpath path.Path) (*dag.Node, error) {
372
- dagnode, err := core.Resolve(n, fpath)
373
- if err != nil {
374
- return nil, err
375
- }
376
-
377
- log.Debugf("objectGet: found dagnode %s (# of bytes: %d - # links: %d)", fpath, len(dagnode.Data), len(dagnode.Links))
378
-
379
- return dagnode, nil
380
-}
381
-
351
// ErrEmptyNode is returned when the input to 'ipfs object put' contains no data
352
var ErrEmptyNode = errors.New("no data or links in this node")
353
core/commands/publish.go
+7
-4
@@ -6,6 +6,8 @@ import (
6
"io"
7
"strings"
8
9
+ context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10
+
11
cmds "github.com/ipfs/go-ipfs/commands"
12
core "github.com/ipfs/go-ipfs/core"
13
crypto "github.com/ipfs/go-ipfs/p2p/crypto"
@@ -89,7 +91,8 @@ Publish an <ipfs-path> to another public key (not implemented):
91
}
92
93
// TODO n.Keychain.Get(name).PrivKey
92
- output, err := publish(n, n.PrivateKey, p)
94
+ // TODO(cryptix): is req.Context().Context a child of n.Context()?
95
+ output, err := publish(req.Context().Context, n, n.PrivateKey, p)
96
if err != nil {
97
res.SetError(err, cmds.ErrNormal)
98
return
@@ -106,14 +109,14 @@ Publish an <ipfs-path> to another public key (not implemented):
109
Type: IpnsEntry{},
110
}
111
109
-func publish(n *core.IpfsNode, k crypto.PrivKey, ref path.Path) (*IpnsEntry, error) {
112
+func publish(ctx context.Context, n *core.IpfsNode, k crypto.PrivKey, ref path.Path) (*IpnsEntry, error) {
113
// First, verify the path exists
111
- _, err := core.Resolve(n, ref)
114
+ _, err := core.Resolve(ctx, n, ref)
115
if err != nil {
116
return nil, err
117
}
118
116
- err = n.Namesys.Publish(n.Context(), k, ref)
119
+ err = n.Namesys.Publish(ctx, k, ref)
120
if err != nil {
121
return nil, err
122
}
core/commands/refs.go
+3
-3
@@ -85,7 +85,7 @@ Note: list all refs recursively with -r.
85
return
86
}
87
88
- objs, err := objectsForPaths(n, req.Arguments())
88
+ objs, err := objectsForPaths(ctx, n, req.Arguments())
89
if err != nil {
90
res.SetError(err, cmds.ErrNormal)
91
return
@@ -161,10 +161,10 @@ Displays the hashes of all local objects.
161
},
162
}
163
164
-func objectsForPaths(n *core.IpfsNode, paths []string) ([]*dag.Node, error) {
164
+func objectsForPaths(ctx context.Context, n *core.IpfsNode, paths []string) ([]*dag.Node, error) {
165
objects := make([]*dag.Node, len(paths))
166
for i, p := range paths {
167
- o, err := core.Resolve(n, path.Path(p))
167
+ o, err := core.Resolve(ctx, n, path.Path(p))
168
if err != nil {
169
return nil, err
170
}
core/corehttp/gateway_handler.go
+7
-3
@@ -1,6 +1,7 @@
1
package corehttp
2
3
import (
4
+ "errors"
5
"fmt"
6
"html/template"
7
"io"
@@ -101,7 +102,7 @@ func (i *gatewayHandler) ResolvePath(ctx context.Context, p string) (*dag.Node,
102
return nil, "", err
103
}
104
104
- node, err := i.node.Resolver.ResolvePath(path.Path(p))
105
+ node, err := i.node.Resolver.ResolvePath(ctx, path.Path(p))
106
if err != nil {
107
return nil, "", err
108
}
@@ -309,6 +310,9 @@ func (i *gatewayHandler) putEmptyDirHandler(w http.ResponseWriter, r *http.Reque
310
}
311
312
func (i *gatewayHandler) putHandler(w http.ResponseWriter, r *http.Request) {
313
+ // TODO(cryptix): will be resolved in PR#1191
314
+ webErrorWithCode(w, "Sorry, PUT is bugged right now, closing request", errors.New("handler disabled"), http.StatusInternalServerError)
315
+ return
316
urlPath := r.URL.Path
317
pathext := urlPath[5:]
318
var err error
@@ -362,7 +366,7 @@ func (i *gatewayHandler) putHandler(w http.ResponseWriter, r *http.Request) {
366
367
// resolving path components into merkledag nodes. if a component does not
368
// resolve, create empty directories (which will be linked and populated below.)
365
- path_nodes, err := i.node.Resolver.ResolveLinks(rootnd, components[:len(components)-1])
369
+ path_nodes, err := i.node.Resolver.ResolveLinks(tctx, rootnd, components[:len(components)-1])
370
if _, ok := err.(path.ErrNoLink); ok {
371
// Create empty directories, links will be made further down the code
372
for len(path_nodes) < len(components) {
@@ -424,7 +428,7 @@ func (i *gatewayHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
428
return
429
}
430
427
- path_nodes, err := i.node.Resolver.ResolveLinks(rootnd, components[:len(components)-1])
431
+ path_nodes, err := i.node.Resolver.ResolveLinks(tctx, rootnd, components[:len(components)-1])
432
if err != nil {
433
webError(w, "Could not resolve parent object", err, http.StatusBadRequest)
434
return
core/corerepo/pinning.go
+8
-4
@@ -26,10 +26,12 @@ import (
26
)
27
28
func Pin(n *core.IpfsNode, paths []string, recursive bool) ([]u.Key, error) {
29
+ // TODO(cryptix): do we want a ctx as first param for (Un)Pin() as well, just like core.Resolve?
30
+ ctx := n.Context()
31
32
dagnodes := make([]*merkledag.Node, 0)
33
for _, fpath := range paths {
32
- dagnode, err := core.Resolve(n, path.Path(fpath))
34
+ dagnode, err := core.Resolve(ctx, n, path.Path(fpath))
35
if err != nil {
36
return nil, fmt.Errorf("pin: %s", err)
37
}
@@ -43,7 +45,7 @@ func Pin(n *core.IpfsNode, paths []string, recursive bool) ([]u.Key, error) {
45
return nil, err
46
}
47
46
- ctx, cancel := context.WithTimeout(context.TODO(), time.Minute)
48
+ ctx, cancel := context.WithTimeout(ctx, time.Minute)
49
defer cancel()
50
err = n.Pinning.Pin(ctx, dagnode, recursive)
51
if err != nil {
@@ -61,10 +63,12 @@ func Pin(n *core.IpfsNode, paths []string, recursive bool) ([]u.Key, error) {
63
}
64
65
func Unpin(n *core.IpfsNode, paths []string, recursive bool) ([]u.Key, error) {
66
+ // TODO(cryptix): do we want a ctx as first param for (Un)Pin() as well, just like core.Resolve?
67
+ ctx := n.Context()
68
69
dagnodes := make([]*merkledag.Node, 0)
70
for _, fpath := range paths {
67
- dagnode, err := core.Resolve(n, path.Path(fpath))
71
+ dagnode, err := core.Resolve(ctx, n, path.Path(fpath))
72
if err != nil {
73
return nil, err
74
}
@@ -75,7 +79,7 @@ func Unpin(n *core.IpfsNode, paths []string, recursive bool) ([]u.Key, error) {
79
for _, dagnode := range dagnodes {
80
k, _ := dagnode.Key()
81
78
- ctx, cancel := context.WithTimeout(context.TODO(), time.Minute)
82
+ ctx, cancel := context.WithTimeout(ctx, time.Minute)
83
defer cancel()
84
err := n.Pinning.Unpin(ctx, k, recursive)
85
if err != nil {
core/coreunix/cat.go
+1
-1
@@ -10,7 +10,7 @@ import (
10
11
func Cat(n *core.IpfsNode, pstr string) (io.Reader, error) {
12
p := path.FromString(pstr)
13
- dagNode, err := n.Resolver.ResolvePath(p)
13
+ dagNode, err := n.Resolver.ResolvePath(n.ContextGroup.Context(), p)
14
if err != nil {
15
return nil, err
16
}
core/pathresolver.go
+29
-12
@@ -5,22 +5,35 @@ import (
5
"fmt"
6
"strings"
7
8
+ context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9
+
10
merkledag "github.com/ipfs/go-ipfs/merkledag"
11
path "github.com/ipfs/go-ipfs/path"
12
)
13
14
const maxLinks = 32
15
14
-var ErrTooManyLinks = errors.New("exceeded maximum number of links in ipns entry")
16
+// errors returned by Resolve function
17
+var (
18
+ ErrTooManyLinks = errors.New("core/resolve: exceeded maximum number of links in ipns entry")
19
+ ErrNoNamesys = errors.New("core/resolve: no Namesys on IpfsNode - can't resolve ipns entry")
20
+)
21
16
-// Resolves the given path by parsing out /ipns/ entries and then going
22
+// Resolve resolves the given path by parsing out /ipns/ entries and then going
23
// through the /ipfs/ entries and returning the final merkledage node.
24
// Effectively enables /ipns/ in CLI commands.
19
-func Resolve(n *IpfsNode, p path.Path) (*merkledag.Node, error) {
20
- return resolveRecurse(n, p, 0)
25
+func Resolve(ctx context.Context, n *IpfsNode, p path.Path) (*merkledag.Node, error) {
26
+ r := resolver{ctx, n, p}
27
+ return r.resolveRecurse(0)
28
}
29
23
-func resolveRecurse(n *IpfsNode, p path.Path, depth int) (*merkledag.Node, error) {
30
+type resolver struct {
31
+ ctx context.Context
32
+ n *IpfsNode
33
+ p path.Path
34
+}
35
+
36
+func (r *resolver) resolveRecurse(depth int) (*merkledag.Node, error) {
37
if depth >= maxLinks {
38
return nil, ErrTooManyLinks
39
}
@@ -29,29 +42,33 @@ func resolveRecurse(n *IpfsNode, p path.Path, depth int) (*merkledag.Node, error
42
// emerges when resolving just a <hash>. Is it meant
43
// to be an ipfs or an ipns resolution?
44
32
- if strings.HasPrefix(p.String(), "/ipns/") {
45
+ if strings.HasPrefix(r.p.String(), "/ipns/") {
46
+ // TODO(cryptix): we sould be able to query the local cache for the path
47
+ if r.n.Namesys == nil {
48
+ return nil, ErrNoNamesys
49
+ }
50
// if it's an ipns path, try to resolve it.
51
// if we can't, we can give that error back to the user.
35
- seg := p.Segments()
52
+ seg := r.p.Segments()
53
if len(seg) < 2 || seg[1] == "" { // just "/ipns/"
37
- return nil, fmt.Errorf("invalid path: %s", string(p))
54
+ return nil, fmt.Errorf("invalid path: %s", string(r.p))
55
}
56
57
ipnsPath := seg[1]
58
extensions := seg[2:]
42
- respath, err := n.Namesys.Resolve(n.Context(), ipnsPath)
59
+ respath, err := r.n.Namesys.Resolve(r.ctx, ipnsPath)
60
if err != nil {
61
return nil, err
62
}
63
64
segments := append(respath.Segments(), extensions...)
48
- respath, err = path.FromSegments(segments...)
65
+ r.p, err = path.FromSegments(segments...)
66
if err != nil {
67
return nil, err
68
}
52
- return resolveRecurse(n, respath, depth+1)
69
+ return r.resolveRecurse(depth + 1)
70
}
71
72
// ok, we have an ipfs path now (or what we'll treat as one)
56
- return n.Resolver.ResolvePath(p)
73
+ return r.n.Resolver.ResolvePath(r.ctx, r.p)
74
}
fuse/readonly/readonly_unix.go
+2
-2
@@ -56,7 +56,7 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
56
return nil, fuse.ENOENT
57
}
58
59
- nd, err := s.Ipfs.Resolver.ResolvePath(path.Path(name))
59
+ nd, err := s.Ipfs.Resolver.ResolvePath(ctx, path.Path(name))
60
if err != nil {
61
// todo: make this error more versatile.
62
return nil, fuse.ENOENT
@@ -124,7 +124,7 @@ func (s *Node) Attr() fuse.Attr {
124
// Lookup performs a lookup under this node.
125
func (s *Node) Lookup(ctx context.Context, name string) (fs.Node, error) {
126
log.Debugf("Lookup '%s'", name)
127
- nodes, err := s.Ipfs.Resolver.ResolveLinks(s.Nd, []string{name})
127
+ nodes, err := s.Ipfs.Resolver.ResolveLinks(ctx, s.Nd, []string{name})
128
if err != nil {
129
// todo: make this error more versatile.
130
return nil, fuse.ENOENT
ipnsfs/system.go
+1
-1
@@ -163,7 +163,7 @@ func (fs *Filesystem) newKeyRoot(parent context.Context, k ci.PrivKey) (*KeyRoot
163
}
164
}
165
166
- mnode, err := fs.resolver.ResolvePath(pointsTo)
166
+ mnode, err := fs.resolver.ResolvePath(ctx, pointsTo)
167
if err != nil {
168
log.Errorf("Failed to retrieve value '%s' for ipns entry: %s\n", pointsTo, err)
169
return nil, err
path/resolver.go
+14
-15
@@ -1,4 +1,4 @@
1
-// package path implements utilities for resolving paths within ipfs.
1
+// Package path implements utilities for resolving paths within ipfs.
2
package path
3
4
import (
@@ -7,6 +7,7 @@ import (
7
8
mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
9
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
10
+
11
merkledag "github.com/ipfs/go-ipfs/merkledag"
12
u "github.com/ipfs/go-ipfs/util"
13
)
@@ -57,33 +58,32 @@ func SplitAbsPath(fpath Path) (mh.Multihash, []string, error) {
58
59
// ResolvePath fetches the node for given path. It returns the last item
60
// returned by ResolvePathComponents.
60
-func (s *Resolver) ResolvePath(fpath Path) (*merkledag.Node, error) {
61
- nodes, err := s.ResolvePathComponents(fpath)
61
+func (s *Resolver) ResolvePath(ctx context.Context, fpath Path) (*merkledag.Node, error) {
62
+ nodes, err := s.ResolvePathComponents(ctx, fpath)
63
if err != nil || nodes == nil {
64
return nil, err
64
- } else {
65
- return nodes[len(nodes)-1], err
65
}
66
+ return nodes[len(nodes)-1], err
67
}
68
69
// ResolvePathComponents fetches the nodes for each segment of the given path.
70
// It uses the first path component as a hash (key) of the first node, then
71
// resolves all other components walking the links, with ResolveLinks.
72
-func (s *Resolver) ResolvePathComponents(fpath Path) ([]*merkledag.Node, error) {
72
+func (s *Resolver) ResolvePathComponents(ctx context.Context, fpath Path) ([]*merkledag.Node, error) {
73
h, parts, err := SplitAbsPath(fpath)
74
if err != nil {
75
return nil, err
76
}
77
78
- log.Debug("Resolve dag get.\n")
79
- ctx, cancel := context.WithTimeout(context.TODO(), time.Minute)
78
+ log.Debug("Resolve dag get.")
79
+ ctx, cancel := context.WithTimeout(ctx, time.Minute)
80
defer cancel()
81
nd, err := s.DAG.Get(ctx, u.Key(h))
82
if err != nil {
83
return nil, err
84
}
85
86
- return s.ResolveLinks(nd, parts)
86
+ return s.ResolveLinks(ctx, nd, parts)
87
}
88
89
// ResolveLinks iteratively resolves names by walking the link hierarchy.
@@ -93,10 +93,9 @@ func (s *Resolver) ResolvePathComponents(fpath Path) ([]*merkledag.Node, error)
93
//
94
// ResolveLinks(nd, []string{"foo", "bar", "baz"})
95
// would retrieve "baz" in ("bar" in ("foo" in nd.Links).Links).Links
96
-func (s *Resolver) ResolveLinks(ndd *merkledag.Node, names []string) (
97
- result []*merkledag.Node, err error) {
96
+func (s *Resolver) ResolveLinks(ctx context.Context, ndd *merkledag.Node, names []string) ([]*merkledag.Node, error) {
97
99
- result = make([]*merkledag.Node, 0, len(names)+1)
98
+ result := make([]*merkledag.Node, 0, len(names)+1)
99
result = append(result, ndd)
100
nd := ndd // dup arg workaround
101
@@ -121,9 +120,9 @@ func (s *Resolver) ResolveLinks(ndd *merkledag.Node, names []string) (
120
121
if nlink.Node == nil {
122
// fetch object for link and assign to nd
124
- ctx, cancel := context.WithTimeout(context.TODO(), time.Minute)
123
+ ctx, cancel := context.WithTimeout(ctx, time.Minute)
124
defer cancel()
126
- nd, err = s.DAG.Get(ctx, next)
125
+ nd, err := s.DAG.Get(ctx, next)
126
if err != nil {
127
return append(result, nd), err
128
}
@@ -134,5 +133,5 @@ func (s *Resolver) ResolveLinks(ndd *merkledag.Node, names []string) (
133
134
result = append(result, nlink.Node)
135
}
137
- return
136
+ return result, nil
137
}
test/sharness/x0111-gateway-writable.sh
renamed
+22
-30
@@ -26,35 +26,31 @@ test_expect_success "HTTP gateway gives access to sample file" '
26
test_expect_success "HTTP POST file gives Hash" '
27
echo "$RANDOM" >infile &&
28
URL="http://localhost:$port/ipfs/" &&
29
- curl -svX POST --data-binary @infile "$URL" 2>curl.out &&
30
- grep "HTTP/1.1 201 Created" curl.out &&
31
- LOCATION=$(grep Location curl.out) &&
32
- HASH=$(expr "$LOCATION" : "< Location: /ipfs/\(.*\)$")
29
+ curl -svX POST --data-binary @infile "$URL" 2>curl_post.out &&
30
+ grep "HTTP/1.1 201 Created" curl_post.out &&
31
+ LOCATION=$(grep Location curl_post.out) &&
32
+ HASH=$(echo $LOCATION | cut -d":" -f2- |tr -d " \n\r")
33
'
34
35
-# this is failing on osx
36
-# claims "multihash too short. must be > 3 bytes" but the multihash is there.
37
-test_expect_failure "We can HTTP GET file just created" '
38
- URL="http://localhost:$port/ipfs/$HASH" &&
35
+test_expect_success "We can HTTP GET file just created" '
36
+ URL="http://localhost:${port}${HASH}" &&
37
curl -so outfile "$URL" &&
40
- test_cmp infile outfile ||
41
- echo $URL &&
42
- test_fsh cat outfile
38
+ test_cmp infile outfile
39
'
40
41
test_expect_success "HTTP PUT empty directory" '
42
URL="http://localhost:$port/ipfs/$HASH_EMPTY_DIR/" &&
43
echo "PUT $URL" &&
48
- curl -svX PUT "$URL" 2>curl.out &&
49
- cat curl.out &&
50
- grep "Ipfs-Hash: $HASH_EMPTY_DIR" curl.out &&
51
- grep "Location: /ipfs/$HASH_EMPTY_DIR/" curl.out &&
52
- grep "HTTP/1.1 201 Created" curl.out
44
+ curl -svX PUT "$URL" 2>curl_putEmpty.out &&
45
+ cat curl_putEmpty.out &&
46
+ grep "Ipfs-Hash: $HASH_EMPTY_DIR" curl_putEmpty.out &&
47
+ grep "Location: /ipfs/$HASH_EMPTY_DIR/" curl_putEmpty.out &&
48
+ grep "HTTP/1.1 201 Created" curl_putEmpty.out
49
'
50
51
test_expect_success "HTTP GET empty directory" '
52
echo "GET $URL" &&
57
- curl -so outfile "$URL" 2>curl.out &&
53
+ curl -so outfile "$URL" 2>curl_getEmpty.out &&
54
grep "Index of /ipfs/$HASH_EMPTY_DIR/" outfile
55
'
56
@@ -62,9 +58,9 @@ test_expect_success "HTTP PUT file to construct a hierarchy" '
58
echo "$RANDOM" >infile &&
59
URL="http://localhost:$port/ipfs/$HASH_EMPTY_DIR/test.txt" &&
60
echo "PUT $URL" &&
65
- curl -svX PUT --data-binary @infile "$URL" 2>curl.out &&
66
- grep "HTTP/1.1 201 Created" curl.out &&
67
- LOCATION=$(grep Location curl.out) &&
61
+ curl -svX PUT --data-binary @infile "$URL" 2>curl_put.out &&
62
+ grep "HTTP/1.1 201 Created" curl_put.out &&
63
+ LOCATION=$(grep Location curl_put.out) &&
64
HASH=$(expr "$LOCATION" : "< Location: /ipfs/\(.*\)/test.txt")
65
'
66
@@ -79,22 +75,18 @@ test_expect_success "HTTP PUT file to append to existing hierarchy" '
75
echo "$RANDOM" >infile2 &&
76
URL="http://localhost:$port/ipfs/$HASH/test/test.txt" &&
77
echo "PUT $URL" &&
82
- curl -svX PUT --data-binary @infile2 "$URL" 2>curl.out &&
83
- grep "HTTP/1.1 201 Created" curl.out &&
84
- LOCATION=$(grep Location curl.out) &&
78
+ curl -svX PUT --data-binary @infile2 "$URL" 2>curl_putAgain.out &&
79
+ grep "HTTP/1.1 201 Created" curl_putAgain.out &&
80
+ LOCATION=$(grep Location curl_putAgain.out) &&
81
HASH=$(expr "$LOCATION" : "< Location: /ipfs/\(.*\)/test/test.txt")
82
'
83
84
89
-test_expect_success "We can HTTP GET file just created" '
85
+test_expect_success "We can HTTP GET file just updated" '
86
URL="http://localhost:$port/ipfs/$HASH/test/test.txt" &&
87
echo "GET $URL" &&
92
- curl -so outfile2 "$URL" &&
93
- test_cmp infile2 outfile2 &&
94
- URL="http://localhost:$port/ipfs/$HASH/test.txt" &&
95
- echo "GET $URL" &&
96
- curl -so outfile "$URL" &&
97
- test_cmp infile outfile
88
+ curl -svo outfile2 "$URL" 2>curl_getAgain.out &&
89
+ test_cmp infile2 outfile2
90
'
91
92
test_kill_ipfs_daemon