github.com/ezoic/ws@v1.0.4-0.20220713205711-5c1d69e074c5/wsutil/helper.go (about)

     1  package wsutil
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"io/ioutil"
     7  
     8  	"github.com/ezoic/ws"
     9  )
    10  
    11  // Message represents a message from peer, that could be presented in one or
    12  // more frames. That is, it contains payload of all message fragments and
    13  // operation code of initial frame for this message.
    14  type Message struct {
    15  	OpCode  ws.OpCode
    16  	Payload []byte
    17  }
    18  
    19  // ReadMessage is a helper function that reads next message from r. It appends
    20  // received message(s) to the third argument and returns the result of it and
    21  // an error if some failure happened. That is, it probably could receive more
    22  // than one message when peer sending fragmented message in multiple frames and
    23  // want to send some control frame between fragments. Then returned slice will
    24  // contain those control frames at first, and then result of gluing fragments.
    25  //
    26  // TODO(ezoic): add DefaultReader with buffer size options.
    27  func ReadMessage(r io.Reader, s ws.State, m []Message) ([]Message, error) {
    28  	rd := Reader{
    29  		Source:    r,
    30  		State:     s,
    31  		CheckUTF8: true,
    32  		OnIntermediate: func(hdr ws.Header, src io.Reader) error {
    33  			bts, err := ioutil.ReadAll(src)
    34  			if err != nil {
    35  				return err
    36  			}
    37  			m = append(m, Message{hdr.OpCode, bts})
    38  			return nil
    39  		},
    40  	}
    41  	h, err := rd.NextFrame()
    42  	if err != nil {
    43  		return m, err
    44  	}
    45  	var p []byte
    46  	if h.Fin {
    47  		// No more frames will be read. Use fixed sized buffer to read payload.
    48  		p = make([]byte, h.Length)
    49  		// It is not possible to receive io.EOF here because Reader does not
    50  		// return EOF if frame payload was successfully fetched.
    51  		// Thus we consistent here with io.Reader behavior.
    52  		_, err = io.ReadFull(&rd, p)
    53  	} else {
    54  		// Frame is fragmented, thus use ioutil.ReadAll behavior.
    55  		var buf bytes.Buffer
    56  		_, err = buf.ReadFrom(&rd)
    57  		p = buf.Bytes()
    58  	}
    59  	if err != nil {
    60  		return m, err
    61  	}
    62  	return append(m, Message{h.OpCode, p}), nil
    63  }
    64  
    65  // ReadClientMessage reads next message from r, considering that caller
    66  // represents server side.
    67  // It is a shortcut for ReadMessage(r, ws.StateServerSide, m)
    68  func ReadClientMessage(r io.Reader, m []Message) ([]Message, error) {
    69  	return ReadMessage(r, ws.StateServerSide, m)
    70  }
    71  
    72  // ReadServerMessage reads next message from r, considering that caller
    73  // represents client side.
    74  // It is a shortcut for ReadMessage(r, ws.StateClientSide, m)
    75  func ReadServerMessage(r io.Reader, m []Message) ([]Message, error) {
    76  	return ReadMessage(r, ws.StateClientSide, m)
    77  }
    78  
    79  // ReadData is a helper function that reads next data (non-control) message
    80  // from rw.
    81  // It takes care on handling all control frames. It will write response on
    82  // control frames to the write part of rw. It blocks until some data frame
    83  // will be received.
    84  //
    85  // Note this may handle and write control frames into the writer part of a
    86  // given io.ReadWriter.
    87  func ReadData(rw io.ReadWriter, s ws.State) ([]byte, ws.OpCode, error) {
    88  	return readData(rw, s, ws.OpText|ws.OpBinary)
    89  }
    90  
    91  // ReadClientData reads next data message from rw, considering that caller
    92  // represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
    93  //
    94  // Note this may handle and write control frames into the writer part of a
    95  // given io.ReadWriter.
    96  func ReadClientData(rw io.ReadWriter) ([]byte, ws.OpCode, error) {
    97  	return ReadData(rw, ws.StateServerSide)
    98  }
    99  
   100  // ReadClientText reads next text message from rw, considering that caller
   101  // represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
   102  // It discards received binary messages.
   103  //
   104  // Note this may handle and write control frames into the writer part of a
   105  // given io.ReadWriter.
   106  func ReadClientText(rw io.ReadWriter) ([]byte, error) {
   107  	p, _, err := readData(rw, ws.StateServerSide, ws.OpText)
   108  	return p, err
   109  }
   110  
   111  // ReadClientBinary reads next binary message from rw, considering that caller
   112  // represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
   113  // It discards received text messages.
   114  //
   115  // Note this may handle and write control frames into the writer part of a given
   116  //  io.ReadWriter.
   117  func ReadClientBinary(rw io.ReadWriter) ([]byte, error) {
   118  	p, _, err := readData(rw, ws.StateServerSide, ws.OpBinary)
   119  	return p, err
   120  }
   121  
   122  // ReadServerData reads next data message from rw, considering that caller
   123  // represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
   124  //
   125  // Note this may handle and write control frames into the writer part of a
   126  // given io.ReadWriter.
   127  func ReadServerData(rw io.ReadWriter) ([]byte, ws.OpCode, error) {
   128  	return ReadData(rw, ws.StateClientSide)
   129  }
   130  
   131  // ReadServerText reads next text message from rw, considering that caller
   132  // represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
   133  // It discards received binary messages.
   134  //
   135  // Note this may handle and write control frames into the writer part of a given
   136  //  io.ReadWriter.
   137  func ReadServerText(rw io.ReadWriter) ([]byte, error) {
   138  	p, _, err := readData(rw, ws.StateClientSide, ws.OpText)
   139  	return p, err
   140  }
   141  
   142  // ReadServerBinary reads next binary message from rw, considering that caller
   143  // represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
   144  // It discards received text messages.
   145  //
   146  // Note this may handle and write control frames into the writer part of a
   147  // given io.ReadWriter.
   148  func ReadServerBinary(rw io.ReadWriter) ([]byte, error) {
   149  	p, _, err := readData(rw, ws.StateClientSide, ws.OpBinary)
   150  	return p, err
   151  }
   152  
   153  // WriteMessage is a helper function that writes message to the w. It
   154  // constructs single frame with given operation code and payload.
   155  // It uses given state to prepare side-dependent things, like cipher
   156  // payload bytes from client to server. It will not mutate p bytes if
   157  // cipher must be made.
   158  //
   159  // If you want to write message in fragmented frames, use Writer instead.
   160  func WriteMessage(w io.Writer, s ws.State, op ws.OpCode, p []byte) error {
   161  	return writeFrame(w, s, op, true, p)
   162  }
   163  
   164  // WriteServerMessage writes message to w, considering that caller
   165  // represents server side.
   166  func WriteServerMessage(w io.Writer, op ws.OpCode, p []byte) error {
   167  	return WriteMessage(w, ws.StateServerSide, op, p)
   168  }
   169  
   170  // WriteServerText is the same as WriteServerMessage with
   171  // ws.OpText.
   172  func WriteServerText(w io.Writer, p []byte) error {
   173  	return WriteServerMessage(w, ws.OpText, p)
   174  }
   175  
   176  // WriteServerBinary is the same as WriteServerMessage with
   177  // ws.OpBinary.
   178  func WriteServerBinary(w io.Writer, p []byte) error {
   179  	return WriteServerMessage(w, ws.OpBinary, p)
   180  }
   181  
   182  // WriteClientMessage writes message to w, considering that caller
   183  // represents client side.
   184  func WriteClientMessage(w io.Writer, op ws.OpCode, p []byte) error {
   185  	return WriteMessage(w, ws.StateClientSide, op, p)
   186  }
   187  
   188  // WriteClientText is the same as WriteClientMessage with
   189  // ws.OpText.
   190  func WriteClientText(w io.Writer, p []byte) error {
   191  	return WriteClientMessage(w, ws.OpText, p)
   192  }
   193  
   194  // WriteClientBinary is the same as WriteClientMessage with
   195  // ws.OpBinary.
   196  func WriteClientBinary(w io.Writer, p []byte) error {
   197  	return WriteClientMessage(w, ws.OpBinary, p)
   198  }
   199  
   200  // HandleClientControlMessage handles control frame from conn and writes
   201  // response when needed.
   202  //
   203  // It considers that caller represents server side.
   204  func HandleClientControlMessage(conn io.Writer, msg Message) error {
   205  	return HandleControlMessage(conn, ws.StateServerSide, msg)
   206  }
   207  
   208  // HandleServerControlMessage handles control frame from conn and writes
   209  // response when needed.
   210  //
   211  // It considers that caller represents client side.
   212  func HandleServerControlMessage(conn io.Writer, msg Message) error {
   213  	return HandleControlMessage(conn, ws.StateClientSide, msg)
   214  }
   215  
   216  // HandleControlMessage handles message which was read by ReadMessage()
   217  // functions.
   218  //
   219  // That is, it is expected, that payload is already unmasked and frame header
   220  // were checked by ws.CheckHeader() call.
   221  func HandleControlMessage(conn io.Writer, state ws.State, msg Message) error {
   222  	return (ControlHandler{
   223  		DisableSrcCiphering: true,
   224  		Src:                 bytes.NewReader(msg.Payload),
   225  		Dst:                 conn,
   226  		State:               state,
   227  	}).Handle(ws.Header{
   228  		Length: int64(len(msg.Payload)),
   229  		OpCode: msg.OpCode,
   230  		Fin:    true,
   231  		Masked: state.ServerSide(),
   232  	})
   233  }
   234  
   235  // ControlFrameHandler returns FrameHandlerFunc for handling control frames.
   236  // For more info see ControlHandler docs.
   237  func ControlFrameHandler(w io.Writer, state ws.State) FrameHandlerFunc {
   238  	return func(h ws.Header, r io.Reader) error {
   239  		return (ControlHandler{
   240  			DisableSrcCiphering: true,
   241  			Src:                 r,
   242  			Dst:                 w,
   243  			State:               state,
   244  		}).Handle(h)
   245  	}
   246  }
   247  
   248  func readData(rw io.ReadWriter, s ws.State, want ws.OpCode) ([]byte, ws.OpCode, error) {
   249  	controlHandler := ControlFrameHandler(rw, s)
   250  	rd := Reader{
   251  		Source:          rw,
   252  		State:           s,
   253  		CheckUTF8:       true,
   254  		SkipHeaderCheck: false,
   255  		OnIntermediate:  controlHandler,
   256  	}
   257  	for {
   258  		hdr, err := rd.NextFrame()
   259  		if err != nil {
   260  			return nil, 0, err
   261  		}
   262  		if hdr.OpCode.IsControl() {
   263  			if err := controlHandler(hdr, &rd); err != nil {
   264  				return nil, 0, err
   265  			}
   266  			continue
   267  		}
   268  		if hdr.OpCode&want == 0 {
   269  			if err := rd.Discard(); err != nil {
   270  				return nil, 0, err
   271  			}
   272  			continue
   273  		}
   274  
   275  		bts, err := ioutil.ReadAll(&rd)
   276  
   277  		return bts, hdr.OpCode, err
   278  	}
   279  }