github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/websocket/hybi.go (about)

     1  // Copyright 2011 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
     6  
     7  // This file implements a protocol of hybi draft.
     8  // http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
     9  
    10  import (
    11  	"bufio"
    12  	"bytes"
    13  	"crypto/rand"
    14  	"crypto/sha1"
    15  	"encoding/base64"
    16  	"encoding/binary"
    17  	"fmt"
    18  	"io"
    19  	"io/ioutil"
    20  	"net/http"
    21  	"net/url"
    22  	"strings"
    23  )
    24  
    25  const (
    26  	websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
    27  
    28  	closeStatusNormal            = 1000
    29  	closeStatusGoingAway         = 1001
    30  	closeStatusProtocolError     = 1002
    31  	closeStatusUnsupportedData   = 1003
    32  	closeStatusFrameTooLarge     = 1004
    33  	closeStatusNoStatusRcvd      = 1005
    34  	closeStatusAbnormalClosure   = 1006
    35  	closeStatusBadMessageData    = 1007
    36  	closeStatusPolicyViolation   = 1008
    37  	closeStatusTooBigData        = 1009
    38  	closeStatusExtensionMismatch = 1010
    39  
    40  	maxControlFramePayloadLength = 125
    41  )
    42  
    43  var (
    44  	ErrBadMaskingKey         = &ProtocolError{"bad masking key"}
    45  	ErrBadPongMessage        = &ProtocolError{"bad pong message"}
    46  	ErrBadClosingStatus      = &ProtocolError{"bad closing status"}
    47  	ErrUnsupportedExtensions = &ProtocolError{"unsupported extensions"}
    48  	ErrNotImplemented        = &ProtocolError{"not implemented"}
    49  
    50  	handshakeHeader = map[string]bool{
    51  		"Host":                   true,
    52  		"Upgrade":                true,
    53  		"Connection":             true,
    54  		"Sec-Websocket-Key":      true,
    55  		"Sec-Websocket-Origin":   true,
    56  		"Sec-Websocket-Version":  true,
    57  		"Sec-Websocket-Protocol": true,
    58  		"Sec-Websocket-Accept":   true,
    59  	}
    60  )
    61  
    62  // A hybiFrameHeader is a frame header as defined in hybi draft.
    63  type hybiFrameHeader struct {
    64  	Fin        bool
    65  	Rsv        [3]bool
    66  	OpCode     byte
    67  	Length     int64
    68  	MaskingKey []byte
    69  
    70  	data *bytes.Buffer
    71  }
    72  
    73  // A hybiFrameReader is a reader for hybi frame.
    74  type hybiFrameReader struct {
    75  	reader io.Reader
    76  
    77  	header hybiFrameHeader
    78  	pos    int64
    79  	length int
    80  }
    81  
    82  func (frame *hybiFrameReader) Read(msg []byte) (n int, err error) {
    83  	n, err = frame.reader.Read(msg)
    84  	if err != nil {
    85  		return 0, err
    86  	}
    87  	if frame.header.MaskingKey != nil {
    88  		for i := 0; i < n; i++ {
    89  			msg[i] = msg[i] ^ frame.header.MaskingKey[frame.pos%4]
    90  			frame.pos++
    91  		}
    92  	}
    93  	return n, err
    94  }
    95  
    96  func (frame *hybiFrameReader) PayloadType() byte { return frame.header.OpCode }
    97  
    98  func (frame *hybiFrameReader) HeaderReader() io.Reader {
    99  	if frame.header.data == nil {
   100  		return nil
   101  	}
   102  	if frame.header.data.Len() == 0 {
   103  		return nil
   104  	}
   105  	return frame.header.data
   106  }
   107  
   108  func (frame *hybiFrameReader) TrailerReader() io.Reader { return nil }
   109  
   110  func (frame *hybiFrameReader) Len() (n int) { return frame.length }
   111  
   112  // A hybiFrameReaderFactory creates new frame reader based on its frame type.
   113  type hybiFrameReaderFactory struct {
   114  	*bufio.Reader
   115  }
   116  
   117  // NewFrameReader reads a frame header from the connection, and creates new reader for the frame.
   118  // See Section 5.2 Base Framing protocol for detail.
   119  // http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2
   120  func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) {
   121  	hybiFrame := new(hybiFrameReader)
   122  	frame = hybiFrame
   123  	var header []byte
   124  	var b byte
   125  	// First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits)
   126  	b, err = buf.ReadByte()
   127  	if err != nil {
   128  		return
   129  	}
   130  	header = append(header, b)
   131  	hybiFrame.header.Fin = ((header[0] >> 7) & 1) != 0
   132  	for i := 0; i < 3; i++ {
   133  		j := uint(6 - i)
   134  		hybiFrame.header.Rsv[i] = ((header[0] >> j) & 1) != 0
   135  	}
   136  	hybiFrame.header.OpCode = header[0] & 0x0f
   137  
   138  	// Second byte. Mask/Payload len(7bits)
   139  	b, err = buf.ReadByte()
   140  	if err != nil {
   141  		return
   142  	}
   143  	header = append(header, b)
   144  	mask := (b & 0x80) != 0
   145  	b &= 0x7f
   146  	lengthFields := 0
   147  	switch {
   148  	case b <= 125: // Payload length 7bits.
   149  		hybiFrame.header.Length = int64(b)
   150  	case b == 126: // Payload length 7+16bits
   151  		lengthFields = 2
   152  	case b == 127: // Payload length 7+64bits
   153  		lengthFields = 8
   154  	}
   155  	for i := 0; i < lengthFields; i++ {
   156  		b, err = buf.ReadByte()
   157  		if err != nil {
   158  			return
   159  		}
   160  		if lengthFields == 8 && i == 0 { // MSB must be zero when 7+64 bits
   161  			b &= 0x7f
   162  		}
   163  		header = append(header, b)
   164  		hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b)
   165  	}
   166  	if mask {
   167  		// Masking key. 4 bytes.
   168  		for i := 0; i < 4; i++ {
   169  			b, err = buf.ReadByte()
   170  			if err != nil {
   171  				return
   172  			}
   173  			header = append(header, b)
   174  			hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b)
   175  		}
   176  	}
   177  	hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length)
   178  	hybiFrame.header.data = bytes.NewBuffer(header)
   179  	hybiFrame.length = len(header) + int(hybiFrame.header.Length)
   180  	return
   181  }
   182  
   183  // A HybiFrameWriter is a writer for hybi frame.
   184  type hybiFrameWriter struct {
   185  	writer *bufio.Writer
   186  
   187  	header *hybiFrameHeader
   188  }
   189  
   190  func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) {
   191  	var header []byte
   192  	var b byte
   193  	if frame.header.Fin {
   194  		b |= 0x80
   195  	}
   196  	for i := 0; i < 3; i++ {
   197  		if frame.header.Rsv[i] {
   198  			j := uint(6 - i)
   199  			b |= 1 << j
   200  		}
   201  	}
   202  	b |= frame.header.OpCode
   203  	header = append(header, b)
   204  	if frame.header.MaskingKey != nil {
   205  		b = 0x80
   206  	} else {
   207  		b = 0
   208  	}
   209  	lengthFields := 0
   210  	length := len(msg)
   211  	switch {
   212  	case length <= 125:
   213  		b |= byte(length)
   214  	case length < 65536:
   215  		b |= 126
   216  		lengthFields = 2
   217  	default:
   218  		b |= 127
   219  		lengthFields = 8
   220  	}
   221  	header = append(header, b)
   222  	for i := 0; i < lengthFields; i++ {
   223  		j := uint((lengthFields - i - 1) * 8)
   224  		b = byte((length >> j) & 0xff)
   225  		header = append(header, b)
   226  	}
   227  	if frame.header.MaskingKey != nil {
   228  		if len(frame.header.MaskingKey) != 4 {
   229  			return 0, ErrBadMaskingKey
   230  		}
   231  		header = append(header, frame.header.MaskingKey...)
   232  		frame.writer.Write(header)
   233  		data := make([]byte, length)
   234  		for i := range data {
   235  			data[i] = msg[i] ^ frame.header.MaskingKey[i%4]
   236  		}
   237  		frame.writer.Write(data)
   238  		err = frame.writer.Flush()
   239  		return length, err
   240  	}
   241  	frame.writer.Write(header)
   242  	frame.writer.Write(msg)
   243  	err = frame.writer.Flush()
   244  	return length, err
   245  }
   246  
   247  func (frame *hybiFrameWriter) Close() error { return nil }
   248  
   249  type hybiFrameWriterFactory struct {
   250  	*bufio.Writer
   251  	needMaskingKey bool
   252  }
   253  
   254  func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) {
   255  	frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType}
   256  	if buf.needMaskingKey {
   257  		frameHeader.MaskingKey, err = generateMaskingKey()
   258  		if err != nil {
   259  			return nil, err
   260  		}
   261  	}
   262  	return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil
   263  }
   264  
   265  type hybiFrameHandler struct {
   266  	conn        *Conn
   267  	payloadType byte
   268  }
   269  
   270  func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (frameReader, error) {
   271  	if handler.conn.IsServerConn() {
   272  		// The client MUST mask all frames sent to the server.
   273  		if frame.(*hybiFrameReader).header.MaskingKey == nil {
   274  			handler.WriteClose(closeStatusProtocolError)
   275  			return nil, io.EOF
   276  		}
   277  	} else {
   278  		// The server MUST NOT mask all frames.
   279  		if frame.(*hybiFrameReader).header.MaskingKey != nil {
   280  			handler.WriteClose(closeStatusProtocolError)
   281  			return nil, io.EOF
   282  		}
   283  	}
   284  	if header := frame.HeaderReader(); header != nil {
   285  		io.Copy(ioutil.Discard, header)
   286  	}
   287  	switch frame.PayloadType() {
   288  	case ContinuationFrame:
   289  		frame.(*hybiFrameReader).header.OpCode = handler.payloadType
   290  	case TextFrame, BinaryFrame:
   291  		handler.payloadType = frame.PayloadType()
   292  	case CloseFrame:
   293  		return nil, io.EOF
   294  	case PingFrame, PongFrame:
   295  		b := make([]byte, maxControlFramePayloadLength)
   296  		n, err := io.ReadFull(frame, b)
   297  		if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
   298  			return nil, err
   299  		}
   300  		io.Copy(ioutil.Discard, frame)
   301  		if frame.PayloadType() == PingFrame {
   302  			if _, err := handler.WritePong(b[:n]); err != nil {
   303  				return nil, err
   304  			}
   305  		}
   306  		return nil, nil
   307  	}
   308  	return frame, nil
   309  }
   310  
   311  func (handler *hybiFrameHandler) WriteClose(status int) (err error) {
   312  	handler.conn.wio.Lock()
   313  	defer handler.conn.wio.Unlock()
   314  	w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame)
   315  	if err != nil {
   316  		return err
   317  	}
   318  	msg := make([]byte, 2)
   319  	binary.BigEndian.PutUint16(msg, uint16(status))
   320  	_, err = w.Write(msg)
   321  	w.Close()
   322  	return err
   323  }
   324  
   325  func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) {
   326  	handler.conn.wio.Lock()
   327  	defer handler.conn.wio.Unlock()
   328  	w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame)
   329  	if err != nil {
   330  		return 0, err
   331  	}
   332  	n, err = w.Write(msg)
   333  	w.Close()
   334  	return n, err
   335  }
   336  
   337  // newHybiConn creates a new WebSocket connection speaking hybi draft protocol.
   338  func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
   339  	if buf == nil {
   340  		br := bufio.NewReader(rwc)
   341  		bw := bufio.NewWriter(rwc)
   342  		buf = bufio.NewReadWriter(br, bw)
   343  	}
   344  	ws := &Conn{config: config, request: request, buf: buf, rwc: rwc,
   345  		frameReaderFactory: hybiFrameReaderFactory{buf.Reader},
   346  		frameWriterFactory: hybiFrameWriterFactory{
   347  			buf.Writer, request == nil},
   348  		PayloadType:        TextFrame,
   349  		defaultCloseStatus: closeStatusNormal}
   350  	ws.frameHandler = &hybiFrameHandler{conn: ws}
   351  	return ws
   352  }
   353  
   354  // generateMaskingKey generates a masking key for a frame.
   355  func generateMaskingKey() (maskingKey []byte, err error) {
   356  	maskingKey = make([]byte, 4)
   357  	if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil {
   358  		return
   359  	}
   360  	return
   361  }
   362  
   363  // generateNonce generates a nonce consisting of a randomly selected 16-byte
   364  // value that has been base64-encoded.
   365  func generateNonce() (nonce []byte) {
   366  	key := make([]byte, 16)
   367  	if _, err := io.ReadFull(rand.Reader, key); err != nil {
   368  		panic(err)
   369  	}
   370  	nonce = make([]byte, 24)
   371  	base64.StdEncoding.Encode(nonce, key)
   372  	return
   373  }
   374  
   375  // removeZone removes IPv6 zone identifer from host.
   376  // E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
   377  func removeZone(host string) string {
   378  	if !strings.HasPrefix(host, "[") {
   379  		return host
   380  	}
   381  	i := strings.LastIndex(host, "]")
   382  	if i < 0 {
   383  		return host
   384  	}
   385  	j := strings.LastIndex(host[:i], "%")
   386  	if j < 0 {
   387  		return host
   388  	}
   389  	return host[:j] + host[i:]
   390  }
   391  
   392  // getNonceAccept computes the base64-encoded SHA-1 of the concatenation of
   393  // the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string.
   394  func getNonceAccept(nonce []byte) (expected []byte, err error) {
   395  	h := sha1.New()
   396  	if _, err = h.Write(nonce); err != nil {
   397  		return
   398  	}
   399  	if _, err = h.Write([]byte(websocketGUID)); err != nil {
   400  		return
   401  	}
   402  	expected = make([]byte, 28)
   403  	base64.StdEncoding.Encode(expected, h.Sum(nil))
   404  	return
   405  }
   406  
   407  // Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17
   408  func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
   409  	bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
   410  
   411  	// According to RFC 6874, an HTTP client, proxy, or other
   412  	// intermediary must remove any IPv6 zone identifier attached
   413  	// to an outgoing URI.
   414  	bw.WriteString("Host: " + removeZone(config.Location.Host) + "\r\n")
   415  	bw.WriteString("Upgrade: websocket\r\n")
   416  	bw.WriteString("Connection: Upgrade\r\n")
   417  	nonce := generateNonce()
   418  	if config.handshakeData != nil {
   419  		nonce = []byte(config.handshakeData["key"])
   420  	}
   421  	bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n")
   422  	bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n")
   423  
   424  	if config.Version != ProtocolVersionHybi13 {
   425  		return ErrBadProtocolVersion
   426  	}
   427  
   428  	bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n")
   429  	if len(config.Protocol) > 0 {
   430  		bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n")
   431  	}
   432  	// TODO(ukai): send Sec-WebSocket-Extensions.
   433  	err = config.Header.WriteSubset(bw, handshakeHeader)
   434  	if err != nil {
   435  		return err
   436  	}
   437  
   438  	bw.WriteString("\r\n")
   439  	if err = bw.Flush(); err != nil {
   440  		return err
   441  	}
   442  
   443  	resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
   444  	if err != nil {
   445  		return err
   446  	}
   447  	if resp.StatusCode != 101 {
   448  		return ErrBadStatus
   449  	}
   450  	if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" ||
   451  		strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
   452  		return ErrBadUpgrade
   453  	}
   454  	expectedAccept, err := getNonceAccept(nonce)
   455  	if err != nil {
   456  		return err
   457  	}
   458  	if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) {
   459  		return ErrChallengeResponse
   460  	}
   461  	if resp.Header.Get("Sec-WebSocket-Extensions") != "" {
   462  		return ErrUnsupportedExtensions
   463  	}
   464  	offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol")
   465  	if offeredProtocol != "" {
   466  		protocolMatched := false
   467  		for i := 0; i < len(config.Protocol); i++ {
   468  			if config.Protocol[i] == offeredProtocol {
   469  				protocolMatched = true
   470  				break
   471  			}
   472  		}
   473  		if !protocolMatched {
   474  			return ErrBadWebSocketProtocol
   475  		}
   476  		config.Protocol = []string{offeredProtocol}
   477  	}
   478  
   479  	return nil
   480  }
   481  
   482  // newHybiClientConn creates a client WebSocket connection after handshake.
   483  func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
   484  	return newHybiConn(config, buf, rwc, nil)
   485  }
   486  
   487  // A HybiServerHandshaker performs a server handshake using hybi draft protocol.
   488  type hybiServerHandshaker struct {
   489  	*Config
   490  	accept []byte
   491  }
   492  
   493  func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) {
   494  	c.Version = ProtocolVersionHybi13
   495  	if req.Method != "GET" {
   496  		return http.StatusMethodNotAllowed, ErrBadRequestMethod
   497  	}
   498  	// HTTP version can be safely ignored.
   499  
   500  	if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
   501  		!strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") {
   502  		return http.StatusBadRequest, ErrNotWebSocket
   503  	}
   504  
   505  	key := req.Header.Get("Sec-Websocket-Key")
   506  	if key == "" {
   507  		return http.StatusBadRequest, ErrChallengeResponse
   508  	}
   509  	version := req.Header.Get("Sec-Websocket-Version")
   510  	switch version {
   511  	case "13":
   512  		c.Version = ProtocolVersionHybi13
   513  	default:
   514  		return http.StatusBadRequest, ErrBadWebSocketVersion
   515  	}
   516  	var scheme string
   517  	if req.TLS != nil {
   518  		scheme = "wss"
   519  	} else {
   520  		scheme = "ws"
   521  	}
   522  	c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI())
   523  	if err != nil {
   524  		return http.StatusBadRequest, err
   525  	}
   526  	protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
   527  	if protocol != "" {
   528  		protocols := strings.Split(protocol, ",")
   529  		for i := 0; i < len(protocols); i++ {
   530  			c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
   531  		}
   532  	}
   533  	c.accept, err = getNonceAccept([]byte(key))
   534  	if err != nil {
   535  		return http.StatusInternalServerError, err
   536  	}
   537  	return http.StatusSwitchingProtocols, nil
   538  }
   539  
   540  // Origin parses the Origin header in req.
   541  // If the Origin header is not set, it returns nil and nil.
   542  func Origin(config *Config, req *http.Request) (*url.URL, error) {
   543  	var origin string
   544  	switch config.Version {
   545  	case ProtocolVersionHybi13:
   546  		origin = req.Header.Get("Origin")
   547  	}
   548  	if origin == "" {
   549  		return nil, nil
   550  	}
   551  	return url.ParseRequestURI(origin)
   552  }
   553  
   554  func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
   555  	if len(c.Protocol) > 0 {
   556  		if len(c.Protocol) != 1 {
   557  			// You need choose a Protocol in Handshake func in Server.
   558  			return ErrBadWebSocketProtocol
   559  		}
   560  	}
   561  	buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n")
   562  	buf.WriteString("Upgrade: websocket\r\n")
   563  	buf.WriteString("Connection: Upgrade\r\n")
   564  	buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n")
   565  	if len(c.Protocol) > 0 {
   566  		buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n")
   567  	}
   568  	// TODO(ukai): send Sec-WebSocket-Extensions.
   569  	if c.Header != nil {
   570  		err := c.Header.WriteSubset(buf, handshakeHeader)
   571  		if err != nil {
   572  			return err
   573  		}
   574  	}
   575  	buf.WriteString("\r\n")
   576  	return buf.Flush()
   577  }
   578  
   579  func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
   580  	return newHybiServerConn(c.Config, buf, rwc, request)
   581  }
   582  
   583  // newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol.
   584  func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
   585  	return newHybiConn(config, buf, rwc, request)
   586  }