Description
Using http's ServeContent, a GET on a directory opened by os.Open unexpectedly closes the socket. The Content-Length header contains a non-zero size but then not a single byte is written in the HTTP body.
This is because a directory opened with os.Open seeks to a positive size but fails when read. I report this as an issue for net/http, instead os, since I am not sure if this is allowed behaviour for a directory. For HTTP, reporting a non-zero Content-Length with an empty body during GET in my understanding isn't.
How to reproduce this issue
GET a directory served by http.ServeContent on a real filesystem:
$ curl -i http://localhost:8080/
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Length: 68
Content-Type: text/plain; charset=utf-8
Last-Modified: Thu, 19 Mar 2015 07:57:56 GMT
Date: Thu, 19 Mar 2015 07:57:56 GMT
curl: (18) transfer closed with 68 bytes remaining to read
Source: https://play.golang.org/p/Tm5SPq9uag
$ go version
go version devel +ecd630d Wed Mar 18 00:59:49 2015 +0000 darwin/amd64
Same for Go 1.4.1 and 1.4.2 on OS X and Linux.
Demo that a directory seeks to a positive size but fails when read
seekdir.go seeks a directory, rewinds and tries to read:
$ go run seekdir.go
seekSize: 374
2015/03/19 09:09:29 read /tmp: is a directory
exit status 1
Source: https://play.golang.org/p/aeJkT4OsPV
How to fix this
Unfortunately I couldn't come up with a good solution. In my understanding, http.ServeContent is fine.
I had hoped that inspecting the return values of CopyN in fs.go line 257 for zero or error would help. But at this point, one can't rewrite the Content-Length header.
If a directory should remain seekable but not readable, a workaround in ServeContent could be to try to read the first n bytes in a buffer before calling WriteHeader.