client: always cancel in-flight request when do request

This fits the way for go1.5 to cancel request.
This commit is contained in:
Yicheng Qin 2015-08-24 10:42:28 -07:00
parent ece39c9462
commit 27b9963959
6 changed files with 123 additions and 20 deletions

20
client/cancelreq.go Normal file
View File

@ -0,0 +1,20 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// borrowed from golang/net/context/ctxhttp/cancelreq.go
// +build go1.5
package client
import "net/http"
func requestCanceler(tr CancelableTransport, req *http.Request) func() {
ch := make(chan struct{})
req.Cancel = ch
return func() {
close(ch)
}
}

17
client/cancelreq_go14.go Normal file
View File

@ -0,0 +1,17 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// borrowed from golang/net/context/ctxhttp/cancelreq_go14.go
// +build !go1.5
package client
import "net/http"
func requestCanceler(tr CancelableTransport, req *http.Request) func() {
return func() {
tr.CancelRequest(req)
}
}

View File

@ -384,6 +384,8 @@ func (c *simpleHTTPClient) Do(ctx context.Context, act httpAction) (*http.Respon
}
defer hcancel()
reqcancel := requestCanceler(c.transport, req)
rtchan := make(chan roundTripResponse, 1)
go func() {
resp, err := c.transport.RoundTrip(req)
@ -399,7 +401,7 @@ func (c *simpleHTTPClient) Do(ctx context.Context, act httpAction) (*http.Respon
resp, err = rtresp.resp, rtresp.err
case <-hctx.Done():
// cancel and wait for request to actually exit before continuing
c.transport.CancelRequest(req)
reqcancel()
rtresp := <-rtchan
resp = rtresp.resp
switch {

View File

@ -109,25 +109,6 @@ func newFakeTransport() *fakeTransport {
}
}
func (t *fakeTransport) RoundTrip(*http.Request) (*http.Response, error) {
select {
case resp := <-t.respchan:
return resp, nil
case err := <-t.errchan:
return nil, err
case <-t.startCancel:
select {
// this simulates that the request is finished before cancel effects
case resp := <-t.respchan:
return resp, nil
// wait on finishCancel to simulate taking some amount of
// time while calling CancelRequest
case <-t.finishCancel:
return nil, errors.New("cancelled")
}
}
}
func (t *fakeTransport) CancelRequest(*http.Request) {
t.startCancel <- struct{}{}
}

View File

@ -0,0 +1,41 @@
// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !go1.5
package client
import (
"errors"
"net/http"
)
func (t *fakeTransport) RoundTrip(req *http.Request) (*http.Response, error) {
select {
case resp := <-t.respchan:
return resp, nil
case err := <-t.errchan:
return nil, err
case <-t.startCancel:
select {
// this simulates that the request is finished before cancel effects
case resp := <-t.respchan:
return resp, nil
// wait on finishCancel to simulate taking some amount of
// time while calling CancelRequest
case <-t.finishCancel:
return nil, errors.New("cancelled")
}
}
}

View File

@ -0,0 +1,42 @@
// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build go1.5
package client
import (
"errors"
"net/http"
)
func (t *fakeTransport) RoundTrip(req *http.Request) (*http.Response, error) {
select {
case resp := <-t.respchan:
return resp, nil
case err := <-t.errchan:
return nil, err
case <-t.startCancel:
case <-req.Cancel:
}
select {
// this simulates that the request is finished before cancel effects
case resp := <-t.respchan:
return resp, nil
// wait on finishCancel to simulate taking some amount of
// time while calling CancelRequest
case <-t.finishCancel:
return nil, errors.New("cancelled")
}
}