forked from mirror/client_golang
Solve "The Proxy Problem" of InstrumentHandler
InstrumentHandler provides proxy object over given http.ResponseWriter - responseWriterDelegator that only implements the bare minimum required of an http.ResponseWriter and doesn’t implement any interface upgrades (http.Flusher, http.Hijacker, etc.). This commit fixes it by providing fancyResponseWriterDelegator with all the fancy bells and whistles if standard library http.ResponseWriter is detected. Heavily inspired by Goji's middleware. https://avtok.com/2014/11/05/interface-upgrades.html#the-proxy-problem
This commit is contained in:
parent
288762e79c
commit
dd4dd69878
|
@ -14,6 +14,9 @@
|
||||||
package prometheus
|
package prometheus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -141,7 +144,18 @@ func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.Respo
|
||||||
urlLen = len(r.URL.String())
|
urlLen = len(r.URL.String())
|
||||||
}
|
}
|
||||||
go computeApproximateRequestSize(r, out, urlLen)
|
go computeApproximateRequestSize(r, out, urlLen)
|
||||||
handlerFunc(delegate, r)
|
|
||||||
|
_, cn := w.(http.CloseNotifier)
|
||||||
|
_, fl := w.(http.Flusher)
|
||||||
|
_, hj := w.(http.Hijacker)
|
||||||
|
_, rf := w.(io.ReaderFrom)
|
||||||
|
var rw http.ResponseWriter
|
||||||
|
if cn && fl && hj && rf {
|
||||||
|
rw = &fancyResponseWriterDelegator{delegate}
|
||||||
|
} else {
|
||||||
|
rw = delegate
|
||||||
|
}
|
||||||
|
handlerFunc(rw, r)
|
||||||
|
|
||||||
elapsed := float64(time.Since(now)) / float64(time.Microsecond)
|
elapsed := float64(time.Since(now)) / float64(time.Microsecond)
|
||||||
|
|
||||||
|
@ -197,6 +211,31 @@ func (r *responseWriterDelegator) Write(b []byte) (int, error) {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fancyResponseWriterDelegator struct {
|
||||||
|
*responseWriterDelegator
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fancyResponseWriterDelegator) CloseNotify() <-chan bool {
|
||||||
|
return f.ResponseWriter.(http.CloseNotifier).CloseNotify()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fancyResponseWriterDelegator) Flush() {
|
||||||
|
f.ResponseWriter.(http.Flusher).Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fancyResponseWriterDelegator) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
|
return f.ResponseWriter.(http.Hijacker).Hijack()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fancyResponseWriterDelegator) ReadFrom(r io.Reader) (int64, error) {
|
||||||
|
if !f.wroteHeader {
|
||||||
|
f.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
n, err := f.ResponseWriter.(io.ReaderFrom).ReadFrom(r)
|
||||||
|
f.written += n
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
func sanitizeMethod(m string) string {
|
func sanitizeMethod(m string) string {
|
||||||
switch m {
|
switch m {
|
||||||
case "GET", "get":
|
case "GET", "get":
|
||||||
|
|
Loading…
Reference in New Issue