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}