123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- package wsutil
- import (
- "bytes"
- "io"
- "io/ioutil"
- "github.com/gobwas/ws"
- )
- // Message represents a message from peer, that could be presented in one or
- // more frames. That is, it contains payload of all message fragments and
- // operation code of initial frame for this message.
- type Message struct {
- OpCode ws.OpCode
- Payload []byte
- }
- // ReadMessage is a helper function that reads next message from r. It appends
- // received message(s) to the third argument and returns the result of it and
- // an error if some failure happened. That is, it probably could receive more
- // than one message when peer sending fragmented message in multiple frames and
- // want to send some control frame between fragments. Then returned slice will
- // contain those control frames at first, and then result of gluing fragments.
- //
- // TODO(gobwas): add DefaultReader with buffer size options.
- func ReadMessage(r io.Reader, s ws.State, m []Message) ([]Message, error) {
- rd := Reader{
- Source: r,
- State: s,
- CheckUTF8: true,
- OnIntermediate: func(hdr ws.Header, src io.Reader) error {
- bts, err := ioutil.ReadAll(src)
- if err != nil {
- return err
- }
- m = append(m, Message{hdr.OpCode, bts})
- return nil
- },
- }
- h, err := rd.NextFrame()
- if err != nil {
- return m, err
- }
- var p []byte
- if h.Fin {
- // No more frames will be read. Use fixed sized buffer to read payload.
- p = make([]byte, h.Length)
- // It is not possible to receive io.EOF here because Reader does not
- // return EOF if frame payload was successfully fetched.
- // Thus we consistent here with io.Reader behavior.
- _, err = io.ReadFull(&rd, p)
- } else {
- // Frame is fragmented, thus use ioutil.ReadAll behavior.
- var buf bytes.Buffer
- _, err = buf.ReadFrom(&rd)
- p = buf.Bytes()
- }
- if err != nil {
- return m, err
- }
- return append(m, Message{h.OpCode, p}), nil
- }
- // ReadClientMessage reads next message from r, considering that caller
- // represents server side.
- // It is a shortcut for ReadMessage(r, ws.StateServerSide, m)
- func ReadClientMessage(r io.Reader, m []Message) ([]Message, error) {
- return ReadMessage(r, ws.StateServerSide, m)
- }
- // ReadServerMessage reads next message from r, considering that caller
- // represents client side.
- // It is a shortcut for ReadMessage(r, ws.StateClientSide, m)
- func ReadServerMessage(r io.Reader, m []Message) ([]Message, error) {
- return ReadMessage(r, ws.StateClientSide, m)
- }
- // ReadData is a helper function that reads next data (non-control) message
- // from rw.
- // It takes care on handling all control frames. It will write response on
- // control frames to the write part of rw. It blocks until some data frame
- // will be received.
- //
- // Note this may handle and write control frames into the writer part of a
- // given io.ReadWriter.
- func ReadData(rw io.ReadWriter, s ws.State) ([]byte, ws.OpCode, error) {
- return readData(rw, s, ws.OpText|ws.OpBinary)
- }
- // ReadClientData reads next data message from rw, considering that caller
- // represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
- //
- // Note this may handle and write control frames into the writer part of a
- // given io.ReadWriter.
- func ReadClientData(rw io.ReadWriter) ([]byte, ws.OpCode, error) {
- return ReadData(rw, ws.StateServerSide)
- }
- // ReadClientText reads next text message from rw, considering that caller
- // represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
- // It discards received binary messages.
- //
- // Note this may handle and write control frames into the writer part of a
- // given io.ReadWriter.
- func ReadClientText(rw io.ReadWriter) ([]byte, error) {
- p, _, err := readData(rw, ws.StateServerSide, ws.OpText)
- return p, err
- }
- // ReadClientBinary reads next binary message from rw, considering that caller
- // represents server side. It is a shortcut for ReadData(rw, ws.StateServerSide).
- // It discards received text messages.
- //
- // Note this may handle and write control frames into the writer part of a given
- // io.ReadWriter.
- func ReadClientBinary(rw io.ReadWriter) ([]byte, error) {
- p, _, err := readData(rw, ws.StateServerSide, ws.OpBinary)
- return p, err
- }
- // ReadServerData reads next data message from rw, considering that caller
- // represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
- //
- // Note this may handle and write control frames into the writer part of a
- // given io.ReadWriter.
- func ReadServerData(rw io.ReadWriter) ([]byte, ws.OpCode, error) {
- return ReadData(rw, ws.StateClientSide)
- }
- // ReadServerText reads next text message from rw, considering that caller
- // represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
- // It discards received binary messages.
- //
- // Note this may handle and write control frames into the writer part of a given
- // io.ReadWriter.
- func ReadServerText(rw io.ReadWriter) ([]byte, error) {
- p, _, err := readData(rw, ws.StateClientSide, ws.OpText)
- return p, err
- }
- // ReadServerBinary reads next binary message from rw, considering that caller
- // represents client side. It is a shortcut for ReadData(rw, ws.StateClientSide).
- // It discards received text messages.
- //
- // Note this may handle and write control frames into the writer part of a
- // given io.ReadWriter.
- func ReadServerBinary(rw io.ReadWriter) ([]byte, error) {
- p, _, err := readData(rw, ws.StateClientSide, ws.OpBinary)
- return p, err
- }
- // WriteMessage is a helper function that writes message to the w. It
- // constructs single frame with given operation code and payload.
- // It uses given state to prepare side-dependent things, like cipher
- // payload bytes from client to server. It will not mutate p bytes if
- // cipher must be made.
- //
- // If you want to write message in fragmented frames, use Writer instead.
- func WriteMessage(w io.Writer, s ws.State, op ws.OpCode, p []byte) error {
- return writeFrame(w, s, op, true, p)
- }
- // WriteServerMessage writes message to w, considering that caller
- // represents server side.
- func WriteServerMessage(w io.Writer, op ws.OpCode, p []byte) error {
- return WriteMessage(w, ws.StateServerSide, op, p)
- }
- // WriteServerText is the same as WriteServerMessage with
- // ws.OpText.
- func WriteServerText(w io.Writer, p []byte) error {
- return WriteServerMessage(w, ws.OpText, p)
- }
- // WriteServerBinary is the same as WriteServerMessage with
- // ws.OpBinary.
- func WriteServerBinary(w io.Writer, p []byte) error {
- return WriteServerMessage(w, ws.OpBinary, p)
- }
- // WriteClientMessage writes message to w, considering that caller
- // represents client side.
- func WriteClientMessage(w io.Writer, op ws.OpCode, p []byte) error {
- return WriteMessage(w, ws.StateClientSide, op, p)
- }
- // WriteClientText is the same as WriteClientMessage with
- // ws.OpText.
- func WriteClientText(w io.Writer, p []byte) error {
- return WriteClientMessage(w, ws.OpText, p)
- }
- // WriteClientBinary is the same as WriteClientMessage with
- // ws.OpBinary.
- func WriteClientBinary(w io.Writer, p []byte) error {
- return WriteClientMessage(w, ws.OpBinary, p)
- }
- // HandleClientControlMessage handles control frame from conn and writes
- // response when needed.
- //
- // It considers that caller represents server side.
- func HandleClientControlMessage(conn io.Writer, msg Message) error {
- return HandleControlMessage(conn, ws.StateServerSide, msg)
- }
- // HandleServerControlMessage handles control frame from conn and writes
- // response when needed.
- //
- // It considers that caller represents client side.
- func HandleServerControlMessage(conn io.Writer, msg Message) error {
- return HandleControlMessage(conn, ws.StateClientSide, msg)
- }
- // HandleControlMessage handles message which was read by ReadMessage()
- // functions.
- //
- // That is, it is expected, that payload is already unmasked and frame header
- // were checked by ws.CheckHeader() call.
- func HandleControlMessage(conn io.Writer, state ws.State, msg Message) error {
- return (ControlHandler{
- DisableSrcCiphering: true,
- Src: bytes.NewReader(msg.Payload),
- Dst: conn,
- State: state,
- }).Handle(ws.Header{
- Length: int64(len(msg.Payload)),
- OpCode: msg.OpCode,
- Fin: true,
- Masked: state.ServerSide(),
- })
- }
- // ControlFrameHandler returns FrameHandlerFunc for handling control frames.
- // For more info see ControlHandler docs.
- func ControlFrameHandler(w io.Writer, state ws.State) FrameHandlerFunc {
- return func(h ws.Header, r io.Reader) error {
- return (ControlHandler{
- DisableSrcCiphering: true,
- Src: r,
- Dst: w,
- State: state,
- }).Handle(h)
- }
- }
- func readData(rw io.ReadWriter, s ws.State, want ws.OpCode) ([]byte, ws.OpCode, error) {
- controlHandler := ControlFrameHandler(rw, s)
- rd := Reader{
- Source: rw,
- State: s,
- CheckUTF8: true,
- SkipHeaderCheck: false,
- OnIntermediate: controlHandler,
- }
- for {
- hdr, err := rd.NextFrame()
- if err != nil {
- return nil, 0, err
- }
- if hdr.OpCode.IsControl() {
- if err := controlHandler(hdr, &rd); err != nil {
- return nil, 0, err
- }
- continue
- }
- if hdr.OpCode&want == 0 {
- if err := rd.Discard(); err != nil {
- return nil, 0, err
- }
- continue
- }
- bts, err := ioutil.ReadAll(&rd)
- return bts, hdr.OpCode, err
- }
- }
|