]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: make responseAndError satisfy the net.Error interface
authorRick Arnold <rickarnoldjr@gmail.com>
Wed, 12 Feb 2014 15:59:58 +0000 (07:59 -0800)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 12 Feb 2014 15:59:58 +0000 (07:59 -0800)
Allow clients to check for timeouts without relying on error substring
matching.

Fixes #6185.

LGTM=bradfitz
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/55470048

src/pkg/net/http/transport.go
src/pkg/net/http/transport_test.go

index df171782357968a52bdd2615b909eafa881a268b..2c312a77a02e1418f6f0d335cf62ee6a56b063b0 100644 (file)
@@ -869,6 +869,18 @@ type writeRequest struct {
        ch  chan<- error
 }
 
+type httpError struct {
+       err     string
+       timeout bool
+}
+
+func (e *httpError) Error() string   { return e.err }
+func (e *httpError) Timeout() bool   { return e.timeout }
+func (e *httpError) Temporary() bool { return true }
+
+var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true}
+var errClosed error = &httpError{err: "net/http: transport closed before response was received"}
+
 func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) {
        pc.t.setReqConn(req.Request, pc)
        pc.lk.Lock()
@@ -939,11 +951,11 @@ WaitResponse:
                        pconnDeadCh = nil                               // avoid spinning
                        failTicker = time.After(100 * time.Millisecond) // arbitrary time to wait for resc
                case <-failTicker:
-                       re = responseAndError{err: errors.New("net/http: transport closed before response was received")}
+                       re = responseAndError{err: errClosed}
                        break WaitResponse
                case <-respHeaderTimer:
                        pc.close()
-                       re = responseAndError{err: errors.New("net/http: timeout awaiting response headers")}
+                       re = responseAndError{err: errTimeout}
                        break WaitResponse
                case re = <-resc:
                        break WaitResponse
index da74ac9a0f8483c4c23c34b2882c2ee4d9ddc4d6..2678d71b1dec19b0e9257ecadd69c61d3648c3ff 100644 (file)
@@ -1237,6 +1237,20 @@ func TestTransportResponseHeaderTimeout(t *testing.T) {
        for i, tt := range tests {
                res, err := c.Get(ts.URL + tt.path)
                if err != nil {
+                       uerr, ok := err.(*url.Error)
+                       if !ok {
+                               t.Errorf("error is not an url.Error; got: %#v", err)
+                               continue
+                       }
+                       nerr, ok := uerr.Err.(net.Error)
+                       if !ok {
+                               t.Errorf("error does not satisfy net.Error interface; got: %#v", err)
+                               continue
+                       }
+                       if !nerr.Timeout() {
+                               t.Errorf("want timeout error; got: %q", nerr)
+                               continue
+                       }
                        if strings.Contains(err.Error(), tt.wantErr) {
                                continue
                        }