diff --git a/.travis.yml b/.travis.yml
index 56196ff3b99563f57452e4b479e1015240fb442b..d24b9c9f6c71eff88f6f2fdbe47fec5e80e10616 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,6 +10,7 @@ services:
 language: go
 go:
 - 1.7
+- 1.8
 install:
 - go get github.com/tools/godep
 script:
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
index e5f883bfb5d3de81d3de3eeac757b3e45287103a..e3b3024c28393482455e346d1bffc006a98055dc 100644
--- a/Godeps/Godeps.json
+++ b/Godeps/Godeps.json
@@ -1,7 +1,7 @@
 {
 	"ImportPath": "github.com/gambol99/keycloak-proxy",
 	"GoVersion": "go1.7",
-	"GodepVersion": "v75",
+	"GodepVersion": "v79",
 	"Deps": [
 		{
 			"ImportPath": "github.com/Sirupsen/logrus",
@@ -72,8 +72,8 @@
 		},
 		{
 			"ImportPath": "github.com/gambol99/goproxy",
-			"Comment": "v1.0-96-g6016d23",
-			"Rev": "16403edea88bc5b716703dca58a5e94ad8b11879"
+			"Comment": "v1.0-87-gc3b6ff1",
+			"Rev": "c3b6ff1178d68ec9e93f7c996f41a3df89931d9f"
 		},
 		{
 			"ImportPath": "github.com/fsnotify/fsnotify",
diff --git a/vendor/github.com/gambol99/goproxy/README.md b/vendor/github.com/gambol99/goproxy/README.md
index b8ef757101f91900226c4e8a0447e2b9ba7e6e13..347993f7879a4573d9d436b28355a2840c17483f 100644
--- a/vendor/github.com/gambol99/goproxy/README.md
+++ b/vendor/github.com/gambol99/goproxy/README.md
@@ -36,7 +36,7 @@ as customable as goproxy intend to be. The main difference is, Fiddler is not
 intended to be used as a real proxy.
 
 A possible use case that suits goproxy but
-not Fiddler, is, gathering statistics on page load times for a certain website over a week.
+not Fiddler, is, gathering statisitics on page load times for a certain website over a week.
 With goproxy you could ask all your users to set their proxy to a dedicated machine running a
 goproxy server. Fiddler is a GUI app not designed to be ran like a server for multiple users.
 
diff --git a/vendor/github.com/gambol99/goproxy/certs.go b/vendor/github.com/gambol99/goproxy/certs.go
index 8da2e6240a9ab123adcd435540cbbb6526f4e2a5..1e8febdef78c474ba3c405eb637bb15507c34e08 100644
--- a/vendor/github.com/gambol99/goproxy/certs.go
+++ b/vendor/github.com/gambol99/goproxy/certs.go
@@ -22,35 +22,90 @@ var defaultTLSConfig = &tls.Config{
 }
 
 var CA_CERT = []byte(`-----BEGIN CERTIFICATE-----
-MIICSjCCAbWgAwIBAgIBADALBgkqhkiG9w0BAQUwSjEjMCEGA1UEChMaZ2l0aHVi
-LmNvbS9lbGF6YXJsL2dvcHJveHkxIzAhBgNVBAMTGmdpdGh1Yi5jb20vZWxhemFy
-bC9nb3Byb3h5MB4XDTAwMDEwMTAwMDAwMFoXDTQ5MTIzMTIzNTk1OVowSjEjMCEG
-A1UEChMaZ2l0aHViLmNvbS9lbGF6YXJsL2dvcHJveHkxIzAhBgNVBAMTGmdpdGh1
-Yi5jb20vZWxhemFybC9nb3Byb3h5MIGdMAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEA
-vz9BbCaJjxs73Tvcq3leP32hAGerQ1RgvlZ68Z4nZmoVHfl+2Nr/m0dmW+GdOfpT
-cs/KzfJjYGr/84x524fiuR8GdZ0HOtXJzyF5seoWnbBIuyr1PbEpgRhGQMqqOUuj
-YExeLbfNHPIoJ8XZ1Vzyv3YxjbmjWA+S/uOe9HWtDbMCAwEAAaNGMEQwDgYDVR0P
-AQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8w
-DAYDVR0RBAUwA4IBKjALBgkqhkiG9w0BAQUDgYEAIcL8huSmGMompNujsvePTUnM
-oEUKtX4Eh/+s+DSfV/TyI0I+3GiPpLplEgFWuoBIJGios0r1dKh5N0TGjxX/RmGm
-qo7E4jjJuo8Gs5U8/fgThZmshax2lwLtbRNwhvUVr65GdahLsZz8I+hySLuatVvR
-qHHq/FQORIiNyNpq/Hg=
+MIIF8jCCA9qgAwIBAgIUAp68XvvuMwaTCeQQjGxHEZhJcPgwDQYJKoZIhvcNAQEN
+BQAwgZAxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZy
+YW5jaXNjbzEUMBIGA1UEChMLQ29yZU9TLCBJbmMxIjAgBgNVBAsTGWdpdGh1Yi5j
+b20vY29yZW9zL2dvcHJveHkxIjAgBgNVBAMTGWdpdGh1Yi5jb20vY29yZW9zL2dv
+cHJveHkwHhcNMTcwMjIyMjI0NjAwWhcNMjIwMjIxMjI0NjAwWjCBkDELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYD
+VQQKEwtDb3JlT1MsIEluYzEiMCAGA1UECxMZZ2l0aHViLmNvbS9jb3Jlb3MvZ29w
+cm94eTEiMCAGA1UEAxMZZ2l0aHViLmNvbS9jb3Jlb3MvZ29wcm94eTCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBANghh+Y4gUYyIY1YzAgHBuLjTt13z5ED
+tbjksaK8kUMofaYCnQRrepTORB3xpxn9cIXpmmPND/c3pUZz+sSbidZF+Rfkz+G4
+oo5I04X7R2iFrw9jECcavr7qGqOt+vhep9iqVaioSWTKZoXY9FOxTpEUfdKyLE8K
+7rd6PfdjkbZ2ZqoKdRHARBE6QlTJv+elIRM6kzshx0oSdZfaUvLdmXFqHdfKz8gb
+FABaa8Aca6r76wHRnhK3+RQ2p+Wfz45/ZMxqQVIMr2mbiCCL4lSUPkUrid6L5DoA
+4A4pLqY+Y0cX2qIF+lmgUwUPvunqM7dA9toHjwBgeB1yF+jVOhFOizB/dXSCsBA2
+D47raP3REIxE6N05pEpGZqUPatcdyakP1Dan9aVO2W3o7P/LGPBdB5AiwVxRiVPx
+dNrz+UcE3dCPBrc9bxJLjyD7PtgPTrZ+hzR/kBfBW/+jvBRKIB5NCNSuQEUN99it
+P1fIencEz1ghaWhCAU5tQutnVBu8d0YlgjfnaD4vCJYEprifAiIpgZH3HaiHfG14
+UXFbdU0MmuIrie2PMAGmtnjhWHG0vc8f2THRklq/CtbfNWtPzUfYv+rpaOFw7bj+
+km0n3kVuGzWZhXPixe63TATR5lK9p21CZPXS+2mW/8uswBiJ4aT5lUZmCf/i1xyn
+Gzgv9so56vjFAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBSYLcfHmyPv3jmdTyBs/lu5PZLxPTANBgkqhkiG9w0BAQ0F
+AAOCAgEAppb+3MhGcL/IjqyRIWCc587eVMMtuHwGlczpMfXnf8TU0MPrvOdTPrqg
+a+AEc1W8O6IGrowmgbZVgfr7Pw0BL4VcSdAEbP7QcbPmRAudF+/xdm5vylJmB339
+4Yq5v1G2Ya5AN5PAHx3WVOA7s/caz30DGrsAoNhezlrk8WJRRxrQUauNveXyxNya
+urBrqjqNVUWAlv2fRHuNXsxMvG32MWQ1BoPa9Ix+dUWYeeWkxS5E9oNo99TRRTHB
+WX4SpsIynmhE+pFEzu2HVP2k5GE5+i78F9/N0cgI5QMSzgYxSebyPEflL1ziqWoq
+4xio69OM0Cq+GCxvOZmvKaNlOjwJa6NWa8IyumNFclTLNzMlBaDkVE9Tb5VEBphO
+ODzSxFMuAfXba4UlRjG9+BLg8ayzu2t9amB+B5/3/1+gkx1TE26jZNwleU6MnpFv
+umPqPa9AW2ZPobCTGjV3MwOIKFyO/cPt4fI6BpKF7jYhUYzsht/BZqQZU/rWY6h8
+GSEH8LcJk+Paaw03HzZWSbMp2oXNTz/BpQjuAdWAkeS3yhx5gvHIysWHvPRT017b
+Tx+Va9+T4DElT0HtmR/w27bXNL9Urj38ETSlbYoilL7ZKltj8djXmqkI1ZF8T1zk
+tj1zk0XYkestBgfrk9XYwvvL7DLyRPPZTAiVq/o5xn5zWp/y40M=
 -----END CERTIFICATE-----`)
 
 var CA_KEY = []byte(`-----BEGIN RSA PRIVATE KEY-----
-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
+MIIJKQIBAAKCAgEA2CGH5jiBRjIhjVjMCAcG4uNO3XfPkQO1uOSxoryRQyh9pgKd
+BGt6lM5EHfGnGf1whemaY80P9zelRnP6xJuJ1kX5F+TP4biijkjThftHaIWvD2MQ
+Jxq+vuoao636+F6n2KpVqKhJZMpmhdj0U7FOkRR90rIsTwrut3o992ORtnZmqgp1
+EcBEETpCVMm/56UhEzqTOyHHShJ1l9pS8t2ZcWod18rPyBsUAFprwBxrqvvrAdGe
+Erf5FDan5Z/Pjn9kzGpBUgyvaZuIIIviVJQ+RSuJ3ovkOgDgDikupj5jRxfaogX6
+WaBTBQ++6eozt0D22gePAGB4HXIX6NU6EU6LMH91dIKwEDYPjuto/dEQjETo3Tmk
+SkZmpQ9q1x3JqQ/UNqf1pU7Zbejs/8sY8F0HkCLBXFGJU/F02vP5RwTd0I8Gtz1v
+EkuPIPs+2A9Otn6HNH+QF8Fb/6O8FEogHk0I1K5ARQ332K0/V8h6dwTPWCFpaEIB
+Tm1C62dUG7x3RiWCN+doPi8IlgSmuJ8CIimBkfcdqId8bXhRcVt1TQya4iuJ7Y8w
+Aaa2eOFYcbS9zx/ZMdGSWr8K1t81a0/NR9i/6ulo4XDtuP6SbSfeRW4bNZmFc+LF
+7rdMBNHmUr2nbUJk9dL7aZb/y6zAGInhpPmVRmYJ/+LXHKcbOC/2yjnq+MUCAwEA
+AQKCAgBDt83SzmWCzvZASVA0O69mq33sWjvI3fa0JcOaj6ab+jXULAFyfxJ7SV2C
+XFLVC9mTu6vKFVgpR2AbgP9TVsCLSIVRfTm9KZKVLjBITIEFOM2u7oUDG5gkTUln
+e32lEFNayZPpMkE8uUYCLgXvqyBIyLjbqUPEyFIfXsfHmYTwPIzSPlCL7UfmdfCO
+jF/6fnysf6/d2SmOBdaea6ONwOzw4iTTlhIgSouryKj2GnGJs0Dg4wK6LrZ2JOHa
+SoZHyZaVjb1Frf/QARFX0Txq77/LAGdEOWSa3+dTyId7QxTsE4dHOMRGDLu2XEaf
+F+h4RHyTt8aQgalg4HypURXOkmN9jSodE8wBlj+oA5AOTFknqu2RMH+UX82uC4gs
+ccVDvd553SJyUtpSkvLvYv2Lu+o4w+uDsYZhdt12MDucnTwAzUqOWt2OSuX5LwZO
+Qi0xTmj5YnOju9MayfSuh14YRvxsVDK0XTZGm1FVlLtm6iitdSWCXZjGgKHEmNCk
+spd8sxdROxUID79tp4SVuAHzLZ3OTUrMVRvUksFRIiOX4vwcupvS8OVnRFC0yTpB
+d+V126XI5qISP0nAEvYOuI3GF3RiEiJ6P9PL15on3YY4AzmaAC8OimlFc7Gv2Vkt
+L7EvT83u/vT00H4xt85YMUksLupQXKSRnm7aTpHdW59zNO7AQQKCAQEA7QtGuzTt
+hG17hOBJ/VK9PE1Jy7aQ+SBZiY+92KgE9xAYoyPsFb/o0gLd11achsPUpTlku08n
+sgaW33wxFvTPL3Qf0TAwXxvavA/2JNboDy7iQbP7SBsNg0DaBU77bBpZo3/DBqK8
+vQPHN+CjiXLYqKFKk4FCX9umN6h1TClFmAQF9VS6pPjZJum3ECgHpvQJQlf4IX/l
+B9rV0wgfy1rnRgSC7eFSYaRiGv8uu1N9EHWQNa3R/a/2lADDTnwWcDsyE1Lu9WoT
+fv4LcOoYAvvNCSzkDwffvQcpJKluMcpZWOO6RqODdS4rv6nIS/Tyucj9jT0+6DGh
+raH80VDS0i+5aQKCAQEA6WogPbSqodvx5gwCCnQ6P/inbQV5rWU9hQfBmhYHGLan
+9cFMcZFWDDLvvEsuvdReFbnwsSfCT8BJWE/xsHbn39ep7mdPunqN3tfyF5sYRS18
+nLJrOQM50xePMbwFd7mnSuUauiDGPpOr0TF7C6kzUyTT3Mnzcxta5Yzpi9rQkm4C
+PcxctPrM6Xq3JZVrehZ/t1Ok+srEpfLbOMcDu22DejjfvMF0enSKZVEGTq3Ls1Yc
+LjhAoOP/YL9LcQqYmIkw8Cj9/5DEGaX97of+UxdDvRb5x4bn1/6/qaJxfSXSy+Rv
+n/E4+HccWRoA9KA0YUdLVBAsO9f2h+u7HUK3vkdc/QKCAQEA21in5uufLf+xYM+7
+J7K8cWSDeQJDPIR21hgw8J7pmUVHxw6ik6213z/P0EfRJ9Nmnk1xrPIeJVp7ment
+8vQuFBc8qfIRkLDRw1xxxL0ol4Qm0e2eBKcj5eTI2kiv1uS7NdQvv6AvTiiE3Gv+
+aF3hpok53SyrItC6Cp7Ti9pVD8oJSW9SFv4+0wdJ4qVoD1Gaj82fSkByysXxPwox
+gZdokx3xmfX6qWfXcGvZ7nXfMK/Y9hMWUc3WOjZKhAHHMatVNxRzEp1J1SV3qNC1
+z2z52he0IUSEAQLzS32M/n3kF6EC6gK8zl4fFYgiVEchpFEcbunRoELs/SL8MyS7
+MMwAoQKCAQAH+0II+iGPkVbPN//l3Z2UTGtlNfe4LysQXniHTVOGy9AofiigBYk8
+t40tEiESCq4A7i/Fzwc89OVNKMap8xbwt44vAcdfKAur4BR+LCaDTw/gx9UUyQB0
+MG0MFVLWijmnPPhR/wboYuJQL/H2Lx37LNo1xY4WlIviJ5Rg3OWe7DYVaOSOp7jU
+DwcuONLJBPXvDeQpUz+wMQLACUYeZZtGVaWI7dCO02dcGY4uqJC7nCkwh2nmVoWI
+CGKLBgK7zI0o2S3+TDP4cI2jV3Eh5DzDvYJjCUDqSOLC6TQaRG3V3QTYIkaBcIk+
+nr4Dn2rLHMX9pOPuU+8xLKVkVcC0t/n9AoIBAQDUPPjFkg80Cl63TZLpToB7K9Ki
+hmoVDqgG2E+91E3cDK2+/8knaPB57A3a34qqp06YjUaKr5v6dwuKgTK4ubUxtw4d
+iTIly2KJQX9U7kFira68irP+q+h6sbi0JfK9+lv5ITmJCBsy1MY4U7rLWnn3P+VS
+UtLGOP4gEn4ZtNFBrFJmP+AySvtTNhM+CF8Hi9p4i7tAkIzZ9kpMiQKU70LizCV9
+2FrsKJw2g4JaU97IFIquM/c6NG4cH+D9eP4YL3G+uodmdERvXJ5muFGUMaXMn/TC
++dyEZ2Dlz6DiGF63r7qGCi4nxyI3HfY3+hNA6X3NuucN8nVnD/S7kuzLWKhZ
 -----END RSA PRIVATE KEY-----`)
 
 var GoproxyCa, goproxyCaErr = tls.X509KeyPair(CA_CERT, CA_KEY)
diff --git a/vendor/github.com/gambol99/goproxy/https.go b/vendor/github.com/gambol99/goproxy/https.go
index 139f88d51936f2c502c6b92a4575a8a603ed3ef3..a9fa6ada69e3e245cbec2b44999ed6e82140dc6d 100644
--- a/vendor/github.com/gambol99/goproxy/https.go
+++ b/vendor/github.com/gambol99/goproxy/https.go
@@ -10,10 +10,8 @@ import (
 	"net/http"
 	"net/url"
 	"os"
-	"regexp"
 	"strconv"
 	"strings"
-	"sync"
 	"sync/atomic"
 )
 
@@ -33,7 +31,6 @@ var (
 	MitmConnect     = &ConnectAction{Action: ConnectMitm, TLSConfig: TLSConfigFromCA(&GoproxyCa)}
 	HTTPMitmConnect = &ConnectAction{Action: ConnectHTTPMitm, TLSConfig: TLSConfigFromCA(&GoproxyCa)}
 	RejectConnect   = &ConnectAction{Action: ConnectReject, TLSConfig: TLSConfigFromCA(&GoproxyCa)}
-	httpsRegexp     = regexp.MustCompile(`^https:\/\/`)
 )
 
 type ConnectAction struct {
@@ -101,25 +98,8 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request
 		}
 		ctx.Logf("Accepting CONNECT to %s", host)
 		proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
-
-		targetTCP, targetOK := targetSiteCon.(*net.TCPConn)
-		proxyClientTCP, clientOK := proxyClient.(*net.TCPConn)
-		if targetOK && clientOK {
-			go copyAndClose(ctx, targetTCP, proxyClientTCP)
-			go copyAndClose(ctx, proxyClientTCP, targetTCP)
-		} else {
-			go func() {
-				var wg sync.WaitGroup
-				wg.Add(2)
-				go copyOrWarn(ctx, targetSiteCon, proxyClient, &wg)
-				go copyOrWarn(ctx, proxyClient, targetSiteCon, &wg)
-				wg.Wait()
-				proxyClient.Close()
-				targetSiteCon.Close()
-
-			}()
-		}
-
+		go copyAndClose(ctx, targetSiteCon, proxyClient)
+		go copyAndClose(ctx, proxyClient, targetSiteCon)
 	case ConnectHijack:
 		ctx.Logf("Hijacking CONNECT to %s", host)
 		proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
@@ -153,7 +133,6 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request
 					httpError(proxyClient, ctx, err)
 					return
 				}
-				defer resp.Body.Close()
 			}
 			resp = proxy.filterResponse(resp, ctx)
 			if err := resp.Write(proxyClient); err != nil {
@@ -186,9 +165,9 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request
 			}
 			defer rawClientTls.Close()
 			clientTlsReader := bufio.NewReader(rawClientTls)
+
 			for !isEof(clientTlsReader) {
 				req, err := http.ReadRequest(clientTlsReader)
-				var ctx = &ProxyCtx{Req: req, Session: atomic.AddInt64(&proxy.sess, 1), proxy: proxy}
 				if err != nil && err != io.EOF {
 					return
 				}
@@ -196,12 +175,10 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request
 					ctx.Warnf("Cannot read TLS request from mitm'd client %v %v", r.Host, err)
 					return
 				}
+
 				req.RemoteAddr = r.RemoteAddr // since we're converting the request, need to carry over the original connecting IP as well
 				ctx.Logf("req %v", r.Host)
-
-				if !httpsRegexp.MatchString(req.URL.String()) {
-					req.URL, err = url.Parse("https://" + r.Host + req.URL.String())
-				}
+				req.URL, err = url.Parse("https://" + r.Host + req.URL.String())
 
 				// Bug fix which goproxy fails to provide request
 				// information URL in the context when does HTTPS MITM
@@ -209,6 +186,11 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request
 
 				req, resp := proxy.filterRequest(req, ctx)
 				if resp == nil {
+					if isWebSocketRequest(req) {
+						ctx.Logf("Request looks like websocket upgrade.")
+						proxy.serveWebsocketTLS(ctx, w, req, tlsConfig, rawClientTls)
+						return
+					}
 					if err != nil {
 						ctx.Warnf("Illegal URL %s", "https://"+r.Host+req.URL.Path)
 						return
@@ -221,9 +203,8 @@ func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request
 					}
 					ctx.Logf("resp %v", resp.Status)
 				}
-				resp = proxy.filterResponse(resp, ctx)
-				defer resp.Body.Close()
 
+				resp = proxy.filterResponse(resp, ctx)
 				text := resp.Status
 				statusCode := strconv.Itoa(resp.StatusCode) + " "
 				if strings.HasPrefix(text, statusCode) {
@@ -284,20 +265,15 @@ func httpError(w io.WriteCloser, ctx *ProxyCtx, err error) {
 	}
 }
 
-func copyOrWarn(ctx *ProxyCtx, dst io.Writer, src io.Reader, wg *sync.WaitGroup) {
-	if _, err := io.Copy(dst, src); err != nil {
+func copyAndClose(ctx *ProxyCtx, w, r net.Conn) {
+	connOk := true
+	if _, err := io.Copy(w, r); err != nil {
+		connOk = false
 		ctx.Warnf("Error copying to client: %s", err)
 	}
-	wg.Done()
-}
-
-func copyAndClose(ctx *ProxyCtx, dst, src *net.TCPConn) {
-	if _, err := io.Copy(dst, src); err != nil {
-		ctx.Warnf("Error copying to client: %s", err)
+	if err := r.Close(); err != nil && connOk {
+		ctx.Warnf("Error closing: %s", err)
 	}
-
-	dst.CloseWrite()
-	src.CloseRead()
 }
 
 func dialerFromEnv(proxy *ProxyHttpServer) func(network, addr string) (net.Conn, error) {
@@ -341,19 +317,15 @@ func (proxy *ProxyHttpServer) NewConnectDialToProxy(https_proxy string) func(net
 				c.Close()
 				return nil, err
 			}
-			defer resp.Body.Close()
 			if resp.StatusCode != 200 {
-				resp, err := ioutil.ReadAll(resp.Body)
-				if err != nil {
-					return nil, err
-				}
+				resp, _ := ioutil.ReadAll(resp.Body)
 				c.Close()
 				return nil, errors.New("proxy refused connection" + string(resp))
 			}
 			return c, nil
 		}
 	}
-	if u.Scheme == "https" {
+	if u.Scheme == "https" || u.Scheme == "wss" {
 		if strings.IndexRune(u.Host, ':') == -1 {
 			u.Host += ":443"
 		}
@@ -379,12 +351,9 @@ func (proxy *ProxyHttpServer) NewConnectDialToProxy(https_proxy string) func(net
 				c.Close()
 				return nil, err
 			}
-			defer resp.Body.Close()
 			if resp.StatusCode != 200 {
-				body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 500))
-				if err != nil {
-					return nil, err
-				}
+				body, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 500))
+				resp.Body.Close()
 				c.Close()
 				return nil, errors.New("proxy refused connection" + string(body))
 			}
diff --git a/vendor/github.com/gambol99/goproxy/proxy.go b/vendor/github.com/gambol99/goproxy/proxy.go
index 5c69597af56e9ef08804ce5a90e267af428f15cf..a83f0489263c8e3db155ec4bb6546f5c07b594ba 100644
--- a/vendor/github.com/gambol99/goproxy/proxy.go
+++ b/vendor/github.com/gambol99/goproxy/proxy.go
@@ -19,6 +19,7 @@ type ProxyHttpServer struct {
 	// setting Verbose to true will log information on each request sent to the proxy
 	Verbose         bool
 	Logger          *log.Logger
+	isReverseProxy  bool
 	NonproxyHandler http.Handler
 	reqHandlers     []ReqHandler
 	respHandlers    []RespHandler
@@ -75,7 +76,7 @@ func removeProxyHeaders(ctx *ProxyCtx, r *http.Request) {
 	// and would wrap the response body with the relevant reader.
 	r.Header.Del("Accept-Encoding")
 	// curl can add that, see
-	// https://jdebp.eu./FGA/web-proxy-connection-header.html
+	// http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/web-proxy-connection-header.html
 	r.Header.Del("Proxy-Connection")
 	r.Header.Del("Proxy-Authenticate")
 	r.Header.Del("Proxy-Authorization")
@@ -98,20 +99,30 @@ func (proxy *ProxyHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request)
 
 		var err error
 		ctx.Logf("Got request %v %v %v %v", r.URL.Path, r.Host, r.Method, r.URL.String())
-		if !r.URL.IsAbs() {
+
+		if (proxy.isReverseProxy && r.URL.IsAbs()) || (!proxy.isReverseProxy && !r.URL.IsAbs()) {
 			proxy.NonproxyHandler.ServeHTTP(w, r)
 			return
 		}
 		r, resp := proxy.filterRequest(r, ctx)
 
 		if resp == nil {
+			if proxy.isReverseProxy && (r.URL.Scheme == "" || r.URL.Host == "") {
+				panic("ReverseProxy did not rewrite request's Scheme or Host")
+			}
+
+			if isWebSocketRequest(r) {
+				ctx.Logf("Request looks like websocket upgrade.")
+				proxy.serveWebsocket(ctx, w, r)
+			}
+
 			removeProxyHeaders(ctx, r)
 			resp, err = ctx.RoundTrip(r)
 			if err != nil {
 				ctx.Error = err
 				resp = proxy.filterResponse(nil, ctx)
 				if resp == nil {
-					ctx.Logf("error read response %v %v:", r.URL.Host, err.Error())
+					ctx.Logf("Error read response %v %v:", r.URL.Host, err.Error())
 					http.Error(w, err.Error(), 500)
 					return
 				}
@@ -120,7 +131,7 @@ func (proxy *ProxyHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request)
 		}
 		origBody := resp.Body
 		resp = proxy.filterResponse(resp, ctx)
-		defer origBody.Close()
+
 		ctx.Logf("Copying response to client %v [%d]", resp.Status, resp.StatusCode)
 		// http.ResponseWriter will take care of filling the correct response length
 		// Setting it now, might impose wrong value, contradicting the actual new
@@ -149,11 +160,26 @@ func NewProxyHttpServer() *ProxyHttpServer {
 		respHandlers:  []RespHandler{},
 		httpsHandlers: []HttpsHandler{},
 		NonproxyHandler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
-			http.Error(w, "This is a proxy server. Does not respond to non-proxy requests.", 500)
+			http.Error(w, "This is a forward proxy server. Does not respond to non-proxy requests.", 500)
 		}),
-		Tr: &http.Transport{TLSClientConfig: tlsClientSkipVerify,
-			Proxy: http.ProxyFromEnvironment},
+		Tr: &http.Transport{
+			TLSClientConfig: tlsClientSkipVerify,
+			Proxy:           http.ProxyFromEnvironment,
+		},
 	}
+
 	proxy.ConnectDial = dialerFromEnv(&proxy)
+
 	return &proxy
 }
+
+func NewReverseProxyHttpServer() *ProxyHttpServer {
+	reverseProxy := NewProxyHttpServer()
+
+	reverseProxy.isReverseProxy = true
+	reverseProxy.NonproxyHandler = http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+		http.Error(w, "This is a reverse proxy server. Does not respond to proxy requests.", 500)
+	})
+
+	return reverseProxy
+}
diff --git a/vendor/github.com/gambol99/goproxy/websocket.go b/vendor/github.com/gambol99/goproxy/websocket.go
new file mode 100644
index 0000000000000000000000000000000000000000..2a9699117a9e88d995dae3e626bae4d4c1d43026
--- /dev/null
+++ b/vendor/github.com/gambol99/goproxy/websocket.go
@@ -0,0 +1,121 @@
+package goproxy
+
+import (
+	"bufio"
+	"crypto/tls"
+	"io"
+	"net/http"
+	"net/url"
+	"strings"
+)
+
+func headerContains(header http.Header, name string, value string) bool {
+	for _, v := range header[name] {
+		for _, s := range strings.Split(v, ",") {
+			if strings.EqualFold(value, strings.TrimSpace(s)) {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func isWebSocketRequest(r *http.Request) bool {
+	return headerContains(r.Header, "Connection", "upgrade") &&
+		headerContains(r.Header, "Upgrade", "websocket")
+}
+
+func (proxy *ProxyHttpServer) serveWebsocketTLS(ctx *ProxyCtx, w http.ResponseWriter, req *http.Request, tlsConfig *tls.Config, clientConn *tls.Conn) {
+	targetURL := url.URL{Scheme: "wss", Host: req.URL.Host, Path: req.URL.Path}
+
+	// Connect to upstream
+	targetConn, err := tls.Dial("tcp", targetURL.Host, tlsConfig)
+	if err != nil {
+		ctx.Warnf("Error dialing target site: %v", err)
+		return
+	}
+	defer targetConn.Close()
+
+	// Perform handshake
+	if err := proxy.websocketHandshake(ctx, req, targetConn, clientConn); err != nil {
+		ctx.Warnf("Websocket handshake error: %v", err)
+		return
+	}
+
+	// Proxy wss connection
+	proxy.proxyWebsocket(ctx, targetConn, clientConn)
+}
+
+func (proxy *ProxyHttpServer) serveWebsocket(ctx *ProxyCtx, w http.ResponseWriter, req *http.Request) {
+	targetURL := url.URL{Scheme: "ws", Host: req.URL.Host, Path: req.URL.Path}
+
+	targetConn, err := proxy.connectDial("tcp", targetURL.Host)
+	if err != nil {
+		ctx.Warnf("Error dialing target site: %v", err)
+		return
+	}
+	defer targetConn.Close()
+
+	// Connect to Client
+	hj, ok := w.(http.Hijacker)
+	if !ok {
+		panic("httpserver does not support hijacking")
+	}
+	clientConn, _, err := hj.Hijack()
+	if err != nil {
+		ctx.Warnf("Hijack error: %v", err)
+		return
+	}
+
+	// Perform handshake
+	if err := proxy.websocketHandshake(ctx, req, targetConn, clientConn); err != nil {
+		ctx.Warnf("Websocket handshake error: %v", err)
+		return
+	}
+
+	// Proxy ws connection
+	proxy.proxyWebsocket(ctx, targetConn, clientConn)
+}
+
+func (proxy *ProxyHttpServer) websocketHandshake(ctx *ProxyCtx, req *http.Request, targetSiteConn io.ReadWriter, clientConn io.ReadWriter) error {
+	// write handshake request to target
+	err := req.Write(targetSiteConn)
+	if err != nil {
+		ctx.Warnf("Error writing upgrade request: %v", err)
+		return err
+	}
+
+	targetTLSReader := bufio.NewReader(targetSiteConn)
+
+	// Read handshake response from target
+	resp, err := http.ReadResponse(targetTLSReader, req)
+	if err != nil {
+		ctx.Warnf("Error reading handhsake response  %v", err)
+		return err
+	}
+
+	// Run response through handlers
+	resp = proxy.filterResponse(resp, ctx)
+
+	// Proxy handshake back to client
+	err = resp.Write(clientConn)
+	if err != nil {
+		ctx.Warnf("Error writing handshake response: %v", err)
+		return err
+	}
+	return nil
+}
+
+func (proxy *ProxyHttpServer) proxyWebsocket(ctx *ProxyCtx, dest io.ReadWriter, source io.ReadWriter) {
+	errChan := make(chan error, 2)
+	cp := func(dst io.Writer, src io.Reader) {
+		_, err := io.Copy(dst, src)
+		ctx.Warnf("Websocket error: %v", err)
+		errChan <- err
+	}
+
+	// Start proxying websocket data
+	go cp(dest, source)
+	go cp(source, dest)
+	<-errChan
+}