I was trying to use the httptest
package in golang. I found out something I don't understand. Here is the code:
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
)
func main() {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello1"))
}))
ts.Close()
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello2"))
}))
ts.Close()
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(100)
w.Write([]byte("Hello3"))
}))
res, err := http.Get(ts.URL)
if err != nil {
log.Fatal(err)
}
greeting, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
log.Fatal(err)
}
ts.Close()
fmt.Printf("%s", greeting)
}
In this code example, I was trying to open and close httptest
servers several times. Somehow it caused deadlock in The Go Playground. I tried on my own environment (Go version: go1.7.4 darwin/amd64) and it caused hanging without responding at all.
My question is: Why w.WriteHeader(100)
caused deadlock but w.WriteHeader(200)
doesn't? Is it the bug from the core library of Golang or just I misunderstood some usage? Tks!
If you slightly modify code:
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/http/httptest"
)
func main() {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello1"))
}))
ts.Close()
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello2"))
}))
ts.Close()
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(100)
w.Write([]byte("Hello3"))
}))
fmt.Println("before get") ///// . <----
res, err := http.Get(ts.URL)
fmt.Println("after get") ///// . <----
if err != nil {
log.Fatal(err)
}
greeting, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
log.Fatal(err)
}
ts.Close()
fmt.Printf("%s", greeting)
}
and run it - you'll see only first line.
That means Go http client want more data from you. So it hangs on line
res, err := http.Get(ts.URL)
and cannot get to the ts.Close()
below.
Next - lets modify a test, so it will close a connection and this way release a clients waiting lock:
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(100)
w.Write([]byte("Hello3"))
hj, _ := w.(http.Hijacker)
conn, _, _ := hj.Hijack()
conn.Close()
}))
I close connection explicitly but this way you get both check strings and test finishes ok. Try it.
Of course it's a HTTP protocol violation so I get an error:
Get http://127.0.0.1:54243: net/http: HTTP/1.x transport connection broken: unexpected EOF