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 implements a client and server for the WebSocket protocol
6// as specified in RFC 6455.
7//
8// This package currently lacks some features found in alternative
9// and more actively maintained WebSocket packages:
10//
11//     https://godoc.org/github.com/gorilla/websocket
12//     https://godoc.org/nhooyr.io/websocket
13package websocket // import "golang.org/x/net/websocket"
14
15import (
16	"bufio"
17	"crypto/tls"
18	"encoding/json"
19	"errors"
20	"io"
21	"io/ioutil"
22	"net"
23	"net/http"
24	"net/url"
25	"sync"
26	"time"
27)
28
29const (
30	ProtocolVersionHybi13    = 13
31	ProtocolVersionHybi      = ProtocolVersionHybi13
32	SupportedProtocolVersion = "13"
33
34	ContinuationFrame = 0
35	TextFrame         = 1
36	BinaryFrame       = 2
37	CloseFrame        = 8
38	PingFrame         = 9
39	PongFrame         = 10
40	UnknownFrame      = 255
41
42	DefaultMaxPayloadBytes = 32 << 20 // 32MB
43)
44
45// ProtocolError represents WebSocket protocol errors.
46type ProtocolError struct {
47	ErrorString string
48}
49
50func (err *ProtocolError) Error() string { return err.ErrorString }
51
52var (
53	ErrBadProtocolVersion   = &ProtocolError{"bad protocol version"}
54	ErrBadScheme            = &ProtocolError{"bad scheme"}
55	ErrBadStatus            = &ProtocolError{"bad status"}
56	ErrBadUpgrade           = &ProtocolError{"missing or bad upgrade"}
57	ErrBadWebSocketOrigin   = &ProtocolError{"missing or bad WebSocket-Origin"}
58	ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"}
59	ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"}
60	ErrBadWebSocketVersion  = &ProtocolError{"missing or bad WebSocket Version"}
61	ErrChallengeResponse    = &ProtocolError{"mismatch challenge/response"}
62	ErrBadFrame             = &ProtocolError{"bad frame"}
63	ErrBadFrameBoundary     = &ProtocolError{"not on frame boundary"}
64	ErrNotWebSocket         = &ProtocolError{"not websocket protocol"}
65	ErrBadRequestMethod     = &ProtocolError{"bad method"}
66	ErrNotSupported         = &ProtocolError{"not supported"}
67)
68
69// ErrFrameTooLarge is returned by Codec's Receive method if payload size
70// exceeds limit set by Conn.MaxPayloadBytes
71var ErrFrameTooLarge = errors.New("websocket: frame payload size exceeds limit")
72
73// Addr is an implementation of net.Addr for WebSocket.
74type Addr struct {
75	*url.URL
76}
77
78// Network returns the network type for a WebSocket, "websocket".
79func (addr *Addr) Network() string { return "websocket" }
80
81// Config is a WebSocket configuration
82type Config struct {
83	// A WebSocket server address.
84	Location *url.URL
85
86	// A Websocket client origin.
87	Origin *url.URL
88
89	// WebSocket subprotocols.
90	Protocol []string
91
92	// WebSocket protocol version.
93	Version int
94
95	// TLS config for secure WebSocket (wss).
96	TlsConfig *tls.Config
97
98	// Additional header fields to be sent in WebSocket opening handshake.
99	Header http.Header
100
101	// Dialer used when opening websocket connections.
102	Dialer *net.Dialer
103
104	handshakeData map[string]string
105}
106
107// serverHandshaker is an interface to handle WebSocket server side handshake.
108type serverHandshaker interface {
109	// ReadHandshake reads handshake request message from client.
110	// Returns http response code and error if any.
111	ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error)
112
113	// AcceptHandshake accepts the client handshake request and sends
114	// handshake response back to client.
115	AcceptHandshake(buf *bufio.Writer) (err error)
116
117	// NewServerConn creates a new WebSocket connection.
118	NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn)
119}
120
121// frameReader is an interface to read a WebSocket frame.
122type frameReader interface {
123	// Reader is to read payload of the frame.
124	io.Reader
125
126	// PayloadType returns payload type.
127	PayloadType() byte
128
129	// HeaderReader returns a reader to read header of the frame.
130	HeaderReader() io.Reader
131
132	// TrailerReader returns a reader to read trailer of the frame.
133	// If it returns nil, there is no trailer in the frame.
134	TrailerReader() io.Reader
135
136	// Len returns total length of the frame, including header and trailer.
137	Len() int
138}
139
140// frameReaderFactory is an interface to creates new frame reader.
141type frameReaderFactory interface {
142	NewFrameReader() (r frameReader, err error)
143}
144
145// frameWriter is an interface to write a WebSocket frame.
146type frameWriter interface {
147	// Writer is to write payload of the frame.
148	io.WriteCloser
149}
150
151// frameWriterFactory is an interface to create new frame writer.
152type frameWriterFactory interface {
153	NewFrameWriter(payloadType byte) (w frameWriter, err error)
154}
155
156type frameHandler interface {
157	HandleFrame(frame frameReader) (r frameReader, err error)
158	WriteClose(status int) (err error)
159}
160
161// Conn represents a WebSocket connection.
162//
163// Multiple goroutines may invoke methods on a Conn simultaneously.
164type Conn struct {
165	config  *Config
166	request *http.Request
167
168	buf *bufio.ReadWriter
169	rwc io.ReadWriteCloser
170
171	rio sync.Mutex
172	frameReaderFactory
173	frameReader
174
175	wio sync.Mutex
176	frameWriterFactory
177
178	frameHandler
179	PayloadType        byte
180	defaultCloseStatus int
181
182	// MaxPayloadBytes limits the size of frame payload received over Conn
183	// by Codec's Receive method. If zero, DefaultMaxPayloadBytes is used.
184	MaxPayloadBytes int
185}
186
187// Read implements the io.Reader interface:
188// it reads data of a frame from the WebSocket connection.
189// if msg is not large enough for the frame data, it fills the msg and next Read
190// will read the rest of the frame data.
191// it reads Text frame or Binary frame.
192func (ws *Conn) Read(msg []byte) (n int, err error) {
193	ws.rio.Lock()
194	defer ws.rio.Unlock()
195again:
196	if ws.frameReader == nil {
197		frame, err := ws.frameReaderFactory.NewFrameReader()
198		if err != nil {
199			return 0, err
200		}
201		ws.frameReader, err = ws.frameHandler.HandleFrame(frame)
202		if err != nil {
203			return 0, err
204		}
205		if ws.frameReader == nil {
206			goto again
207		}
208	}
209	n, err = ws.frameReader.Read(msg)
210	if err == io.EOF {
211		if trailer := ws.frameReader.TrailerReader(); trailer != nil {
212			io.Copy(ioutil.Discard, trailer)
213		}
214		ws.frameReader = nil
215		goto again
216	}
217	return n, err
218}
219
220// Write implements the io.Writer interface:
221// it writes data as a frame to the WebSocket connection.
222func (ws *Conn) Write(msg []byte) (n int, err error) {
223	ws.wio.Lock()
224	defer ws.wio.Unlock()
225	w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType)
226	if err != nil {
227		return 0, err
228	}
229	n, err = w.Write(msg)
230	w.Close()
231	return n, err
232}
233
234// Close implements the io.Closer interface.
235func (ws *Conn) Close() error {
236	err := ws.frameHandler.WriteClose(ws.defaultCloseStatus)
237	err1 := ws.rwc.Close()
238	if err != nil {
239		return err
240	}
241	return err1
242}
243
244// IsClientConn reports whether ws is a client-side connection.
245func (ws *Conn) IsClientConn() bool { return ws.request == nil }
246
247// IsServerConn reports whether ws is a server-side connection.
248func (ws *Conn) IsServerConn() bool { return ws.request != nil }
249
250// LocalAddr returns the WebSocket Origin for the connection for client, or
251// the WebSocket location for server.
252func (ws *Conn) LocalAddr() net.Addr {
253	if ws.IsClientConn() {
254		return &Addr{ws.config.Origin}
255	}
256	return &Addr{ws.config.Location}
257}
258
259// RemoteAddr returns the WebSocket location for the connection for client, or
260// the Websocket Origin for server.
261func (ws *Conn) RemoteAddr() net.Addr {
262	if ws.IsClientConn() {
263		return &Addr{ws.config.Location}
264	}
265	return &Addr{ws.config.Origin}
266}
267
268var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn")
269
270// SetDeadline sets the connection's network read & write deadlines.
271func (ws *Conn) SetDeadline(t time.Time) error {
272	if conn, ok := ws.rwc.(net.Conn); ok {
273		return conn.SetDeadline(t)
274	}
275	return errSetDeadline
276}
277
278// SetReadDeadline sets the connection's network read deadline.
279func (ws *Conn) SetReadDeadline(t time.Time) error {
280	if conn, ok := ws.rwc.(net.Conn); ok {
281		return conn.SetReadDeadline(t)
282	}
283	return errSetDeadline
284}
285
286// SetWriteDeadline sets the connection's network write deadline.
287func (ws *Conn) SetWriteDeadline(t time.Time) error {
288	if conn, ok := ws.rwc.(net.Conn); ok {
289		return conn.SetWriteDeadline(t)
290	}
291	return errSetDeadline
292}
293
294// Config returns the WebSocket config.
295func (ws *Conn) Config() *Config { return ws.config }
296
297// Request returns the http request upgraded to the WebSocket.
298// It is nil for client side.
299func (ws *Conn) Request() *http.Request { return ws.request }
300
301// Codec represents a symmetric pair of functions that implement a codec.
302type Codec struct {
303	Marshal   func(v interface{}) (data []byte, payloadType byte, err error)
304	Unmarshal func(data []byte, payloadType byte, v interface{}) (err error)
305}
306
307// Send sends v marshaled by cd.Marshal as single frame to ws.
308func (cd Codec) Send(ws *Conn, v interface{}) (err error) {
309	data, payloadType, err := cd.Marshal(v)
310	if err != nil {
311		return err
312	}
313	ws.wio.Lock()
314	defer ws.wio.Unlock()
315	w, err := ws.frameWriterFactory.NewFrameWriter(payloadType)
316	if err != nil {
317		return err
318	}
319	_, err = w.Write(data)
320	w.Close()
321	return err
322}
323
324// Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores
325// in v. The whole frame payload is read to an in-memory buffer; max size of
326// payload is defined by ws.MaxPayloadBytes. If frame payload size exceeds
327// limit, ErrFrameTooLarge is returned; in this case frame is not read off wire
328// completely. The next call to Receive would read and discard leftover data of
329// previous oversized frame before processing next frame.
330func (cd Codec) Receive(ws *Conn, v interface{}) (err error) {
331	ws.rio.Lock()
332	defer ws.rio.Unlock()
333	if ws.frameReader != nil {
334		_, err = io.Copy(ioutil.Discard, ws.frameReader)
335		if err != nil {
336			return err
337		}
338		ws.frameReader = nil
339	}
340again:
341	frame, err := ws.frameReaderFactory.NewFrameReader()
342	if err != nil {
343		return err
344	}
345	frame, err = ws.frameHandler.HandleFrame(frame)
346	if err != nil {
347		return err
348	}
349	if frame == nil {
350		goto again
351	}
352	maxPayloadBytes := ws.MaxPayloadBytes
353	if maxPayloadBytes == 0 {
354		maxPayloadBytes = DefaultMaxPayloadBytes
355	}
356	if hf, ok := frame.(*hybiFrameReader); ok && hf.header.Length > int64(maxPayloadBytes) {
357		// payload size exceeds limit, no need to call Unmarshal
358		//
359		// set frameReader to current oversized frame so that
360		// the next call to this function can drain leftover
361		// data before processing the next frame
362		ws.frameReader = frame
363		return ErrFrameTooLarge
364	}
365	payloadType := frame.PayloadType()
366	data, err := ioutil.ReadAll(frame)
367	if err != nil {
368		return err
369	}
370	return cd.Unmarshal(data, payloadType, v)
371}
372
373func marshal(v interface{}) (msg []byte, payloadType byte, err error) {
374	switch data := v.(type) {
375	case string:
376		return []byte(data), TextFrame, nil
377	case []byte:
378		return data, BinaryFrame, nil
379	}
380	return nil, UnknownFrame, ErrNotSupported
381}
382
383func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
384	switch data := v.(type) {
385	case *string:
386		*data = string(msg)
387		return nil
388	case *[]byte:
389		*data = msg
390		return nil
391	}
392	return ErrNotSupported
393}
394
395/*
396Message is a codec to send/receive text/binary data in a frame on WebSocket connection.
397To send/receive text frame, use string type.
398To send/receive binary frame, use []byte type.
399
400Trivial usage:
401
402	import "websocket"
403
404	// receive text frame
405	var message string
406	websocket.Message.Receive(ws, &message)
407
408	// send text frame
409	message = "hello"
410	websocket.Message.Send(ws, message)
411
412	// receive binary frame
413	var data []byte
414	websocket.Message.Receive(ws, &data)
415
416	// send binary frame
417	data = []byte{0, 1, 2}
418	websocket.Message.Send(ws, data)
419
420*/
421var Message = Codec{marshal, unmarshal}
422
423func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) {
424	msg, err = json.Marshal(v)
425	return msg, TextFrame, err
426}
427
428func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
429	return json.Unmarshal(msg, v)
430}
431
432/*
433JSON is a codec to send/receive JSON data in a frame from a WebSocket connection.
434
435Trivial usage:
436
437	import "websocket"
438
439	type T struct {
440		Msg string
441		Count int
442	}
443
444	// receive JSON type T
445	var data T
446	websocket.JSON.Receive(ws, &data)
447
448	// send JSON type T
449	websocket.JSON.Send(ws, data)
450*/
451var JSON = Codec{jsonMarshal, jsonUnmarshal}
452