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
Closed

Comments

@blixt
Copy link
Contributor

blixt 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
Copy link
Contributor Author

blixt 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 as completed Oct 28, 2016
@blixt
Copy link
Contributor Author

blixt 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.
Projects
None yet
Development

No branches or pull requests

2 participants