Teach http client to cancel request on context cancellation
The context may be cancelled while a request is in flight. We need to handle this and cancel the request. The code is based on the ideas from https://blog.golang.org/context
Tor Arne Vestbø committed
Apr 17, 2015 at 18:22 UTC
661fb0a4b500d91944a30734d4d1f18bb3146aef
1 file changed
+36
-17
commands/http/client.go
+36
-17
@@ -82,25 +82,44 @@ func (c *client) Send(req cmds.Request) (cmds.Response, error) {
82
version := config.CurrentVersionNumber
83
httpReq.Header.Set("User-Agent", fmt.Sprintf("/go-ipfs/%s/", version))
84
85
- httpRes, err := http.DefaultClient.Do(httpReq)
86
- if err != nil {
87
- return nil, err
88
- }
89
-
90
- // using the overridden JSON encoding in request
91
- res, err := getResponse(httpRes, req)
92
- if err != nil {
93
- return nil, err
94
- }
85
+ ec := make(chan error, 1)
86
+ rc := make(chan cmds.Response, 1)
87
+ dc := req.Context().Context.Done()
88
96
- if found && len(previousUserProvidedEncoding) > 0 {
97
- // reset to user provided encoding after sending request
98
- // NB: if user has provided an encoding but it is the empty string,
99
- // still leave it as JSON.
100
- req.SetOption(cmds.EncShort, previousUserProvidedEncoding)
89
+ go func() {
90
+ httpRes, err := http.DefaultClient.Do(httpReq)
91
+ if err != nil {
92
+ ec <- err
93
+ return
94
+ }
95
+ // using the overridden JSON encoding in request
96
+ res, err := getResponse(httpRes, req)
97
+ if err != nil {
98
+ ec <- err
99
+ return
100
+ }
101
+ rc <- res
102
+ }()
103
+
104
+ for {
105
+ select {
106
+ case <-dc:
107
+ log.Debug("Context cancelled, cancelling HTTP request...")
108
+ tr := http.DefaultTransport.(*http.Transport)
109
+ tr.CancelRequest(httpReq)
110
+ dc = nil // Wait for ec or rc
111
+ case err := <-ec:
112
+ return nil, err
113
+ case res := <-rc:
114
+ if found && len(previousUserProvidedEncoding) > 0 {
115
+ // reset to user provided encoding after sending request
116
+ // NB: if user has provided an encoding but it is the empty string,
117
+ // still leave it as JSON.
118
+ req.SetOption(cmds.EncShort, previousUserProvidedEncoding)
119
+ }
120
+ return res, nil
121
+ }
122
}
102
-
103
- return res, nil
123
}
124
125
func getQuery(req cmds.Request) (string, error) {