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 }