-
Notifications
You must be signed in to change notification settings - Fork 18k
net/http: http.ServeFile and http.ServeContent Explicitly Set http.StatusOK #11269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Only the first WriteHeader wins. How did you get a 200? Can you post a minimal example demonstrating the issue? |
In this case the WriteHeader is being called explicitly in The use-case (for context) is serving static files to respond to HTTP 50x's or HTTP 404's when using Go as a web server without a reverse proxy like nginx in front. package main
import (
"log"
"net/http"
"os"
"path/filepath"
)
func main() {
// e.g. /Users/you/example.com/
static := os.Getenv("STATIC_DIR")
// Set this to 200, 500, 404, etc - same result - multiple WriteHeader
// calls.
http.Handle("/", serveErrorPage(500, static))
http.ListenAndServe(":8000", nil)
}
func serveErrorPage(code int, dir string) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
// Call duplicated by src/net/http/fs.go#L254
w.WriteHeader(code)
path := filepath.Join(dir, r.URL.Path)
log.Println(path)
http.ServeFile(w, r, path)
}
return http.HandlerFunc(fn)
} A fairly contrived/minimal example but should demonstrate the issue. Set |
I tried your code. The server is returning a 500 header. Maybe you're confused that the HTML body doesn't say 500?
The problem with trying to use ServeContent after doing WriteHeader(500) is that the header will already be flushed at that point, and ServeContent will be unable to set the Content-Type, etc. So you'll need to do that part anyway. But if you do that, calling ServeContent after your own WriteHeader(500) seems to work fine. Feel free to re-open this bug if I'm missing something. |
Thanks for the reply @bradfitz. Indicating I was getting a HTTP 200 was a mistake—that wasn't the case (must have been conflating it with some other testing I was doing at the time). I still see the following from the server's log when calling 2015/06/25 07:28:21 static/page.html
2015/06/25 07:28:21 http: multiple response.WriteHeader calls ... and the corresponding
This is with the program unmodified from above. |
I see. I don't think this is worth changing. Once you've already sent the headers, ServeContent can no longer do If-Modified-Since or Range requests, etc. At that point there's little functionality it's providing that you can't more easily do yourself for your custom 500 handler. I think changing this behavior would just be encouraging people in the wrong direction. I'm content saying that it should only be used prior to writing headers. |
What version of Go are you using (go version)?
go version go1.4.2 darwin/amd64
What operating system and processor architecture are you using?
OS X 10.10.3 x86-64
What did you do?
Set
w.WriteHeader(http.StatusInternalServerError)
prior to callinghttp.ServeFile
What did you expect to see?
A
HTTP 500
status.What did you see instead?
A
HTTP 200
status (and the usual multiple header writes error for messing it up).Currently
http.ServeFile
(which callshttp.ServeContent
and then eventuallyhttp.serveContent
) implicitly sets the status code to HTTP 200 as per this line in src/http/fs.goFrom what I can see, removing this line would result in
net/http
implicitly callingw.WriteHeader(StatusOK)
as per usual (http://golang.org/src/net/http/server.go#L990) - which is the behaviour I'd expected until running into this.Proposed Fix
http.serveContent
to only callw.WriteHeader(code)
on an error condition. Setvar code int
(i.e. zero value) instead of defaulting tocode := StatusOK
.code
still has the zero value before we write to the ResponseWriter, then don't callWriteHeader
.http.StatusOK
if no header has been set by the time we're ready to write back.Writing
StatusOK
in serveContent appears to be redundant.The text was updated successfully, but these errors were encountered: