Gert Cuykens Gert Cuykens - 2 months ago 7
HTTP Question

Why does http.Get result in two requests instead of one?

Create a test file

./bower_components/index.html
and run
go test
in
./
.

Why does the following print two lines instead of just the first one?

./bower_components/index.html
./bower_components/


Output:

=== RUN TestRootHandler
./bower_components/index.html
./bower_components/ ???
--- PASS: TestRootHandler (0.00s)
main_test.go:32: 200 - ./bower_components/Hello World.html
PASS
ok


Code:

// RootHandler for HTTP
func RootHandler(root string, h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := os.Open(root + r.URL.Path)
if err != nil {
fmt.Println(err.Error())
h.ServeHTTP(w, r)
return
}
fmt.Println(root + r.URL.Path)
r.URL.Path = root + r.URL.Path
h.ServeHTTP(w, r)
})
}

// TestRootHandler
func TestRootHandler(t *testing.T) {
ts := httptest.NewServer(RootHandler("./bower_components", http.FileServer(http.Dir("./"))))
defer ts.Close()
res, err := http.Get(ts.URL + "/index.html")
if err != nil {
t.Fatal(err)
}
body, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
t.Fatal(err)
}
t.Logf("%d - %s", res.StatusCode, body)
}


Let me know if you don't understand the question then I will setup a github repository so you can just run the go test command to see what I mean.

Answer

That's just the way how http.FileServer() is written. Quoting from its doc:

As a special case, the returned file server redirects any request ending in "/index.html" to the same path, without the final "index.html".

This is what you experience: you were requesting /bower_components/index.html, so the handler returned by http.FileServer() sends a redirect:

HTTP/1.1 301 Moved Permanently
Location: ./

And http.Get() being well-behaved, follows this redirect, and performs another HTTP GET, now without the index.html, and the http.FileServer() handler will try and serve the index.html in such case.

Comments