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.
25
func echoServer(ws *Conn) { io.Copy(ws, ws) }
32
func countServer(ws *Conn) {
35
err := JSON.Receive(ws, &count)
40
count.S = strings.Repeat(count.S, count.N)
41
err = JSON.Send(ws, count)
48
func subProtocolHandshake(config *Config, req *http.Request) error {
49
for _, proto := range config.Protocol {
51
config.Protocol = []string{proto}
55
return ErrBadWebSocketProtocol
58
func subProtoServer(ws *Conn) {
59
for _, proto := range ws.Config().Protocol {
60
io.WriteString(ws, proto)
65
http.Handle("/echo", Handler(echoServer))
66
http.Handle("/count", Handler(countServer))
68
Handshake: subProtocolHandshake,
69
Handler: Handler(subProtoServer),
71
http.Handle("/subproto", subproto)
72
server := httptest.NewServer(nil)
73
serverAddr = server.Listener.Addr().String()
74
log.Print("Test WebSocket server listening on ", serverAddr)
77
func newConfig(t *testing.T, path string) *Config {
78
config, _ := NewConfig(fmt.Sprintf("ws://%s%s", serverAddr, path), "http://localhost")
82
func TestEcho(t *testing.T) {
86
client, err := net.Dial("tcp", serverAddr)
88
t.Fatal("dialing", err)
90
conn, err := NewClient(newConfig(t, "/echo"), client)
92
t.Errorf("WebSocket handshake error: %v", err)
96
msg := []byte("hello, world\n")
97
if _, err := conn.Write(msg); err != nil {
98
t.Errorf("Write: %v", err)
100
var actual_msg = make([]byte, 512)
101
n, err := conn.Read(actual_msg)
103
t.Errorf("Read: %v", err)
105
actual_msg = actual_msg[0:n]
106
if !bytes.Equal(msg, actual_msg) {
107
t.Errorf("Echo: expected %q got %q", msg, actual_msg)
112
func TestAddr(t *testing.T) {
116
client, err := net.Dial("tcp", serverAddr)
118
t.Fatal("dialing", err)
120
conn, err := NewClient(newConfig(t, "/echo"), client)
122
t.Errorf("WebSocket handshake error: %v", err)
126
ra := conn.RemoteAddr().String()
127
if !strings.HasPrefix(ra, "ws://") || !strings.HasSuffix(ra, "/echo") {
128
t.Errorf("Bad remote addr: %v", ra)
130
la := conn.LocalAddr().String()
131
if !strings.HasPrefix(la, "http://") {
132
t.Errorf("Bad local addr: %v", la)
137
func TestCount(t *testing.T) {
141
client, err := net.Dial("tcp", serverAddr)
143
t.Fatal("dialing", err)
145
conn, err := NewClient(newConfig(t, "/count"), client)
147
t.Errorf("WebSocket handshake error: %v", err)
153
if err := JSON.Send(conn, count); err != nil {
154
t.Errorf("Write: %v", err)
156
if err := JSON.Receive(conn, &count); err != nil {
157
t.Errorf("Read: %v", err)
160
t.Errorf("count: expected %d got %d", 1, count.N)
162
if count.S != "hello" {
163
t.Errorf("count: expected %q got %q", "hello", count.S)
165
if err := JSON.Send(conn, count); err != nil {
166
t.Errorf("Write: %v", err)
168
if err := JSON.Receive(conn, &count); err != nil {
169
t.Errorf("Read: %v", err)
172
t.Errorf("count: expected %d got %d", 2, count.N)
174
if count.S != "hellohello" {
175
t.Errorf("count: expected %q got %q", "hellohello", count.S)
180
func TestWithQuery(t *testing.T) {
183
client, err := net.Dial("tcp", serverAddr)
185
t.Fatal("dialing", err)
188
config := newConfig(t, "/echo")
189
config.Location, err = url.ParseRequestURI(fmt.Sprintf("ws://%s/echo?q=v", serverAddr))
191
t.Fatal("location url", err)
194
ws, err := NewClient(config, client)
196
t.Errorf("WebSocket handshake: %v", err)
202
func testWithProtocol(t *testing.T, subproto []string) (string, error) {
205
client, err := net.Dial("tcp", serverAddr)
207
t.Fatal("dialing", err)
210
config := newConfig(t, "/subproto")
211
config.Protocol = subproto
213
ws, err := NewClient(config, client)
217
msg := make([]byte, 16)
218
n, err := ws.Read(msg)
223
return string(msg[:n]), nil
226
func TestWithProtocol(t *testing.T) {
227
proto, err := testWithProtocol(t, []string{"chat"})
229
t.Errorf("SubProto: unexpected error: %v", err)
232
t.Errorf("SubProto: expected %q, got %q", "chat", proto)
236
func TestWithTwoProtocol(t *testing.T) {
237
proto, err := testWithProtocol(t, []string{"test", "chat"})
239
t.Errorf("SubProto: unexpected error: %v", err)
242
t.Errorf("SubProto: expected %q, got %q", "chat", proto)
246
func TestWithBadProtocol(t *testing.T) {
247
_, err := testWithProtocol(t, []string{"test"})
248
if err != ErrBadStatus {
249
t.Errorf("SubProto: expected %v, got %v", ErrBadStatus, err)
253
func TestHTTP(t *testing.T) {
256
// If the client did not send a handshake that matches the protocol
257
// specification, the server MUST return an HTTP response with an
258
// appropriate error code (such as 400 Bad Request)
259
resp, err := http.Get(fmt.Sprintf("http://%s/echo", serverAddr))
261
t.Errorf("Get: error %#v", err)
265
t.Error("Get: resp is null")
268
if resp.StatusCode != http.StatusBadRequest {
269
t.Errorf("Get: expected %q got %q", http.StatusBadRequest, resp.StatusCode)
273
func TestTrailingSpaces(t *testing.T) {
274
// http://code.google.com/p/go/issues/detail?id=955
275
// The last runs of this create keys with trailing spaces that should not be
276
// generated by the client.
278
config := newConfig(t, "/echo")
279
for i := 0; i < 30; i++ {
281
ws, err := DialConfig(config)
283
t.Errorf("Dial #%d failed: %v", i, err)
290
func TestDialConfigBadVersion(t *testing.T) {
292
config := newConfig(t, "/echo")
293
config.Version = 1234
295
_, err := DialConfig(config)
297
if dialerr, ok := err.(*DialError); ok {
298
if dialerr.Err != ErrBadProtocolVersion {
299
t.Errorf("dial expected err %q but got %q", ErrBadProtocolVersion, dialerr.Err)
304
func TestSmallBuffer(t *testing.T) {
305
// http://code.google.com/p/go/issues/detail?id=1145
306
// Read should be able to handle reading a fragment of a frame.
310
client, err := net.Dial("tcp", serverAddr)
312
t.Fatal("dialing", err)
314
conn, err := NewClient(newConfig(t, "/echo"), client)
316
t.Errorf("WebSocket handshake error: %v", err)
320
msg := []byte("hello, world\n")
321
if _, err := conn.Write(msg); err != nil {
322
t.Errorf("Write: %v", err)
324
var small_msg = make([]byte, 8)
325
n, err := conn.Read(small_msg)
327
t.Errorf("Read: %v", err)
329
if !bytes.Equal(msg[:len(small_msg)], small_msg) {
330
t.Errorf("Echo: expected %q got %q", msg[:len(small_msg)], small_msg)
332
var second_msg = make([]byte, len(msg))
333
n, err = conn.Read(second_msg)
335
t.Errorf("Read: %v", err)
337
second_msg = second_msg[0:n]
338
if !bytes.Equal(msg[len(small_msg):], second_msg) {
339
t.Errorf("Echo: expected %q got %q", msg[len(small_msg):], second_msg)
344
var parseAuthorityTests = []struct {
351
Host: "www.google.com",
358
Host: "www.google.com",
360
"www.google.com:443",
365
Host: "www.google.com:80",
372
Host: "www.google.com:443",
374
"www.google.com:443",
376
// some invalid ones for parseAuthority. parseAuthority doesn't
377
// concern itself with the scheme unless it actually knows about it
381
Host: "www.google.com",
388
Host: "www.google.com:80",
402
Host: "www.google.com",
408
func TestParseAuthority(t *testing.T) {
409
for _, tt := range parseAuthorityTests {
410
out := parseAuthority(tt.in)
412
t.Errorf("got %v; want %v", out, tt.out)
417
type closerConn struct {
419
closed int // count of the number of times Close was called
422
func (c *closerConn) Close() error {
424
return c.Conn.Close()
427
func TestClose(t *testing.T) {
430
conn, err := net.Dial("tcp", serverAddr)
432
t.Fatal("dialing", err)
435
cc := closerConn{Conn: conn}
437
client, err := NewClient(newConfig(t, "/echo"), &cc)
439
t.Fatalf("WebSocket handshake: %v", err)
442
// set the deadline to ten minutes ago, which will have expired by the time
443
// client.Close sends the close status frame.
444
conn.SetDeadline(time.Now().Add(-10 * time.Minute))
446
if err := client.Close(); err == nil {
447
t.Errorf("ws.Close(): expected error, got %v", err)
450
t.Fatalf("ws.Close(): expected underlying ws.rwc.Close to be called > 0 times, got: %v", cc.closed)