Commit fb3f152c authored by Dave Cheney's avatar Dave Cheney

net/url: make *url.Error implement net.Error

Fixes #12866

net/http.Client returns some errors wrapped in a *url.Error. To avoid
the requirement to unwrap these errors to determine if the cause was
temporary or a timeout, make *url.Error implement net.Error directly.

Change-Id: I1ba84ecc7ad5147a40f056ff1254e60290152408
Reviewed-on: https://go-review.googlesource.com/15672Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
parent 2d5601d8
......@@ -983,13 +983,12 @@ func TestClientTimeout_Headers(t *testing.T) {
if err == nil {
t.Fatal("got response from Get; expected error")
}
ue, ok := err.(*url.Error)
if !ok {
if _, ok := err.(*url.Error); !ok {
t.Fatalf("Got error of type %T; want *url.Error", err)
}
ne, ok := ue.Err.(net.Error)
ne, ok := err.(net.Error)
if !ok {
t.Fatalf("Got url.Error.Err of type %T; want some net.Error", err)
t.Fatalf("Got error of type %T; want some net.Error", err)
}
if !ne.Timeout() {
t.Error("net.Error.Timeout = false; want true")
......
......@@ -24,6 +24,24 @@ type Error struct {
func (e *Error) Error() string { return e.Op + " " + e.URL + ": " + e.Err.Error() }
type timeout interface {
Timeout() bool
}
func (e *Error) Timeout() bool {
t, ok := e.Err.(timeout)
return ok && t.Timeout()
}
type temporary interface {
Temporary() bool
}
func (e *Error) Temporary() bool {
t, ok := e.Err.(temporary)
return ok && t.Temporary()
}
func ishex(c byte) bool {
switch {
case '0' <= c && c <= '9':
......
......@@ -6,6 +6,8 @@ package url
import (
"fmt"
"io"
"net"
"reflect"
"strings"
"testing"
......@@ -1229,3 +1231,84 @@ func TestShouldEscape(t *testing.T) {
}
}
}
type timeoutError struct {
timeout bool
}
func (e *timeoutError) Error() string { return "timeout error" }
func (e *timeoutError) Timeout() bool { return e.timeout }
type temporaryError struct {
temporary bool
}
func (e *temporaryError) Error() string { return "temporary error" }
func (e *temporaryError) Temporary() bool { return e.temporary }
type timeoutTemporaryError struct {
timeoutError
temporaryError
}
func (e *timeoutTemporaryError) Error() string { return "timeout/temporary error" }
var netErrorTests = []struct {
err error
timeout bool
temporary bool
}{{
err: &Error{"Get", "http://google.com/", &timeoutError{timeout: true}},
timeout: true,
temporary: false,
}, {
err: &Error{"Get", "http://google.com/", &timeoutError{timeout: false}},
timeout: false,
temporary: false,
}, {
err: &Error{"Get", "http://google.com/", &temporaryError{temporary: true}},
timeout: false,
temporary: true,
}, {
err: &Error{"Get", "http://google.com/", &temporaryError{temporary: false}},
timeout: false,
temporary: false,
}, {
err: &Error{"Get", "http://google.com/", &timeoutTemporaryError{timeoutError{timeout: true}, temporaryError{temporary: true}}},
timeout: true,
temporary: true,
}, {
err: &Error{"Get", "http://google.com/", &timeoutTemporaryError{timeoutError{timeout: false}, temporaryError{temporary: true}}},
timeout: false,
temporary: true,
}, {
err: &Error{"Get", "http://google.com/", &timeoutTemporaryError{timeoutError{timeout: true}, temporaryError{temporary: false}}},
timeout: true,
temporary: false,
}, {
err: &Error{"Get", "http://google.com/", &timeoutTemporaryError{timeoutError{timeout: false}, temporaryError{temporary: false}}},
timeout: false,
temporary: false,
}, {
err: &Error{"Get", "http://google.com/", io.EOF},
timeout: false,
temporary: false,
}}
// Test that url.Error implements net.Error and that it forwards
func TestURLErrorImplementsNetError(t *testing.T) {
for i, tt := range netErrorTests {
err, ok := tt.err.(net.Error)
if !ok {
t.Errorf("%d: %T does not implement net.Error", i+1, tt.err)
continue
}
if err.Timeout() != tt.timeout {
t.Errorf("%d: err.Timeout(): want %v, have %v", i+1, tt.timeout, err.Timeout())
continue
}
if err.Temporary() != tt.temporary {
t.Errorf("%d: err.Temporary(): want %v, have %v", i+1, tt.temporary, err.Temporary())
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment