@cryptotaxi247 / kubo / commits / f640ba008

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