github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/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  	"io"
    10  	"net"
    11  	"net/http"
    12  	"net/url"
    13  )
    14  
    15  // DialError is an error that occurs while dialling a websocket server.
    16  type DialError struct {
    17  	*Config
    18  	Err error
    19  }
    20  
    21  func (e *DialError) Error() string {
    22  	return "websocket.Dial " + e.Config.Location.String() + ": " + e.Err.Error()
    23  }
    24  
    25  // NewConfig creates a new WebSocket config for client connection.
    26  func NewConfig(server, origin string) (config *Config, err error) {
    27  	config = new(Config)
    28  	config.Version = ProtocolVersionHybi13
    29  	config.Location, err = url.ParseRequestURI(server)
    30  	if err != nil {
    31  		return
    32  	}
    33  	config.Origin, err = url.ParseRequestURI(origin)
    34  	if err != nil {
    35  		return
    36  	}
    37  	config.Header = http.Header(make(map[string][]string))
    38  	return
    39  }
    40  
    41  // NewClient creates a new WebSocket client connection over rwc.
    42  func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) {
    43  	br := bufio.NewReader(rwc)
    44  	bw := bufio.NewWriter(rwc)
    45  	err = hybiClientHandshake(config, br, bw)
    46  	if err != nil {
    47  		return
    48  	}
    49  	buf := bufio.NewReadWriter(br, bw)
    50  	ws = newHybiClientConn(config, buf, rwc)
    51  	return
    52  }
    53  
    54  // Dial opens a new client connection to a WebSocket.
    55  func Dial(url_, protocol, origin string) (ws *Conn, err error) {
    56  	config, err := NewConfig(url_, origin)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	if protocol != "" {
    61  		config.Protocol = []string{protocol}
    62  	}
    63  	return DialConfig(config)
    64  }
    65  
    66  var portMap = map[string]string{
    67  	"ws":  "80",
    68  	"wss": "443",
    69  }
    70  
    71  func parseAuthority(location *url.URL) string {
    72  	if _, ok := portMap[location.Scheme]; ok {
    73  		if _, _, err := net.SplitHostPort(location.Host); err != nil {
    74  			return net.JoinHostPort(location.Host, portMap[location.Scheme])
    75  		}
    76  	}
    77  	return location.Host
    78  }
    79  
    80  // DialConfig opens a new client connection to a WebSocket with a config.
    81  func DialConfig(config *Config) (ws *Conn, err error) {
    82  	var client net.Conn
    83  	if config.Location == nil {
    84  		return nil, &DialError{config, ErrBadWebSocketLocation}
    85  	}
    86  	if config.Origin == nil {
    87  		return nil, &DialError{config, ErrBadWebSocketOrigin}
    88  	}
    89  	dialer := config.Dialer
    90  	if dialer == nil {
    91  		dialer = &net.Dialer{}
    92  	}
    93  	client, err = dialWithDialer(dialer, config)
    94  	if err != nil {
    95  		goto Error
    96  	}
    97  	ws, err = NewClient(config, client)
    98  	if err != nil {
    99  		client.Close()
   100  		goto Error
   101  	}
   102  	return
   103  
   104  Error:
   105  	return nil, &DialError{config, err}
   106  }