Skip to content
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

net/http: ResponseWriter implementations don't always follow documentation #17653

Closed
blixt opened this issue Oct 28, 2016 · 2 comments

Comments

Projects
None yet
2 participants
@blixt
Copy link
Contributor

commented Oct 28, 2016

These are excerpts from the documentation for the ResponseWriter interface. For Write:

// If WriteHeader has not yet been called, Write calls
// WriteHeader(http.StatusOK) before writing the data.

For WriteHeader:

// If WriteHeader is not called explicitly, the first call to Write
// will trigger an implicit WriteHeader(http.StatusOK).

The code below never calls ResponseWriter.WriteHeader for simple requests. I had expected that the implementation of the ResponseWriter interface would follow it by calling out to the interface WriteHeader method instead of directly calling its internal writeHeader function.

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Hello World!")
    })
    http.ListenAndServe(":8080", Middleware(http.DefaultServeMux))
}

func Middleware(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Use a different ResponseWriter for this request...
        w2 := myResponseWriter{w}
        h.ServeHTTP(w2, r)
    })
}

type myResponseWriter struct {
    http.ResponseWriter
}

func (w myResponseWriter) WriteHeader(code int) {
    // This code is never called with the http.response implementation.
    w.ResponseWriter.WriteHeader(code)
    fmt.Println("Yay, I wrote a header!")
}

I also put this code on the Go Playground.

Go version that I'm using:

go version go1.7.3 darwin/amd64
@blixt

This comment has been minimized.

Copy link
Contributor Author

commented Oct 28, 2016

Nevermind, I was thinking a bit oddly about this, that something else is causing WriteHeader to be called but if the concrete implementation does everything it can't know that it's been wrapped.

@blixt blixt closed this Oct 28, 2016

@blixt

This comment has been minimized.

Copy link
Contributor Author

commented Oct 28, 2016

If someone else finds this issue because they were trying to do what I'm doing, I believe this is a valid base to start off a ResponseWriter wrapper from:

type MyResponseWriter struct {
    http.ResponseWriter
    wroteHeader bool
}

func (w *MyResponseWriter) Write(p []byte) (n int, err error) {
    if !w.wroteHeader {
        w.WriteHeader(http.StatusOK)
    }
    return w.ResponseWriter.Write(p)
}

func (w *MyResponseWriter) WriteHeader(code int) {
    w.ResponseWriter.WriteHeader(code)
    // Check after in case there's error handling in the wrapped ResponseWriter.
    if !w.wroteHeader {
        return
    }
    w.wroteHeader = true
    // Do other stuff here.
}

@golang golang locked and limited conversation to collaborators Oct 28, 2017

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.