blob: e59da0b60af8ae262ee6719714d4ccd6fdd358f8 [file] [log] [blame]
Russ Cox3294cb52012-01-25 15:31:30 -05001// 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 "crypto/tls"
10 "io"
11 "net"
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
David Symonds359f9342012-02-18 12:49:41 +110029 config.Location, err = url.ParseRequestURI(server)
Russ Cox3294cb52012-01-25 15:31:30 -050030 if err != nil {
31 return
32 }
David Symonds359f9342012-02-18 12:49:41 +110033 config.Origin, err = url.ParseRequestURI(origin)
Russ Cox3294cb52012-01-25 15:31:30 -050034 if err != nil {
35 return
36 }
37 return
38}
39
40// NewClient creates a new WebSocket client connection over rwc.
41func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) {
42 br := bufio.NewReader(rwc)
43 bw := bufio.NewWriter(rwc)
44 switch config.Version {
45 case ProtocolVersionHixie75:
46 err = hixie75ClientHandshake(config, br, bw)
47 case ProtocolVersionHixie76, ProtocolVersionHybi00:
48 err = hixie76ClientHandshake(config, br, bw)
49 case ProtocolVersionHybi08, ProtocolVersionHybi13:
50 err = hybiClientHandshake(config, br, bw)
51 default:
52 err = ErrBadProtocolVersion
53 }
54 if err != nil {
55 return
56 }
57 buf := bufio.NewReadWriter(br, bw)
58 switch config.Version {
59 case ProtocolVersionHixie75, ProtocolVersionHixie76, ProtocolVersionHybi00:
60 ws = newHixieClientConn(config, buf, rwc)
61 case ProtocolVersionHybi08, ProtocolVersionHybi13:
62 ws = newHybiClientConn(config, buf, rwc)
63 }
64 return
65}
66
Francisco Souza3b94eae2012-09-06 15:22:57 +100067// Dial opens a new client connection to a WebSocket.
Russ Cox3294cb52012-01-25 15:31:30 -050068func Dial(url_, protocol, origin string) (ws *Conn, err error) {
69 config, err := NewConfig(url_, origin)
70 if err != nil {
71 return nil, err
72 }
Fumitoshi Ukai5a654032012-10-10 07:45:07 +090073 if protocol != "" {
74 config.Protocol = []string{protocol}
75 }
Russ Cox3294cb52012-01-25 15:31:30 -050076 return DialConfig(config)
77}
78
79// DialConfig opens a new client connection to a WebSocket with a config.
80func DialConfig(config *Config) (ws *Conn, err error) {
81 var client net.Conn
82 if config.Location == nil {
83 return nil, &DialError{config, ErrBadWebSocketLocation}
84 }
85 if config.Origin == nil {
86 return nil, &DialError{config, ErrBadWebSocketOrigin}
87 }
88 switch config.Location.Scheme {
89 case "ws":
90 client, err = net.Dial("tcp", config.Location.Host)
91
92 case "wss":
93 client, err = tls.Dial("tcp", config.Location.Host, config.TlsConfig)
94
95 default:
96 err = ErrBadScheme
97 }
98 if err != nil {
99 goto Error
100 }
101
102 ws, err = NewClient(config, client)
103 if err != nil {
104 goto Error
105 }
106 return
107
108Error:
109 return nil, &DialError{config, err}
110}