diff --git a/glide.lock b/glide.lock index 092eb0694..1316462ff 100644 --- a/glide.lock +++ b/glide.lock @@ -1,4 +1,4 @@ -hash: 123a0f00c37d07cd6d0583437b70092176e8d5c2445e127afef40acdc4e5aa32 +hash: 17b4abe35874c0990cf9ac68f4cdfae0229f4395097bcaab3105b698d91bd272 updated: 2017-09-18T11:52:16.848940186+02:00 imports: - name: cloud.google.com/go @@ -477,7 +477,7 @@ imports: - name: github.com/urfave/negroni version: 490e6a555d47ca891a89a150d0c1ef3922dfffe9 - name: github.com/vulcand/oxy - version: 6c94d2888dba2b1a15a89b8a2ca515fc85e07477 + version: 648088ee0902cf8d8337826ae2a82444008720e2 repo: https://github.com/containous/oxy.git vcs: git subpackages: diff --git a/glide.yaml b/glide.yaml index 0a9c81934..6878be391 100644 --- a/glide.yaml +++ b/glide.yaml @@ -12,7 +12,7 @@ import: - package: github.com/cenk/backoff - package: github.com/containous/flaeg - package: github.com/vulcand/oxy - version: 6c94d2888dba2b1a15a89b8a2ca515fc85e07477 + version: 648088ee0902cf8d8337826ae2a82444008720e2 repo: https://github.com/containous/oxy.git vcs: git subpackages: diff --git a/integration/websocket_test.go b/integration/websocket_test.go index 220562eb8..2ad267fae 100644 --- a/integration/websocket_test.go +++ b/integration/websocket_test.go @@ -3,6 +3,7 @@ package integration import ( "crypto/tls" "crypto/x509" + "encoding/base64" "io/ioutil" "net" "net/http" @@ -295,3 +296,97 @@ func (s *WebsocketSuite) TestSSLTermination(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(string(msg), checker.Equals, "OK") } + +func (s *WebsocketSuite) TestBasicAuth(c *check.C) { + var upgrader = gorillawebsocket.Upgrader{} // use default options + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + conn, err := upgrader.Upgrade(w, r, nil) + + if err != nil { + return + } + defer conn.Close() + + user, password, _ := r.BasicAuth() + c.Assert(user, check.Equals, "traefiker") + c.Assert(password, check.Equals, "secret") + + for { + mt, message, err := conn.ReadMessage() + if err != nil { + break + } + err = conn.WriteMessage(mt, message) + if err != nil { + break + } + } + })) + file := s.adaptFile(c, "fixtures/websocket/config.toml", struct { + WebsocketServer string + }{ + WebsocketServer: srv.URL, + }) + + defer os.Remove(file) + cmd, display := s.traefikCmd(withConfigFile(file), "--debug") + defer display(c) + + err := cmd.Start() + c.Assert(err, check.IsNil) + defer cmd.Process.Kill() + + // wait for traefik + err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("127.0.0.1")) + c.Assert(err, checker.IsNil) + + config, err := websocket.NewConfig("ws://127.0.0.1:8000/ws", "ws://127.0.0.1:8000") + auth := "traefiker:secret" + config.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth))) + + c.Assert(err, check.IsNil) + + conn, err := net.DialTimeout("tcp", "127.0.0.1:8000", time.Second) + c.Assert(err, checker.IsNil) + client, err := websocket.NewClient(config, conn) + c.Assert(err, checker.IsNil) + + n, err := client.Write([]byte("OK")) + c.Assert(err, checker.IsNil) + c.Assert(n, checker.Equals, 2) + + msg := make([]byte, 2) + n, err = client.Read(msg) + c.Assert(err, checker.IsNil) + c.Assert(n, checker.Equals, 2) + c.Assert(string(msg), checker.Equals, "OK") +} + +func (s *WebsocketSuite) TestSpecificResponseFromBackend(c *check.C) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(401) + })) + file := s.adaptFile(c, "fixtures/websocket/config.toml", struct { + WebsocketServer string + }{ + WebsocketServer: srv.URL, + }) + + defer os.Remove(file) + cmd, display := s.traefikCmd(withConfigFile(file), "--debug") + defer display(c) + + err := cmd.Start() + c.Assert(err, check.IsNil) + defer cmd.Process.Kill() + + // wait for traefik + err = try.GetRequest("http://127.0.0.1:8080/api/providers", 10*time.Second, try.BodyContains("127.0.0.1")) + c.Assert(err, checker.IsNil) + + _, resp, err := gorillawebsocket.DefaultDialer.Dial("ws://127.0.0.1:8000/ws", nil) + c.Assert(err, checker.NotNil) + c.Assert(resp.StatusCode, check.Equals, 401) + +} diff --git a/vendor/github.com/vulcand/oxy/forward/fwd.go b/vendor/github.com/vulcand/oxy/forward/fwd.go index 04974ad4d..a30c76ba0 100644 --- a/vendor/github.com/vulcand/oxy/forward/fwd.go +++ b/vendor/github.com/vulcand/oxy/forward/fwd.go @@ -9,6 +9,7 @@ import ( "net/http" "net/url" "os" + "reflect" "strconv" "strings" "time" @@ -261,8 +262,32 @@ func (f *websocketForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, } targetConn, resp, err := dialer.Dial(outReq.URL.String(), outReq.Header) if err != nil { - ctx.log.Errorf("Error dialing `%v`: %v", outReq.Host, err) - ctx.errHandler.ServeHTTP(w, req, err) + if resp == nil { + ctx.errHandler.ServeHTTP(w, req, err) + } else { + ctx.log.Errorf("Error dialing %q: %v with resp: %d %s", outReq.Host, err, resp.StatusCode, resp.Status) + hijacker, ok := w.(http.Hijacker) + if !ok { + ctx.log.Errorf("%s can not be hijack", reflect.TypeOf(w)) + ctx.errHandler.ServeHTTP(w, req, err) + return + } + + conn, _, err := hijacker.Hijack() + if err != nil { + ctx.log.Errorf("Failed to hijack responseWriter") + ctx.errHandler.ServeHTTP(w, req, err) + return + } + defer conn.Close() + + err = resp.Write(conn) + if err != nil { + ctx.log.Errorf("Failed to forward response") + ctx.errHandler.ServeHTTP(w, req, err) + return + } + } return }