github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/websocket/websocket.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 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 an alternative
     9  // and more actively maintained WebSocket package:
    10  //
    11  //     https://godoc.org/github.com/gorilla/websocket
    12  //
    13  package websocket // import "github.com/Andyfoo/golang/x/net/websocket"
    14  
    15  import (
    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  
    29  const (
    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.
    46  type ProtocolError struct {
    47  	ErrorString string
    48  }
    49  
    50  func (err *ProtocolError) Error() string { return err.ErrorString }
    51  
    52  var (
    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
    71  var ErrFrameTooLarge = errors.New("websocket: frame payload size exceeds limit")
    72  
    73  // Addr is an implementation of net.Addr for WebSocket.
    74  type Addr struct {
    75  	*url.URL
    76  }
    77  
    78  // Network returns the network type for a WebSocket, "websocket".
    79  func (addr *Addr) Network() string { return "websocket" }
    80  
    81  // Config is a WebSocket configuration
    82  type 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.
   108  type 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.
   122  type 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.
   141  type frameReaderFactory interface {
   142  	NewFrameReader() (r frameReader, err error)
   143  }
   144  
   145  // frameWriter is an interface to write a WebSocket frame.
   146  type 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.
   152  type frameWriterFactory interface {
   153  	NewFrameWriter(payloadType byte) (w frameWriter, err error)
   154  }
   155  
   156  type 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.
   164  type 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.
   192  func (ws *Conn) Read(msg []byte) (n int, err error) {
   193  	ws.rio.Lock()
   194  	defer ws.rio.Unlock()
   195  again:
   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.
   222  func (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.
   235  func (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.
   245  func (ws *Conn) IsClientConn() bool { return ws.request == nil }
   246  
   247  // IsServerConn reports whether ws is a server-side connection.
   248  func (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.
   252  func (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.
   261  func (ws *Conn) RemoteAddr() net.Addr {
   262  	if ws.IsClientConn() {
   263  		return &Addr{ws.config.Location}
   264  	}
   265  	return &Addr{ws.config.Origin}
   266  }
   267  
   268  var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn")
   269  
   270  // SetDeadline sets the connection's network read & write deadlines.
   271  func (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.
   279  func (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.
   287  func (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.
   295  func (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.
   299  func (ws *Conn) Request() *http.Request { return ws.request }
   300  
   301  // Codec represents a symmetric pair of functions that implement a codec.
   302  type 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.
   308  func (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.
   330  func (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  	}
   340  again:
   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  
   373  func 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  
   383  func 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  /*
   396  Message is a codec to send/receive text/binary data in a frame on WebSocket connection.
   397  To send/receive text frame, use string type.
   398  To send/receive binary frame, use []byte type.
   399  
   400  Trivial 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  */
   421  var Message = Codec{marshal, unmarshal}
   422  
   423  func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) {
   424  	msg, err = json.Marshal(v)
   425  	return msg, TextFrame, err
   426  }
   427  
   428  func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
   429  	return json.Unmarshal(msg, v)
   430  }
   431  
   432  /*
   433  JSON is a codec to send/receive JSON data in a frame from a WebSocket connection.
   434  
   435  Trivial 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  */
   451  var JSON = Codec{jsonMarshal, jsonUnmarshal}