Skip to content

Instantly share code, notes, and snippets.

@hlubek
Created January 17, 2023 12:45
Show Gist options
  • Save hlubek/1a986e6d6cdf3d24af077a6739f969a9 to your computer and use it in GitHub Desktop.
Save hlubek/1a986e6d6cdf3d24af077a6739f969a9 to your computer and use it in GitHub Desktop.
Example for using http.NewResponseController in Go 1.20
package main
import (
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// Do not use a type assertion like `if hijacker, ok := w.(http.Hijacker); ok`,
// because that would only work if the wrapped response writer "forwards" that interface.
// The new response controller takes care of checking and unwrapping the response writer.
rc := http.NewResponseController(w)
conn, stream, err := rc.Hijack()
if err != nil {
log.Printf("Error hijacking connection: %s", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
defer conn.Close()
stream.Write([]byte("--- hello from stream ---"))
stream.Flush()
})
mux.HandleFunc("/not-found", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("not found"))
})
// Use a very simple logging middleware for demonstration purposes.
h := logHttp(mux)
err := http.ListenAndServe(":8080", h)
if err != nil {
panic(err)
}
}
func logHttp(mux http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Create a wrapped response writer for storing the status code.
wr := &wrappedResponse{w, 0}
mux.ServeHTTP(wr, r)
log.Printf("%s %s - %d", r.Method, r.URL.Path, wr.effectiveStatusCode())
})
}
type wrappedResponse struct {
http.ResponseWriter
statusCode int
}
// WriteHeader overrides the default WriteHeader method to save the status code.
func (w *wrappedResponse) WriteHeader(code int) {
w.statusCode = code
w.ResponseWriter.WriteHeader(code)
}
func (w *wrappedResponse) effectiveStatusCode() int {
if w.statusCode == 0 {
return 200
}
return w.statusCode
}
// Unwrap returns the original response writer, so the response controller can call Hijack.
func (w *wrappedResponse) Unwrap() http.ResponseWriter {
return w.ResponseWriter
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment