github.com/deis/deis@v1.13.5-0.20170519182049-1d9e59fbdbfc/Godeps/_workspace/src/golang.org/x/net/websocket/client.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package websocket
     6  
     7  import (
     8  	"bufio"
     9  	"crypto/tls"
    10  	"io"
    11  	"net"
    12  	"net/http"
    13  	"net/url"
    14  )
    15  
    16  // DialError is an error that occurs while dialling a websocket server.
    17  type DialError struct {
    18  	*Config
    19  	Err error
    20  }
    21  
    22  func (e *DialError) Error() string {
    23  	return "websocket.Dial " + e.Config.Location.String() + ": " + e.Err.Error()
    24  }
    25  
    26  // NewConfig creates a new WebSocket config for client connection.
    27  func NewConfig(server, origin string) (config *Config, err error) {
    28  	config = new(Config)
    29  	config.Version = ProtocolVersionHybi13
    30  	config.Location, err = url.ParseRequestURI(server)
    31  	if err != nil {
    32  		return
    33  	}
    34  	config.Origin, err = url.ParseRequestURI(origin)
    35  	if err != nil {
    36  		return
    37  	}
    38  	config.Header = http.Header(make(map[string][]string))
    39  	return
    40  }
    41  
    42  // NewClient creates a new WebSocket client connection over rwc.
    43  func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) {
    44  	br := bufio.NewReader(rwc)
    45  	bw := bufio.NewWriter(rwc)
    46  	err = hybiClientHandshake(config, br, bw)
    47  	if err != nil {
    48  		return
    49  	}
    50  	buf := bufio.NewReadWriter(br, bw)
    51  	ws = newHybiClientConn(config, buf, rwc)
    52  	return
    53  }
    54  
    55  // Dial opens a new client connection to a WebSocket.
    56  func Dial(url_, protocol, origin string) (ws *Conn, err error) {
    57  	config, err := NewConfig(url_, origin)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	if protocol != "" {
    62  		config.Protocol = []string{protocol}
    63  	}
    64  	return DialConfig(config)
    65  }
    66  
    67  var portMap = map[string]string{
    68  	"ws":  "80",
    69  	"wss": "443",
    70  }
    71  
    72  func parseAuthority(location *url.URL) string {
    73  	if _, ok := portMap[location.Scheme]; ok {
    74  		if _, _, err := net.SplitHostPort(location.Host); err != nil {
    75  			return net.JoinHostPort(location.Host, portMap[location.Scheme])
    76  		}
    77  	}
    78  	return location.Host
    79  }
    80  
    81  // DialConfig opens a new client connection to a WebSocket with a config.
    82  func DialConfig(config *Config) (ws *Conn, err error) {
    83  	var client net.Conn
    84  	if config.Location == nil {
    85  		return nil, &DialError{config, ErrBadWebSocketLocation}
    86  	}
    87  	if config.Origin == nil {
    88  		return nil, &DialError{config, ErrBadWebSocketOrigin}
    89  	}
    90  	switch config.Location.Scheme {
    91  	case "ws":
    92  		client, err = net.Dial("tcp", parseAuthority(config.Location))
    93  
    94  	case "wss":
    95  		client, err = tls.Dial("tcp", parseAuthority(config.Location), config.TlsConfig)
    96  
    97  	default:
    98  		err = ErrBadScheme
    99  	}
   100  	if err != nil {
   101  		goto Error
   102  	}
   103  
   104  	ws, err = NewClient(config, client)
   105  	if err != nil {
   106  		client.Close()
   107  		goto Error
   108  	}
   109  	return
   110  
   111  Error:
   112  	return nil, &DialError{config, err}
   113  }