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