github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/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 an alternative 9 // and more actively maintained WebSocket package: 10 // 11 // https://godoc.org/github.com/gorilla/websocket 12 // 13 package websocket // import "github.com/Andyfoo/golang/x/net/websocket" 14 15 import ( 16 "bufio" 17 "crypto/tls" 18 "encoding/json" 19 "errors" 20 "io" 21 "io/ioutil" 22 "net" 23 "net/http" 24 "net/url" 25 "sync" 26 "time" 27 ) 28 29 const ( 30 ProtocolVersionHybi13 = 13 31 ProtocolVersionHybi = ProtocolVersionHybi13 32 SupportedProtocolVersion = "13" 33 34 ContinuationFrame = 0 35 TextFrame = 1 36 BinaryFrame = 2 37 CloseFrame = 8 38 PingFrame = 9 39 PongFrame = 10 40 UnknownFrame = 255 41 42 DefaultMaxPayloadBytes = 32 << 20 // 32MB 43 ) 44 45 // ProtocolError represents WebSocket protocol errors. 46 type ProtocolError struct { 47 ErrorString string 48 } 49 50 func (err *ProtocolError) Error() string { return err.ErrorString } 51 52 var ( 53 ErrBadProtocolVersion = &ProtocolError{"bad protocol version"} 54 ErrBadScheme = &ProtocolError{"bad scheme"} 55 ErrBadStatus = &ProtocolError{"bad status"} 56 ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"} 57 ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"} 58 ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"} 59 ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"} 60 ErrBadWebSocketVersion = &ProtocolError{"missing or bad WebSocket Version"} 61 ErrChallengeResponse = &ProtocolError{"mismatch challenge/response"} 62 ErrBadFrame = &ProtocolError{"bad frame"} 63 ErrBadFrameBoundary = &ProtocolError{"not on frame boundary"} 64 ErrNotWebSocket = &ProtocolError{"not websocket protocol"} 65 ErrBadRequestMethod = &ProtocolError{"bad method"} 66 ErrNotSupported = &ProtocolError{"not supported"} 67 ) 68 69 // ErrFrameTooLarge is returned by Codec's Receive method if payload size 70 // exceeds limit set by Conn.MaxPayloadBytes 71 var ErrFrameTooLarge = errors.New("websocket: frame payload size exceeds limit") 72 73 // Addr is an implementation of net.Addr for WebSocket. 74 type Addr struct { 75 *url.URL 76 } 77 78 // Network returns the network type for a WebSocket, "websocket". 79 func (addr *Addr) Network() string { return "websocket" } 80 81 // Config is a WebSocket configuration 82 type Config struct { 83 // A WebSocket server address. 84 Location *url.URL 85 86 // A Websocket client origin. 87 Origin *url.URL 88 89 // WebSocket subprotocols. 90 Protocol []string 91 92 // WebSocket protocol version. 93 Version int 94 95 // TLS config for secure WebSocket (wss). 96 TlsConfig *tls.Config 97 98 // Additional header fields to be sent in WebSocket opening handshake. 99 Header http.Header 100 101 // Dialer used when opening websocket connections. 102 Dialer *net.Dialer 103 104 handshakeData map[string]string 105 } 106 107 // serverHandshaker is an interface to handle WebSocket server side handshake. 108 type serverHandshaker interface { 109 // ReadHandshake reads handshake request message from client. 110 // Returns http response code and error if any. 111 ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) 112 113 // AcceptHandshake accepts the client handshake request and sends 114 // handshake response back to client. 115 AcceptHandshake(buf *bufio.Writer) (err error) 116 117 // NewServerConn creates a new WebSocket connection. 118 NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn) 119 } 120 121 // frameReader is an interface to read a WebSocket frame. 122 type frameReader interface { 123 // Reader is to read payload of the frame. 124 io.Reader 125 126 // PayloadType returns payload type. 127 PayloadType() byte 128 129 // HeaderReader returns a reader to read header of the frame. 130 HeaderReader() io.Reader 131 132 // TrailerReader returns a reader to read trailer of the frame. 133 // If it returns nil, there is no trailer in the frame. 134 TrailerReader() io.Reader 135 136 // Len returns total length of the frame, including header and trailer. 137 Len() int 138 } 139 140 // frameReaderFactory is an interface to creates new frame reader. 141 type frameReaderFactory interface { 142 NewFrameReader() (r frameReader, err error) 143 } 144 145 // frameWriter is an interface to write a WebSocket frame. 146 type frameWriter interface { 147 // Writer is to write payload of the frame. 148 io.WriteCloser 149 } 150 151 // frameWriterFactory is an interface to create new frame writer. 152 type frameWriterFactory interface { 153 NewFrameWriter(payloadType byte) (w frameWriter, err error) 154 } 155 156 type frameHandler interface { 157 HandleFrame(frame frameReader) (r frameReader, err error) 158 WriteClose(status int) (err error) 159 } 160 161 // Conn represents a WebSocket connection. 162 // 163 // Multiple goroutines may invoke methods on a Conn simultaneously. 164 type Conn struct { 165 config *Config 166 request *http.Request 167 168 buf *bufio.ReadWriter 169 rwc io.ReadWriteCloser 170 171 rio sync.Mutex 172 frameReaderFactory 173 frameReader 174 175 wio sync.Mutex 176 frameWriterFactory 177 178 frameHandler 179 PayloadType byte 180 defaultCloseStatus int 181 182 // MaxPayloadBytes limits the size of frame payload received over Conn 183 // by Codec's Receive method. If zero, DefaultMaxPayloadBytes is used. 184 MaxPayloadBytes int 185 } 186 187 // Read implements the io.Reader interface: 188 // it reads data of a frame from the WebSocket connection. 189 // if msg is not large enough for the frame data, it fills the msg and next Read 190 // will read the rest of the frame data. 191 // it reads Text frame or Binary frame. 192 func (ws *Conn) Read(msg []byte) (n int, err error) { 193 ws.rio.Lock() 194 defer ws.rio.Unlock() 195 again: 196 if ws.frameReader == nil { 197 frame, err := ws.frameReaderFactory.NewFrameReader() 198 if err != nil { 199 return 0, err 200 } 201 ws.frameReader, err = ws.frameHandler.HandleFrame(frame) 202 if err != nil { 203 return 0, err 204 } 205 if ws.frameReader == nil { 206 goto again 207 } 208 } 209 n, err = ws.frameReader.Read(msg) 210 if err == io.EOF { 211 if trailer := ws.frameReader.TrailerReader(); trailer != nil { 212 io.Copy(ioutil.Discard, trailer) 213 } 214 ws.frameReader = nil 215 goto again 216 } 217 return n, err 218 } 219 220 // Write implements the io.Writer interface: 221 // it writes data as a frame to the WebSocket connection. 222 func (ws *Conn) Write(msg []byte) (n int, err error) { 223 ws.wio.Lock() 224 defer ws.wio.Unlock() 225 w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType) 226 if err != nil { 227 return 0, err 228 } 229 n, err = w.Write(msg) 230 w.Close() 231 return n, err 232 } 233 234 // Close implements the io.Closer interface. 235 func (ws *Conn) Close() error { 236 err := ws.frameHandler.WriteClose(ws.defaultCloseStatus) 237 err1 := ws.rwc.Close() 238 if err != nil { 239 return err 240 } 241 return err1 242 } 243 244 // IsClientConn reports whether ws is a client-side connection. 245 func (ws *Conn) IsClientConn() bool { return ws.request == nil } 246 247 // IsServerConn reports whether ws is a server-side connection. 248 func (ws *Conn) IsServerConn() bool { return ws.request != nil } 249 250 // LocalAddr returns the WebSocket Origin for the connection for client, or 251 // the WebSocket location for server. 252 func (ws *Conn) LocalAddr() net.Addr { 253 if ws.IsClientConn() { 254 return &Addr{ws.config.Origin} 255 } 256 return &Addr{ws.config.Location} 257 } 258 259 // RemoteAddr returns the WebSocket location for the connection for client, or 260 // the Websocket Origin for server. 261 func (ws *Conn) RemoteAddr() net.Addr { 262 if ws.IsClientConn() { 263 return &Addr{ws.config.Location} 264 } 265 return &Addr{ws.config.Origin} 266 } 267 268 var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn") 269 270 // SetDeadline sets the connection's network read & write deadlines. 271 func (ws *Conn) SetDeadline(t time.Time) error { 272 if conn, ok := ws.rwc.(net.Conn); ok { 273 return conn.SetDeadline(t) 274 } 275 return errSetDeadline 276 } 277 278 // SetReadDeadline sets the connection's network read deadline. 279 func (ws *Conn) SetReadDeadline(t time.Time) error { 280 if conn, ok := ws.rwc.(net.Conn); ok { 281 return conn.SetReadDeadline(t) 282 } 283 return errSetDeadline 284 } 285 286 // SetWriteDeadline sets the connection's network write deadline. 287 func (ws *Conn) SetWriteDeadline(t time.Time) error { 288 if conn, ok := ws.rwc.(net.Conn); ok { 289 return conn.SetWriteDeadline(t) 290 } 291 return errSetDeadline 292 } 293 294 // Config returns the WebSocket config. 295 func (ws *Conn) Config() *Config { return ws.config } 296 297 // Request returns the http request upgraded to the WebSocket. 298 // It is nil for client side. 299 func (ws *Conn) Request() *http.Request { return ws.request } 300 301 // Codec represents a symmetric pair of functions that implement a codec. 302 type Codec struct { 303 Marshal func(v interface{}) (data []byte, payloadType byte, err error) 304 Unmarshal func(data []byte, payloadType byte, v interface{}) (err error) 305 } 306 307 // Send sends v marshaled by cd.Marshal as single frame to ws. 308 func (cd Codec) Send(ws *Conn, v interface{}) (err error) { 309 data, payloadType, err := cd.Marshal(v) 310 if err != nil { 311 return err 312 } 313 ws.wio.Lock() 314 defer ws.wio.Unlock() 315 w, err := ws.frameWriterFactory.NewFrameWriter(payloadType) 316 if err != nil { 317 return err 318 } 319 _, err = w.Write(data) 320 w.Close() 321 return err 322 } 323 324 // Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores 325 // in v. The whole frame payload is read to an in-memory buffer; max size of 326 // payload is defined by ws.MaxPayloadBytes. If frame payload size exceeds 327 // limit, ErrFrameTooLarge is returned; in this case frame is not read off wire 328 // completely. The next call to Receive would read and discard leftover data of 329 // previous oversized frame before processing next frame. 330 func (cd Codec) Receive(ws *Conn, v interface{}) (err error) { 331 ws.rio.Lock() 332 defer ws.rio.Unlock() 333 if ws.frameReader != nil { 334 _, err = io.Copy(ioutil.Discard, ws.frameReader) 335 if err != nil { 336 return err 337 } 338 ws.frameReader = nil 339 } 340 again: 341 frame, err := ws.frameReaderFactory.NewFrameReader() 342 if err != nil { 343 return err 344 } 345 frame, err = ws.frameHandler.HandleFrame(frame) 346 if err != nil { 347 return err 348 } 349 if frame == nil { 350 goto again 351 } 352 maxPayloadBytes := ws.MaxPayloadBytes 353 if maxPayloadBytes == 0 { 354 maxPayloadBytes = DefaultMaxPayloadBytes 355 } 356 if hf, ok := frame.(*hybiFrameReader); ok && hf.header.Length > int64(maxPayloadBytes) { 357 // payload size exceeds limit, no need to call Unmarshal 358 // 359 // set frameReader to current oversized frame so that 360 // the next call to this function can drain leftover 361 // data before processing the next frame 362 ws.frameReader = frame 363 return ErrFrameTooLarge 364 } 365 payloadType := frame.PayloadType() 366 data, err := ioutil.ReadAll(frame) 367 if err != nil { 368 return err 369 } 370 return cd.Unmarshal(data, payloadType, v) 371 } 372 373 func marshal(v interface{}) (msg []byte, payloadType byte, err error) { 374 switch data := v.(type) { 375 case string: 376 return []byte(data), TextFrame, nil 377 case []byte: 378 return data, BinaryFrame, nil 379 } 380 return nil, UnknownFrame, ErrNotSupported 381 } 382 383 func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) { 384 switch data := v.(type) { 385 case *string: 386 *data = string(msg) 387 return nil 388 case *[]byte: 389 *data = msg 390 return nil 391 } 392 return ErrNotSupported 393 } 394 395 /* 396 Message is a codec to send/receive text/binary data in a frame on WebSocket connection. 397 To send/receive text frame, use string type. 398 To send/receive binary frame, use []byte type. 399 400 Trivial usage: 401 402 import "websocket" 403 404 // receive text frame 405 var message string 406 websocket.Message.Receive(ws, &message) 407 408 // send text frame 409 message = "hello" 410 websocket.Message.Send(ws, message) 411 412 // receive binary frame 413 var data []byte 414 websocket.Message.Receive(ws, &data) 415 416 // send binary frame 417 data = []byte{0, 1, 2} 418 websocket.Message.Send(ws, data) 419 420 */ 421 var Message = Codec{marshal, unmarshal} 422 423 func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) { 424 msg, err = json.Marshal(v) 425 return msg, TextFrame, err 426 } 427 428 func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) { 429 return json.Unmarshal(msg, v) 430 } 431 432 /* 433 JSON is a codec to send/receive JSON data in a frame from a WebSocket connection. 434 435 Trivial usage: 436 437 import "websocket" 438 439 type T struct { 440 Msg string 441 Count int 442 } 443 444 // receive JSON type T 445 var data T 446 websocket.JSON.Receive(ws, &data) 447 448 // send JSON type T 449 websocket.JSON.Send(ws, data) 450 */ 451 var JSON = Codec{jsonMarshal, jsonUnmarshal}