Merge pull request #830 from aaronlehmann/no-closenotifier-panic

Don't panic when a http.ResponseWriter does not implement CloseNotifier
This commit is contained in:
Stephen Day 2015-08-06 16:32:10 -07:00
commit ec77b836dd
3 changed files with 22 additions and 17 deletions

View file

@ -103,17 +103,21 @@ func GetRequestID(ctx Context) string {
// WithResponseWriter returns a new context and response writer that makes // WithResponseWriter returns a new context and response writer that makes
// interesting response statistics available within the context. // interesting response statistics available within the context.
func WithResponseWriter(ctx Context, w http.ResponseWriter) (Context, http.ResponseWriter) { func WithResponseWriter(ctx Context, w http.ResponseWriter) (Context, http.ResponseWriter) {
closeNotifier, ok := w.(http.CloseNotifier) irw := instrumentedResponseWriter{
if !ok {
panic("the ResponseWriter does not implement CloseNotifier")
}
irw := &instrumentedResponseWriter{
ResponseWriter: w, ResponseWriter: w,
CloseNotifier: closeNotifier,
Context: ctx, Context: ctx,
} }
return irw, irw if closeNotifier, ok := w.(http.CloseNotifier); ok {
irwCN := &instrumentedResponseWriterCN{
instrumentedResponseWriter: irw,
CloseNotifier: closeNotifier,
}
return irwCN, irwCN
}
return &irw, &irw
} }
// GetResponseWriter returns the http.ResponseWriter from the provided // GetResponseWriter returns the http.ResponseWriter from the provided
@ -263,11 +267,19 @@ func (ctx *muxVarsContext) Value(key interface{}) interface{} {
return ctx.Context.Value(key) return ctx.Context.Value(key)
} }
// instrumentedResponseWriterCN provides response writer information in a
// context. It implements http.CloseNotifier so that users can detect
// early disconnects.
type instrumentedResponseWriterCN struct {
instrumentedResponseWriter
http.CloseNotifier
}
// instrumentedResponseWriter provides response writer information in a // instrumentedResponseWriter provides response writer information in a
// context. // context. This variant is only used in the case where CloseNotifier is not
// implemented by the parent ResponseWriter.
type instrumentedResponseWriter struct { type instrumentedResponseWriter struct {
http.ResponseWriter http.ResponseWriter
http.CloseNotifier
Context Context
mu sync.Mutex mu sync.Mutex

View file

@ -110,13 +110,6 @@ func (trw *testResponseWriter) Header() http.Header {
return trw.header return trw.header
} }
// CloseNotify is only here to make the testResponseWriter implement the
// http.CloseNotifier interface, which WithResponseWriter expects to be
// implemented.
func (trw *testResponseWriter) CloseNotify() <-chan bool {
return make(chan bool)
}
func (trw *testResponseWriter) Write(p []byte) (n int, err error) { func (trw *testResponseWriter) Write(p []byte) (n int, err error) {
if trw.status == 0 { if trw.status == 0 {
trw.status = http.StatusOK trw.status = http.StatusOK

View file

@ -29,7 +29,7 @@ func copyFullPayload(responseWriter http.ResponseWriter, r *http.Request, destWr
if notifier, ok := responseWriter.(http.CloseNotifier); ok { if notifier, ok := responseWriter.(http.CloseNotifier); ok {
clientClosed = notifier.CloseNotify() clientClosed = notifier.CloseNotify()
} else { } else {
panic("the ResponseWriter does not implement CloseNotifier") ctxu.GetLogger(context).Warn("the ResponseWriter does not implement CloseNotifier")
} }
// Read in the data, if any. // Read in the data, if any.