Closed
Description
(From aaronlevy on IRC)
It's hard for a client to know when a HTTP request failed due to timeout, and when for other reasons.
Given a slow server
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
time.Sleep(3*time.Second)
fmt.Fprintf(w, "req rcvd")
})
http.ListenAndServe(":8080", nil)
}
and a client
package main
import (
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"time"
)
func main() {
client := &http.Client{
Timeout: time.Duration(time.Second),
}
req, err := client.Get("http://localhost:8080")
if err != nil {
fmt.Printf("type: %T\n", err)
fmt.Printf("error: %v\n", err)
if err2, ok := err.(*url.Error); ok {
fmt.Printf("inner type: %T\n", err2.Err)
fmt.Printf("inner error: %v\n", err2.Err)
if err3, ok := err2.Err.(net.Error); ok {
fmt.Printf("is timeout: %v\n", err3.Timeout())
}
if err4, ok := err2.Err.(*net.OpError); ok {
fmt.Printf("OpError inner type: %T\n", err4.Err)
fmt.Printf("OpError inner error: %v\n", err4.Err)
}
}
return
}
resp, err := ioutil.ReadAll(req.Body)
req.Body.Close()
if err != nil {
fmt.Println(err)
}
fmt.Printf("%s", resp)
}
Results in
$ go run server.go &
$ go run client.go
type: *url.Error
error: Get http://localhost:8080: read tcp 127.0.0.1:8080: use of closed network connection
inner type: *net.OpError
inner error: read tcp 127.0.0.1:8080: use of closed network connection
is timeout: false
OpError inner type: *errors.errorString
OpError inner error: use of closed network connection
That's quite the gift wrapping on that error. But the real bug is "is timeout: false". The error was caused by a timeout, it should claim to be one.