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 }