Commit db4cd8ee authored by Nimi Wariboko Jr's avatar Nimi Wariboko Jr

Proxy: Add keepalive directive to proxy to set MaxIdleConnsPerHost on transport. Fixes #938

parent da5b3cfc
......@@ -108,7 +108,7 @@ func (p Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
if nameURL, err := url.Parse(host.Name); err == nil {
outreq.Host = nameURL.Host
if proxy == nil {
proxy = NewSingleHostReverseProxy(nameURL, host.WithoutPathPrefix)
proxy = NewSingleHostReverseProxy(nameURL, host.WithoutPathPrefix, 0)
}
// use upstream credentials by default
......
......@@ -716,11 +716,11 @@ func newFakeUpstream(name string, insecure bool) *fakeUpstream {
from: "/",
host: &UpstreamHost{
Name: name,
ReverseProxy: NewSingleHostReverseProxy(uri, ""),
ReverseProxy: NewSingleHostReverseProxy(uri, "", 0),
},
}
if insecure {
u.host.ReverseProxy.Transport = InsecureTransport
u.host.ReverseProxy.UseInsecureTransport()
}
return u
}
......@@ -744,7 +744,7 @@ func (u *fakeUpstream) Select() *UpstreamHost {
}
u.host = &UpstreamHost{
Name: u.name,
ReverseProxy: NewSingleHostReverseProxy(uri, u.without),
ReverseProxy: NewSingleHostReverseProxy(uri, u.without, 0),
}
}
return u.host
......@@ -785,7 +785,7 @@ func (u *fakeWsUpstream) Select() *UpstreamHost {
uri, _ := url.Parse(u.name)
return &UpstreamHost{
Name: u.name,
ReverseProxy: NewSingleHostReverseProxy(uri, u.without),
ReverseProxy: NewSingleHostReverseProxy(uri, u.without, 0),
UpstreamHeaders: http.Header{
"Connection": {"{>Connection}"},
"Upgrade": {"{>Upgrade}"}},
......
......@@ -83,7 +83,7 @@ func socketDial(hostName string) func(network, addr string) (conn net.Conn, err
// the target request will be for /base/dir.
// Without logic: target's path is "/", incoming is "/api/messages",
// without is "/api", then the target request will be for /messages.
func NewSingleHostReverseProxy(target *url.URL, without string) *ReverseProxy {
func NewSingleHostReverseProxy(target *url.URL, without string, keepalive int) *ReverseProxy {
targetQuery := target.RawQuery
director := func(req *http.Request) {
if target.Scheme == "unix" {
......@@ -122,10 +122,44 @@ func NewSingleHostReverseProxy(target *url.URL, without string) *ReverseProxy {
rp.Transport = &http.Transport{
Dial: socketDial(target.String()),
}
} else if keepalive != 0 {
rp.Transport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
if keepalive < 0 {
rp.Transport.(*http.Transport).DisableKeepAlives = true
} else {
rp.Transport.(*http.Transport).MaxIdleConnsPerHost = keepalive
}
}
return rp
}
// InsecureTransport is used to facilitate HTTPS proxying
// when it is OK for upstream to be using a bad certificate,
// since this transport skips verification.
func (rp *ReverseProxy) UseInsecureTransport() {
if rp.Transport == nil {
rp.Transport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
TLSHandshakeTimeout: 10 * time.Second,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
} else if transport, ok := rp.Transport.(*http.Transport); ok {
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
}
}
func copyHeader(dst, src http.Header) {
for k, vv := range src {
for _, v := range vv {
......@@ -147,19 +181,6 @@ var hopHeaders = []string{
"Upgrade",
}
// InsecureTransport is used to facilitate HTTPS proxying
// when it is OK for upstream to be using a bad certificate,
// since this transport skips verification.
var InsecureTransport http.RoundTripper = &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
TLSHandshakeTimeout: 10 * time.Second,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
type respUpdateFn func(resp *http.Response)
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, outreq *http.Request, respUpdateFn respUpdateFn) error {
......
......@@ -25,6 +25,7 @@ type staticUpstream struct {
downstreamHeaders http.Header
Hosts HostPool
Policy Policy
KeepAlive int
insecureSkipVerify bool
FailTimeout time.Duration
......@@ -154,9 +155,9 @@ func (u *staticUpstream) NewHost(host string) (*UpstreamHost, error) {
return nil, err
}
uh.ReverseProxy = NewSingleHostReverseProxy(baseURL, uh.WithoutPathPrefix)
uh.ReverseProxy = NewSingleHostReverseProxy(baseURL, uh.WithoutPathPrefix, u.KeepAlive)
if u.insecureSkipVerify {
uh.ReverseProxy.Transport = InsecureTransport
uh.ReverseProxy.UseInsecureTransport()
}
return uh, nil
......@@ -312,6 +313,15 @@ func parseBlock(c *caddyfile.Dispenser, u *staticUpstream) error {
u.IgnoredSubPaths = ignoredPaths
case "insecure_skip_verify":
u.insecureSkipVerify = true
case "keepalive":
if !c.NextArg() {
return c.ArgErr()
}
n, err := strconv.Atoi(c.Val())
if err != nil {
return err
}
u.KeepAlive = n
default:
return c.Errf("unknown property '%s'", c.Val())
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment