diff --git a/commands/http/handler.go b/commands/http/handler.go index 774c5ca4a..772e7b7c2 100644 --- a/commands/http/handler.go +++ b/commands/http/handler.go @@ -7,6 +7,7 @@ import ( "net/http" "strconv" "strings" + "time" "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/rs/cors" context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" @@ -106,20 +107,36 @@ func (i internalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusInternalServerError) return } - ctx, cancel := context.WithCancel(node.Context()) - defer cancel() - /* - TODO(cryptix): the next line looks very fishy to me.. - It looks like the the context for the command request beeing prepared here is shared across all incoming requests.. - I assume it really isn't because ServeHTTP() doesn't take a pointer receiver, but it's really subtule.. + tout, found, err := req.Option("timeout").String() + if err != nil { + err = fmt.Errorf("error parsing timeout option: %s", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } - Shouldn't the context be just put on the command request? + var ctx context.Context + if found { + duration, err := time.ParseDuration(tout) + if err != nil { + err = fmt.Errorf("error parsing timeout option: %s", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } - ps: take note of the name clash - commands.Context != context.Context - */ - i.ctx.Context = ctx - req.SetContext(i.ctx) + tctx, cancel := context.WithTimeout(node.Context(), duration) + defer cancel() + ctx = tctx + } else { + cctx, cancel := context.WithCancel(node.Context()) + defer cancel() + ctx = cctx + } + + //ps: take note of the name clash - commands.Context != context.Context + cmdctx := i.ctx + cmdctx.Context = ctx + req.SetContext(cmdctx) // call the command res := i.root.Call(req) diff --git a/commands/option.go b/commands/option.go index 85ed78015..fdab518a9 100644 --- a/commands/option.go +++ b/commands/option.go @@ -154,22 +154,25 @@ func (ov OptionValue) String() (value string, found bool, err error) { // Flag names const ( - EncShort = "enc" - EncLong = "encoding" - RecShort = "r" - RecLong = "recursive" - ChanOpt = "stream-channels" + EncShort = "enc" + EncLong = "encoding" + RecShort = "r" + RecLong = "recursive" + ChanOpt = "stream-channels" + TimeoutOpt = "timeout" ) // options that are used by this package var OptionEncodingType = StringOption(EncShort, EncLong, "The encoding type the output should be encoded with (json, xml, or text)") var OptionRecursivePath = BoolOption(RecShort, RecLong, "Add directory paths recursively") var OptionStreamChannels = BoolOption(ChanOpt, "Stream channel output") +var OptionTimeout = StringOption(TimeoutOpt, "set a global timeout on the command") // global options, added to every command var globalOptions = []Option{ OptionEncodingType, OptionStreamChannels, + OptionTimeout, } // the above array of Options, wrapped in a Command diff --git a/core/commands/block.go b/core/commands/block.go index 38d1533fc..6346e53ac 100644 --- a/core/commands/block.go +++ b/core/commands/block.go @@ -9,7 +9,6 @@ import ( "strings" mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash" - "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "github.com/ipfs/go-ipfs/blocks" key "github.com/ipfs/go-ipfs/blocks/key" cmds "github.com/ipfs/go-ipfs/commands" @@ -178,7 +177,7 @@ func getBlockForKey(req cmds.Request, skey string) (*blocks.Block, error) { } k := key.Key(h) - b, err := n.Blocks.GetBlock(context.TODO(), k) + b, err := n.Blocks.GetBlock(req.Context().Context, k) if err != nil { return nil, err } diff --git a/core/commands/ls.go b/core/commands/ls.go index 758709944..27f11d1da 100644 --- a/core/commands/ls.go +++ b/core/commands/ls.go @@ -81,7 +81,7 @@ it contains, with the following format: Links: make([]LsLink, len(dagnode.Links)), } for j, link := range dagnode.Links { - ctx, cancel := context.WithTimeout(context.TODO(), time.Minute) + ctx, cancel := context.WithTimeout(req.Context().Context, time.Minute) defer cancel() link.Node, err = link.GetNode(ctx, node.DAG) if err != nil {