2017-08-01 20:32:44 +03:00
package integration
2017-07-25 17:56:46 +03:00
import (
2017-09-06 10:36:02 +03:00
"crypto/tls"
"crypto/x509"
2017-09-29 22:04:03 +03:00
"encoding/base64"
2017-09-06 10:36:02 +03:00
"io/ioutil"
2017-08-01 16:24:08 +03:00
"net"
"net/http"
"net/http/httptest"
2017-07-25 17:56:46 +03:00
"os"
2017-08-01 16:24:08 +03:00
"time"
2017-07-25 17:56:46 +03:00
2017-08-01 20:32:44 +03:00
"github.com/containous/traefik/integration/try"
2017-08-01 16:24:08 +03:00
"github.com/go-check/check"
gorillawebsocket "github.com/gorilla/websocket"
2017-07-25 17:56:46 +03:00
checker "github.com/vdemeester/shakers"
2017-08-01 16:24:08 +03:00
"golang.org/x/net/websocket"
2017-07-25 17:56:46 +03:00
)
// WebsocketSuite
type WebsocketSuite struct { BaseSuite }
2017-09-13 11:34:04 +03:00
func ( s * WebsocketSuite ) TestBase ( c * check . C ) {
2017-08-01 16:24:08 +03:00
var upgrader = gorillawebsocket . Upgrader { } // use default options
2017-07-25 17:56:46 +03:00
srv := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
c , err := upgrader . Upgrade ( w , r , nil )
if err != nil {
return
}
defer c . Close ( )
for {
mt , message , err := c . ReadMessage ( )
if err != nil {
break
}
err = c . WriteMessage ( mt , message )
if err != nil {
break
}
}
} ) )
2017-09-13 11:34:04 +03:00
file := s . adaptFile ( c , "fixtures/websocket/config.toml" , struct {
2017-07-25 17:56:46 +03:00
WebsocketServer string
} {
WebsocketServer : srv . URL ,
} )
defer os . Remove ( file )
2018-11-27 19:42:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) , "--global.debug" )
2017-09-13 11:34:04 +03:00
defer display ( c )
2017-07-25 17:56:46 +03:00
err := cmd . Start ( )
c . Assert ( err , check . IsNil )
defer cmd . Process . Kill ( )
// wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 10 * time . Second , try . BodyContains ( "127.0.0.1" ) )
2017-07-25 17:56:46 +03:00
c . Assert ( err , checker . IsNil )
2017-08-01 16:24:08 +03:00
conn , _ , err := gorillawebsocket . DefaultDialer . Dial ( "ws://127.0.0.1:8000/ws" , nil )
2017-08-18 03:18:02 +03:00
c . Assert ( err , checker . IsNil )
2017-07-25 17:56:46 +03:00
2017-08-18 03:18:02 +03:00
err = conn . WriteMessage ( gorillawebsocket . TextMessage , [ ] byte ( "OK" ) )
2017-07-25 17:56:46 +03:00
c . Assert ( err , checker . IsNil )
_ , msg , err := conn . ReadMessage ( )
c . Assert ( err , checker . IsNil )
c . Assert ( string ( msg ) , checker . Equals , "OK" )
}
2017-08-01 16:24:08 +03:00
2017-09-13 11:34:04 +03:00
func ( s * WebsocketSuite ) TestWrongOrigin ( c * check . C ) {
2017-08-01 16:24:08 +03:00
var upgrader = gorillawebsocket . Upgrader { } // use default options
srv := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
c , err := upgrader . Upgrade ( w , r , nil )
if err != nil {
return
}
defer c . Close ( )
for {
mt , message , err := c . ReadMessage ( )
if err != nil {
break
}
err = c . WriteMessage ( mt , message )
if err != nil {
break
}
}
} ) )
2017-09-13 11:34:04 +03:00
file := s . adaptFile ( c , "fixtures/websocket/config.toml" , struct {
2017-08-01 16:24:08 +03:00
WebsocketServer string
} {
WebsocketServer : srv . URL ,
} )
defer os . Remove ( file )
2018-11-27 19:42:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) , "--global.debug" )
2017-09-13 11:34:04 +03:00
defer display ( c )
2017-08-01 16:24:08 +03:00
err := cmd . Start ( )
c . Assert ( err , check . IsNil )
defer cmd . Process . Kill ( )
// wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 10 * time . Second , try . BodyContains ( "127.0.0.1" ) )
2017-08-01 16:24:08 +03:00
c . Assert ( err , checker . IsNil )
config , err := websocket . NewConfig ( "ws://127.0.0.1:8000/ws" , "ws://127.0.0.1:800" )
c . Assert ( err , check . IsNil )
conn , err := net . DialTimeout ( "tcp" , "127.0.0.1:8000" , time . Second )
2017-08-18 03:18:02 +03:00
c . Assert ( err , checker . IsNil )
2017-08-01 16:24:08 +03:00
_ , err = websocket . NewClient ( config , conn )
c . Assert ( err , checker . NotNil )
c . Assert ( err , checker . ErrorMatches , "bad status" )
}
2017-09-13 11:34:04 +03:00
func ( s * WebsocketSuite ) TestOrigin ( c * check . C ) {
2017-08-18 03:18:02 +03:00
// use default options
var upgrader = gorillawebsocket . Upgrader { }
2017-08-01 16:24:08 +03:00
srv := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
c , err := upgrader . Upgrade ( w , r , nil )
if err != nil {
return
}
defer c . Close ( )
for {
mt , message , err := c . ReadMessage ( )
if err != nil {
break
}
err = c . WriteMessage ( mt , message )
if err != nil {
break
}
}
} ) )
2017-09-13 11:34:04 +03:00
file := s . adaptFile ( c , "fixtures/websocket/config.toml" , struct {
2017-08-01 16:24:08 +03:00
WebsocketServer string
} {
WebsocketServer : srv . URL ,
} )
defer os . Remove ( file )
2018-11-27 19:42:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) , "--global.debug" )
2017-09-13 11:34:04 +03:00
defer display ( c )
2017-08-01 16:24:08 +03:00
err := cmd . Start ( )
c . Assert ( err , check . IsNil )
defer cmd . Process . Kill ( )
// wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 10 * time . Second , try . BodyContains ( "127.0.0.1" ) )
2017-08-01 16:24:08 +03:00
c . Assert ( err , checker . IsNil )
config , err := websocket . NewConfig ( "ws://127.0.0.1:8000/ws" , "ws://127.0.0.1:8000" )
c . Assert ( err , check . IsNil )
conn , err := net . DialTimeout ( "tcp" , "127.0.0.1:8000" , time . Second )
2017-08-18 03:18:02 +03:00
c . Assert ( err , check . IsNil )
2017-08-01 16:24:08 +03:00
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" )
}
2017-09-13 11:34:04 +03:00
func ( s * WebsocketSuite ) TestWrongOriginIgnoredByServer ( c * check . C ) {
2017-08-01 16:24:08 +03:00
var upgrader = gorillawebsocket . Upgrader { CheckOrigin : func ( r * http . Request ) bool {
return true
} }
srv := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
c , err := upgrader . Upgrade ( w , r , nil )
if err != nil {
return
}
defer c . Close ( )
for {
mt , message , err := c . ReadMessage ( )
if err != nil {
break
}
err = c . WriteMessage ( mt , message )
if err != nil {
break
}
}
} ) )
2017-09-13 11:34:04 +03:00
file := s . adaptFile ( c , "fixtures/websocket/config.toml" , struct {
2017-08-01 16:24:08 +03:00
WebsocketServer string
} {
WebsocketServer : srv . URL ,
} )
defer os . Remove ( file )
2018-11-27 19:42:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) , "--global.debug" )
2017-09-13 11:34:04 +03:00
defer display ( c )
2017-08-01 16:24:08 +03:00
err := cmd . Start ( )
c . Assert ( err , check . IsNil )
defer cmd . Process . Kill ( )
// wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 10 * time . Second , try . BodyContains ( "127.0.0.1" ) )
2017-08-01 16:24:08 +03:00
c . Assert ( err , checker . IsNil )
config , err := websocket . NewConfig ( "ws://127.0.0.1:8000/ws" , "ws://127.0.0.1:80" )
c . Assert ( err , check . IsNil )
conn , err := net . DialTimeout ( "tcp" , "127.0.0.1:8000" , time . Second )
2017-08-18 03:18:02 +03:00
c . Assert ( err , checker . IsNil )
2017-08-01 16:24:08 +03:00
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" )
}
2017-09-06 10:36:02 +03:00
2017-09-13 11:34:04 +03:00
func ( s * WebsocketSuite ) TestSSLTermination ( c * check . C ) {
2017-09-06 10:36:02 +03:00
var upgrader = gorillawebsocket . Upgrader { } // use default options
srv := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
c , err := upgrader . Upgrade ( w , r , nil )
if err != nil {
return
}
defer c . Close ( )
for {
mt , message , err := c . ReadMessage ( )
if err != nil {
break
}
err = c . WriteMessage ( mt , message )
if err != nil {
break
}
}
} ) )
2017-09-13 11:34:04 +03:00
file := s . adaptFile ( c , "fixtures/websocket/config_https.toml" , struct {
2017-09-06 10:36:02 +03:00
WebsocketServer string
} {
WebsocketServer : srv . URL ,
} )
defer os . Remove ( file )
2018-11-27 19:42:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) , "--global.debug" )
2017-09-13 11:34:04 +03:00
defer display ( c )
2017-09-06 10:36:02 +03:00
err := cmd . Start ( )
c . Assert ( err , check . IsNil )
defer cmd . Process . Kill ( )
// wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 10 * time . Second , try . BodyContains ( "127.0.0.1" ) )
2017-09-06 10:36:02 +03:00
c . Assert ( err , checker . IsNil )
2018-07-03 11:02:03 +03:00
// Add client self-signed cert
2017-09-06 10:36:02 +03:00
roots := x509 . NewCertPool ( )
certContent , err := ioutil . ReadFile ( "./resources/tls/local.cert" )
2017-12-04 22:04:08 +03:00
c . Assert ( err , checker . IsNil )
2017-09-06 10:36:02 +03:00
roots . AppendCertsFromPEM ( certContent )
gorillawebsocket . DefaultDialer . TLSClientConfig = & tls . Config {
RootCAs : roots ,
}
conn , _ , err := gorillawebsocket . DefaultDialer . Dial ( "wss://127.0.0.1:8000/ws" , nil )
c . Assert ( err , checker . IsNil )
err = conn . WriteMessage ( gorillawebsocket . TextMessage , [ ] byte ( "OK" ) )
c . Assert ( err , checker . IsNil )
_ , msg , err := conn . ReadMessage ( )
c . Assert ( err , checker . IsNil )
c . Assert ( string ( msg ) , checker . Equals , "OK" )
}
2017-09-29 22:04:03 +03:00
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 )
2018-11-27 19:42:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) , "--global.debug" )
2017-09-29 22:04:03 +03:00
defer display ( c )
err := cmd . Start ( )
c . Assert ( err , check . IsNil )
defer cmd . Process . Kill ( )
// wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 10 * time . Second , try . BodyContains ( "127.0.0.1" ) )
2017-09-29 22:04:03 +03:00
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 ) {
2017-11-20 11:40:03 +03:00
w . WriteHeader ( http . StatusUnauthorized )
2017-09-29 22:04:03 +03:00
} ) )
file := s . adaptFile ( c , "fixtures/websocket/config.toml" , struct {
WebsocketServer string
} {
WebsocketServer : srv . URL ,
} )
defer os . Remove ( file )
2018-11-27 19:42:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) , "--global.debug" )
2017-09-29 22:04:03 +03:00
defer display ( c )
err := cmd . Start ( )
c . Assert ( err , check . IsNil )
defer cmd . Process . Kill ( )
// wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 10 * time . Second , try . BodyContains ( "127.0.0.1" ) )
2017-09-29 22:04:03 +03:00
c . Assert ( err , checker . IsNil )
_ , resp , err := gorillawebsocket . DefaultDialer . Dial ( "ws://127.0.0.1:8000/ws" , nil )
c . Assert ( err , checker . NotNil )
2017-11-20 11:40:03 +03:00
c . Assert ( resp . StatusCode , check . Equals , http . StatusUnauthorized )
2017-09-29 22:04:03 +03:00
}
2017-10-02 16:36:02 +03:00
func ( s * WebsocketSuite ) TestURLWithURLEncodedChar ( c * check . C ) {
var upgrader = gorillawebsocket . Upgrader { } // use default options
srv := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
2017-11-22 20:20:03 +03:00
c . Assert ( r . URL . EscapedPath ( ) , check . Equals , "/ws/http%3A%2F%2Ftest" )
2017-10-02 16:36:02 +03:00
conn , err := upgrader . Upgrade ( w , r , nil )
if err != nil {
return
}
defer conn . Close ( )
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 )
2018-11-27 19:42:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) , "--global.debug" )
2017-10-02 16:36:02 +03:00
defer display ( c )
err := cmd . Start ( )
c . Assert ( err , check . IsNil )
defer cmd . Process . Kill ( )
// wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 10 * time . Second , try . BodyContains ( "127.0.0.1" ) )
2017-10-02 16:36:02 +03:00
c . Assert ( err , checker . IsNil )
conn , _ , err := gorillawebsocket . DefaultDialer . Dial ( "ws://127.0.0.1:8000/ws/http%3A%2F%2Ftest" , nil )
c . Assert ( err , checker . IsNil )
err = conn . WriteMessage ( gorillawebsocket . TextMessage , [ ] byte ( "OK" ) )
c . Assert ( err , checker . IsNil )
_ , msg , err := conn . ReadMessage ( )
c . Assert ( err , checker . IsNil )
c . Assert ( string ( msg ) , checker . Equals , "OK" )
}
2017-10-20 18:38:04 +03:00
func ( s * WebsocketSuite ) TestSSLhttp2 ( c * check . C ) {
var upgrader = gorillawebsocket . Upgrader { } // use default options
ts := httptest . NewUnstartedServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
c , err := upgrader . Upgrade ( w , r , nil )
if err != nil {
return
}
defer c . Close ( )
for {
mt , message , err := c . ReadMessage ( )
if err != nil {
break
}
err = c . WriteMessage ( mt , message )
if err != nil {
break
}
}
} ) )
ts . TLS = & tls . Config { }
ts . TLS . NextProtos = append ( ts . TLS . NextProtos , ` h2 ` )
ts . TLS . NextProtos = append ( ts . TLS . NextProtos , ` http/1.1 ` )
ts . StartTLS ( )
file := s . adaptFile ( c , "fixtures/websocket/config_https.toml" , struct {
WebsocketServer string
} {
WebsocketServer : ts . URL ,
} )
defer os . Remove ( file )
2018-11-27 19:42:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) , "--global.debug" , "--accesslog" )
2017-10-20 18:38:04 +03:00
defer display ( c )
err := cmd . Start ( )
c . Assert ( err , check . IsNil )
defer cmd . Process . Kill ( )
// wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 10 * time . Second , try . BodyContains ( "127.0.0.1" ) )
2017-10-20 18:38:04 +03:00
c . Assert ( err , checker . IsNil )
2018-07-03 11:02:03 +03:00
// Add client self-signed cert
2017-10-20 18:38:04 +03:00
roots := x509 . NewCertPool ( )
certContent , err := ioutil . ReadFile ( "./resources/tls/local.cert" )
2017-12-04 22:04:08 +03:00
c . Assert ( err , checker . IsNil )
2017-10-20 18:38:04 +03:00
roots . AppendCertsFromPEM ( certContent )
gorillawebsocket . DefaultDialer . TLSClientConfig = & tls . Config {
RootCAs : roots ,
}
conn , _ , err := gorillawebsocket . DefaultDialer . Dial ( "wss://127.0.0.1:8000/echo" , nil )
c . Assert ( err , checker . IsNil )
err = conn . WriteMessage ( gorillawebsocket . TextMessage , [ ] byte ( "OK" ) )
c . Assert ( err , checker . IsNil )
_ , msg , err := conn . ReadMessage ( )
c . Assert ( err , checker . IsNil )
c . Assert ( string ( msg ) , checker . Equals , "OK" )
}
2017-11-09 12:04:03 +03:00
func ( s * WebsocketSuite ) TestHeaderAreForwared ( c * check . C ) {
var upgrader = gorillawebsocket . Upgrader { } // use default options
srv := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
c . Assert ( r . Header . Get ( "X-Token" ) , check . Equals , "my-token" )
c , err := upgrader . Upgrade ( w , r , nil )
if err != nil {
return
}
defer c . Close ( )
for {
mt , message , err := c . ReadMessage ( )
if err != nil {
break
}
err = c . 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 )
2018-11-27 19:42:04 +03:00
cmd , display := s . traefikCmd ( withConfigFile ( file ) , "--global.debug" )
2017-11-09 12:04:03 +03:00
defer display ( c )
err := cmd . Start ( )
c . Assert ( err , check . IsNil )
defer cmd . Process . Kill ( )
// wait for traefik
2019-05-16 11:58:06 +03:00
err = try . GetRequest ( "http://127.0.0.1:8080/api/rawdata" , 10 * time . Second , try . BodyContains ( "127.0.0.1" ) )
2017-11-09 12:04:03 +03:00
c . Assert ( err , checker . IsNil )
headers := http . Header { }
headers . Add ( "X-Token" , "my-token" )
conn , _ , err := gorillawebsocket . DefaultDialer . Dial ( "ws://127.0.0.1:8000/ws" , headers )
c . Assert ( err , checker . IsNil )
err = conn . WriteMessage ( gorillawebsocket . TextMessage , [ ] byte ( "OK" ) )
c . Assert ( err , checker . IsNil )
_ , msg , err := conn . ReadMessage ( )
c . Assert ( err , checker . IsNil )
c . Assert ( string ( msg ) , checker . Equals , "OK" )
}