Create middleware to be able to handle HTTP pipelining correctly
This commit is contained in:
parent
1c3e4124f8
commit
aa705dd691
8 changed files with 179 additions and 73 deletions
2
vendor/github.com/vulcand/oxy/cbreaker/cbreaker.go
generated
vendored
2
vendor/github.com/vulcand/oxy/cbreaker/cbreaker.go
generated
vendored
|
@ -156,7 +156,7 @@ func (c *CircuitBreaker) activateFallback(w http.ResponseWriter, req *http.Reque
|
|||
|
||||
func (c *CircuitBreaker) serve(w http.ResponseWriter, req *http.Request) {
|
||||
start := c.clock.UtcNow()
|
||||
p := utils.NewSimpleProxyWriter(w)
|
||||
p := utils.NewProxyWriter(w)
|
||||
|
||||
c.next.ServeHTTP(p, req)
|
||||
|
||||
|
|
36
vendor/github.com/vulcand/oxy/forward/fwd.go
generated
vendored
36
vendor/github.com/vulcand/oxy/forward/fwd.go
generated
vendored
|
@ -466,16 +466,6 @@ func (f *httpForwarder) serveHTTP(w http.ResponseWriter, inReq *http.Request, ct
|
|||
defer logEntry.Debug("vulcand/oxy/forward/http: completed ServeHttp on request")
|
||||
}
|
||||
|
||||
var pw utils.ProxyWriter
|
||||
|
||||
// Disable closeNotify when method GET for http pipelining
|
||||
// Waiting for https://github.com/golang/go/issues/23921
|
||||
if inReq.Method == http.MethodGet {
|
||||
pw = utils.NewProxyWriterWithoutCloseNotify(w)
|
||||
} else {
|
||||
pw = utils.NewSimpleProxyWriter(w)
|
||||
}
|
||||
|
||||
start := time.Now().UTC()
|
||||
|
||||
outReq := new(http.Request)
|
||||
|
@ -490,18 +480,24 @@ func (f *httpForwarder) serveHTTP(w http.ResponseWriter, inReq *http.Request, ct
|
|||
ModifyResponse: f.modifyResponse,
|
||||
BufferPool: f.bufferPool,
|
||||
}
|
||||
revproxy.ServeHTTP(pw, outReq)
|
||||
|
||||
if inReq.TLS != nil {
|
||||
f.log.Debugf("vulcand/oxy/forward/http: Round trip: %v, code: %v, Length: %v, duration: %v tls:version: %x, tls:resume:%t, tls:csuite:%x, tls:server:%v",
|
||||
inReq.URL, pw.StatusCode(), pw.GetLength(), time.Now().UTC().Sub(start),
|
||||
inReq.TLS.Version,
|
||||
inReq.TLS.DidResume,
|
||||
inReq.TLS.CipherSuite,
|
||||
inReq.TLS.ServerName)
|
||||
if f.log.GetLevel() >= log.DebugLevel {
|
||||
pw := utils.NewProxyWriter(w)
|
||||
revproxy.ServeHTTP(pw, outReq)
|
||||
|
||||
if inReq.TLS != nil {
|
||||
f.log.Debugf("vulcand/oxy/forward/http: Round trip: %v, code: %v, Length: %v, duration: %v tls:version: %x, tls:resume:%t, tls:csuite:%x, tls:server:%v",
|
||||
inReq.URL, pw.StatusCode(), pw.GetLength(), time.Now().UTC().Sub(start),
|
||||
inReq.TLS.Version,
|
||||
inReq.TLS.DidResume,
|
||||
inReq.TLS.CipherSuite,
|
||||
inReq.TLS.ServerName)
|
||||
} else {
|
||||
f.log.Debugf("vulcand/oxy/forward/http: Round trip: %v, code: %v, Length: %v, duration: %v",
|
||||
inReq.URL, pw.StatusCode(), pw.GetLength(), time.Now().UTC().Sub(start))
|
||||
}
|
||||
} else {
|
||||
f.log.Debugf("vulcand/oxy/forward/http: Round trip: %v, code: %v, Length: %v, duration: %v",
|
||||
inReq.URL, pw.StatusCode(), pw.GetLength(), time.Now().UTC().Sub(start))
|
||||
revproxy.ServeHTTP(w, outReq)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
2
vendor/github.com/vulcand/oxy/roundrobin/rebalancer.go
generated
vendored
2
vendor/github.com/vulcand/oxy/roundrobin/rebalancer.go
generated
vendored
|
@ -148,7 +148,7 @@ func (rb *Rebalancer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
defer logEntry.Debug("vulcand/oxy/roundrobin/rebalancer: completed ServeHttp on request")
|
||||
}
|
||||
|
||||
pw := utils.NewSimpleProxyWriter(w)
|
||||
pw := utils.NewProxyWriter(w)
|
||||
start := rb.clock.UtcNow()
|
||||
|
||||
// make shallow copy of request before changing anything to avoid side effects
|
||||
|
|
76
vendor/github.com/vulcand/oxy/utils/netutils.go
generated
vendored
76
vendor/github.com/vulcand/oxy/utils/netutils.go
generated
vendored
|
@ -12,89 +12,65 @@ import (
|
|||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type ProxyWriter interface {
|
||||
http.ResponseWriter
|
||||
GetLength() int64
|
||||
StatusCode() int
|
||||
GetWriter() http.ResponseWriter
|
||||
}
|
||||
|
||||
// ProxyWriterWithoutCloseNotify helps to capture response headers and status code
|
||||
// from the ServeHTTP. It can be safely passed to ServeHTTP handler,
|
||||
// wrapping the real response writer.
|
||||
type ProxyWriterWithoutCloseNotify struct {
|
||||
type ProxyWriter struct {
|
||||
W http.ResponseWriter
|
||||
Code int
|
||||
Length int64
|
||||
code int
|
||||
length int64
|
||||
}
|
||||
|
||||
func NewProxyWriterWithoutCloseNotify(writer http.ResponseWriter) *ProxyWriterWithoutCloseNotify {
|
||||
return &ProxyWriterWithoutCloseNotify{
|
||||
func NewProxyWriter(writer http.ResponseWriter) *ProxyWriter {
|
||||
return &ProxyWriter{
|
||||
W: writer,
|
||||
}
|
||||
}
|
||||
|
||||
func NewSimpleProxyWriter(writer http.ResponseWriter) *SimpleProxyWriter {
|
||||
return &SimpleProxyWriter{
|
||||
ProxyWriterWithoutCloseNotify: NewProxyWriterWithoutCloseNotify(writer),
|
||||
}
|
||||
}
|
||||
|
||||
type SimpleProxyWriter struct {
|
||||
*ProxyWriterWithoutCloseNotify
|
||||
}
|
||||
|
||||
func (p *ProxyWriterWithoutCloseNotify) GetWriter() http.ResponseWriter {
|
||||
return p.W
|
||||
}
|
||||
|
||||
func (p *ProxyWriterWithoutCloseNotify) StatusCode() int {
|
||||
if p.Code == 0 {
|
||||
func (p *ProxyWriter) StatusCode() int {
|
||||
if p.code == 0 {
|
||||
// per contract standard lib will set this to http.StatusOK if not set
|
||||
// by user, here we avoid the confusion by mirroring this logic
|
||||
return http.StatusOK
|
||||
}
|
||||
return p.Code
|
||||
return p.code
|
||||
}
|
||||
|
||||
func (p *ProxyWriterWithoutCloseNotify) Header() http.Header {
|
||||
func (p *ProxyWriter) GetLength() int64 {
|
||||
return p.length
|
||||
}
|
||||
|
||||
func (p *ProxyWriter) Header() http.Header {
|
||||
return p.W.Header()
|
||||
}
|
||||
|
||||
func (p *ProxyWriterWithoutCloseNotify) Write(buf []byte) (int, error) {
|
||||
p.Length = p.Length + int64(len(buf))
|
||||
func (p *ProxyWriter) Write(buf []byte) (int, error) {
|
||||
p.length = p.length + int64(len(buf))
|
||||
return p.W.Write(buf)
|
||||
}
|
||||
|
||||
func (p *ProxyWriterWithoutCloseNotify) WriteHeader(code int) {
|
||||
p.Code = code
|
||||
func (p *ProxyWriter) WriteHeader(code int) {
|
||||
p.code = code
|
||||
p.W.WriteHeader(code)
|
||||
}
|
||||
|
||||
func (p *ProxyWriterWithoutCloseNotify) Flush() {
|
||||
func (p *ProxyWriter) Flush() {
|
||||
if f, ok := p.W.(http.Flusher); ok {
|
||||
f.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ProxyWriterWithoutCloseNotify) GetLength() int64 {
|
||||
return p.Length
|
||||
}
|
||||
|
||||
func (p *SimpleProxyWriter) CloseNotify() <-chan bool {
|
||||
if cn, ok := p.GetWriter().(http.CloseNotifier); ok {
|
||||
func (p *ProxyWriter) CloseNotify() <-chan bool {
|
||||
if cn, ok := p.W.(http.CloseNotifier); ok {
|
||||
return cn.CloseNotify()
|
||||
}
|
||||
log.Warningf("Upstream ResponseWriter of type %v does not implement http.CloseNotifier. Returning dummy channel.", reflect.TypeOf(p.GetWriter()))
|
||||
log.Debugf("Upstream ResponseWriter of type %v does not implement http.CloseNotifier. Returning dummy channel.", reflect.TypeOf(p.W))
|
||||
return make(<-chan bool)
|
||||
}
|
||||
|
||||
func (p *ProxyWriterWithoutCloseNotify) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
func (p *ProxyWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
if hi, ok := p.W.(http.Hijacker); ok {
|
||||
return hi.Hijack()
|
||||
}
|
||||
log.Warningf("Upstream ResponseWriter of type %v does not implement http.Hijacker. Returning dummy channel.", reflect.TypeOf(p.W))
|
||||
return nil, nil, fmt.Errorf("The response writer that was wrapped in this proxy, does not implement http.Hijacker. It is of type: %v", reflect.TypeOf(p.W))
|
||||
log.Debugf("Upstream ResponseWriter of type %v does not implement http.Hijacker. Returning dummy channel.", reflect.TypeOf(p.W))
|
||||
return nil, nil, fmt.Errorf("the response writer that was wrapped in this proxy, does not implement http.Hijacker. It is of type: %v", reflect.TypeOf(p.W))
|
||||
}
|
||||
|
||||
func NewBufferWriter(w io.WriteCloser) *BufferWriter {
|
||||
|
@ -139,8 +115,8 @@ func (b *BufferWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
|||
if hi, ok := b.W.(http.Hijacker); ok {
|
||||
return hi.Hijack()
|
||||
}
|
||||
log.Warningf("Upstream ResponseWriter of type %v does not implement http.Hijacker. Returning dummy channel.", reflect.TypeOf(b.W))
|
||||
return nil, nil, fmt.Errorf("The response writer that was wrapped in this proxy, does not implement http.Hijacker. It is of type: %v", reflect.TypeOf(b.W))
|
||||
log.Debugf("Upstream ResponseWriter of type %v does not implement http.Hijacker. Returning dummy channel.", reflect.TypeOf(b.W))
|
||||
return nil, nil, fmt.Errorf("the response writer that was wrapped in this proxy, does not implement http.Hijacker. It is of type: %v", reflect.TypeOf(b.W))
|
||||
}
|
||||
|
||||
type nopWriteCloser struct {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue