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 5package websocket 6 7import ( 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. 16type DialError struct { 17 *Config 18 Err error 19} 20 21func (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. 26func 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. 42func 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. 55func 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 66var portMap = map[string]string{ 67 "ws": "80", 68 "wss": "443", 69} 70 71func 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. 81func 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 104Error: 105 return nil, &DialError{config, err} 106} 107