From 45999946be1b6c1e490c00233ba617f758e6e564 Mon Sep 17 00:00:00 2001 From: rht Date: Sat, 30 Jan 2016 10:19:27 +0700 Subject: [PATCH 1/3] Directly wire ctx into http request License: MIT Signed-off-by: rht --- commands/http/client.go | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/commands/http/client.go b/commands/http/client.go index 99a9f131f..1f2ee18c9 100644 --- a/commands/http/client.go +++ b/commands/http/client.go @@ -34,7 +34,7 @@ type Client interface { type client struct { serverAddress string - httpClient http.Client + httpClient *http.Client } func NewClient(address string) Client { @@ -43,7 +43,7 @@ func NewClient(address string) Client { // refused on 'client.Do' return &client{ serverAddress: address, - httpClient: http.Client{ + httpClient: &http.Client{ Transport: &http.Transport{ DisableKeepAlives: true, }, @@ -103,7 +103,7 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) { ec := make(chan error, 1) rc := make(chan cmds.Response, 1) - dc := req.Context().Done() + httpReq.Cancel = req.Context().Done() go func() { httpRes, err := c.httpClient.Do(httpReq) @@ -122,24 +122,17 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) { rc <- res }() - for { - select { - case <-dc: - log.Debug("Context cancelled, cancelling HTTP request...") - tr := http.DefaultTransport.(*http.Transport) - tr.CancelRequest(httpReq) - dc = nil // Wait for ec or rc - case err := <-ec: - return nil, err - case res := <-rc: - if found && len(previousUserProvidedEncoding) > 0 { - // reset to user provided encoding after sending request - // NB: if user has provided an encoding but it is the empty string, - // still leave it as JSON. - req.SetOption(cmds.EncShort, previousUserProvidedEncoding) - } - return res, nil + select { + case err := <-ec: + return nil, err + case res := <-rc: + if found && len(previousUserProvidedEncoding) > 0 { + // reset to user provided encoding after sending request + // NB: if user has provided an encoding but it is the empty string, + // still leave it as JSON. + req.SetOption(cmds.EncShort, previousUserProvidedEncoding) } + return res, nil } } From 72e98deb93355ddfcc179b03cc1d1d5d737ca071 Mon Sep 17 00:00:00 2001 From: rht Date: Sat, 30 Jan 2016 10:22:46 +0700 Subject: [PATCH 2/3] Cleanup http client Send License: MIT Signed-off-by: rht --- commands/http/client.go | 56 ++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 37 deletions(-) diff --git a/commands/http/client.go b/commands/http/client.go index 1f2ee18c9..8489bf9b6 100644 --- a/commands/http/client.go +++ b/commands/http/client.go @@ -38,16 +38,9 @@ type client struct { } func NewClient(address string) Client { - // We cannot use the default transport because of a bug in go's connection reuse - // code. It causes random failures in the connection including io.EOF and connection - // refused on 'client.Do' return &client{ serverAddress: address, - httpClient: &http.Client{ - Transport: &http.Transport{ - DisableKeepAlives: true, - }, - }, + httpClient: http.DefaultClient, } } @@ -101,39 +94,28 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) { } httpReq.Header.Set(uaHeader, config.ApiVersion) - ec := make(chan error, 1) - rc := make(chan cmds.Response, 1) httpReq.Cancel = req.Context().Done() + httpReq.Close = true - go func() { - httpRes, err := c.httpClient.Do(httpReq) - if err != nil { - ec <- err - return - } - - // using the overridden JSON encoding in request - res, err := getResponse(httpRes, req) - if err != nil { - ec <- err - return - } - - rc <- res - }() - - select { - case err := <-ec: + httpRes, err := c.httpClient.Do(httpReq) + if err != nil { return nil, err - case res := <-rc: - if found && len(previousUserProvidedEncoding) > 0 { - // reset to user provided encoding after sending request - // NB: if user has provided an encoding but it is the empty string, - // still leave it as JSON. - req.SetOption(cmds.EncShort, previousUserProvidedEncoding) - } - return res, nil } + + // using the overridden JSON encoding in request + res, err := getResponse(httpRes, req) + if err != nil { + return nil, err + } + + if found && len(previousUserProvidedEncoding) > 0 { + // reset to user provided encoding after sending request + // NB: if user has provided an encoding but it is the empty string, + // still leave it as JSON. + req.SetOption(cmds.EncShort, previousUserProvidedEncoding) + } + + return res, nil } func getQuery(req cmds.Request) (string, error) { From 6f76129b8796701363c5fa9c3e072cb5cb7669e8 Mon Sep 17 00:00:00 2001 From: rht Date: Sat, 30 Jan 2016 10:26:35 +0700 Subject: [PATCH 3/3] Simplify context canceled err message License: MIT Signed-off-by: rht --- cmd/ipfs/main.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index 611dbd695..32d72239c 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -39,6 +39,7 @@ var log = logging.Logger("cmd/ipfs") var ( errUnexpectedApiOutput = errors.New("api returned unexpected output") errApiVersionMismatch = errors.New("api version mismatch") + errRequestCanceled = errors.New("request canceled") ) const ( @@ -328,7 +329,7 @@ func callCommand(ctx context.Context, req cmds.Request, root *cmds.Command, cmd if isConnRefused(err) { err = repo.ErrApiNotRunning } - return nil, err + return nil, wrapContextCanceled(err) } } else { @@ -625,3 +626,10 @@ func isConnRefused(err error) bool { return netoperr.Op == "dial" } + +func wrapContextCanceled(err error) error { + if strings.Contains(err.Error(), "request canceled") { + err = errRequestCanceled + } + return err +}