github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/net/websocket/hybi.go (about) 1 // Copyright 2011 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 6 7 // This file implements a protocol of hybi draft. 8 // http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17 9 10 import ( 11 "bufio" 12 "bytes" 13 "crypto/rand" 14 "crypto/sha1" 15 "encoding/base64" 16 "encoding/binary" 17 "fmt" 18 "io" 19 "io/ioutil" 20 "net/http" 21 "net/url" 22 "strings" 23 ) 24 25 const ( 26 websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" 27 28 closeStatusNormal = 1000 29 closeStatusGoingAway = 1001 30 closeStatusProtocolError = 1002 31 closeStatusUnsupportedData = 1003 32 closeStatusFrameTooLarge = 1004 33 closeStatusNoStatusRcvd = 1005 34 closeStatusAbnormalClosure = 1006 35 closeStatusBadMessageData = 1007 36 closeStatusPolicyViolation = 1008 37 closeStatusTooBigData = 1009 38 closeStatusExtensionMismatch = 1010 39 40 maxControlFramePayloadLength = 125 41 ) 42 43 var ( 44 ErrBadMaskingKey = &ProtocolError{"bad masking key"} 45 ErrBadPongMessage = &ProtocolError{"bad pong message"} 46 ErrBadClosingStatus = &ProtocolError{"bad closing status"} 47 ErrUnsupportedExtensions = &ProtocolError{"unsupported extensions"} 48 ErrNotImplemented = &ProtocolError{"not implemented"} 49 50 handshakeHeader = map[string]bool{ 51 "Host": true, 52 "Upgrade": true, 53 "Connection": true, 54 "Sec-Websocket-Key": true, 55 "Sec-Websocket-Origin": true, 56 "Sec-Websocket-Version": true, 57 "Sec-Websocket-Protocol": true, 58 "Sec-Websocket-Accept": true, 59 } 60 ) 61 62 // A hybiFrameHeader is a frame header as defined in hybi draft. 63 type hybiFrameHeader struct { 64 Fin bool 65 Rsv [3]bool 66 OpCode byte 67 Length int64 68 MaskingKey []byte 69 70 data *bytes.Buffer 71 } 72 73 // A hybiFrameReader is a reader for hybi frame. 74 type hybiFrameReader struct { 75 reader io.Reader 76 77 header hybiFrameHeader 78 pos int64 79 length int 80 } 81 82 func (frame *hybiFrameReader) Read(msg []byte) (n int, err error) { 83 n, err = frame.reader.Read(msg) 84 if err != nil { 85 return 0, err 86 } 87 if frame.header.MaskingKey != nil { 88 for i := 0; i < n; i++ { 89 msg[i] = msg[i] ^ frame.header.MaskingKey[frame.pos%4] 90 frame.pos++ 91 } 92 } 93 return n, err 94 } 95 96 func (frame *hybiFrameReader) PayloadType() byte { return frame.header.OpCode } 97 98 func (frame *hybiFrameReader) HeaderReader() io.Reader { 99 if frame.header.data == nil { 100 return nil 101 } 102 if frame.header.data.Len() == 0 { 103 return nil 104 } 105 return frame.header.data 106 } 107 108 func (frame *hybiFrameReader) TrailerReader() io.Reader { return nil } 109 110 func (frame *hybiFrameReader) Len() (n int) { return frame.length } 111 112 // A hybiFrameReaderFactory creates new frame reader based on its frame type. 113 type hybiFrameReaderFactory struct { 114 *bufio.Reader 115 } 116 117 // NewFrameReader reads a frame header from the connection, and creates new reader for the frame. 118 // See Section 5.2 Base Framing protocol for detail. 119 // http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2 120 func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) { 121 hybiFrame := new(hybiFrameReader) 122 frame = hybiFrame 123 var header []byte 124 var b byte 125 // First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits) 126 b, err = buf.ReadByte() 127 if err != nil { 128 return 129 } 130 header = append(header, b) 131 hybiFrame.header.Fin = ((header[0] >> 7) & 1) != 0 132 for i := 0; i < 3; i++ { 133 j := uint(6 - i) 134 hybiFrame.header.Rsv[i] = ((header[0] >> j) & 1) != 0 135 } 136 hybiFrame.header.OpCode = header[0] & 0x0f 137 138 // Second byte. Mask/Payload len(7bits) 139 b, err = buf.ReadByte() 140 if err != nil { 141 return 142 } 143 header = append(header, b) 144 mask := (b & 0x80) != 0 145 b &= 0x7f 146 lengthFields := 0 147 switch { 148 case b <= 125: // Payload length 7bits. 149 hybiFrame.header.Length = int64(b) 150 case b == 126: // Payload length 7+16bits 151 lengthFields = 2 152 case b == 127: // Payload length 7+64bits 153 lengthFields = 8 154 } 155 for i := 0; i < lengthFields; i++ { 156 b, err = buf.ReadByte() 157 if err != nil { 158 return 159 } 160 if lengthFields == 8 && i == 0 { // MSB must be zero when 7+64 bits 161 b &= 0x7f 162 } 163 header = append(header, b) 164 hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b) 165 } 166 if mask { 167 // Masking key. 4 bytes. 168 for i := 0; i < 4; i++ { 169 b, err = buf.ReadByte() 170 if err != nil { 171 return 172 } 173 header = append(header, b) 174 hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b) 175 } 176 } 177 hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length) 178 hybiFrame.header.data = bytes.NewBuffer(header) 179 hybiFrame.length = len(header) + int(hybiFrame.header.Length) 180 return 181 } 182 183 // A HybiFrameWriter is a writer for hybi frame. 184 type hybiFrameWriter struct { 185 writer *bufio.Writer 186 187 header *hybiFrameHeader 188 } 189 190 func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) { 191 var header []byte 192 var b byte 193 if frame.header.Fin { 194 b |= 0x80 195 } 196 for i := 0; i < 3; i++ { 197 if frame.header.Rsv[i] { 198 j := uint(6 - i) 199 b |= 1 << j 200 } 201 } 202 b |= frame.header.OpCode 203 header = append(header, b) 204 if frame.header.MaskingKey != nil { 205 b = 0x80 206 } else { 207 b = 0 208 } 209 lengthFields := 0 210 length := len(msg) 211 switch { 212 case length <= 125: 213 b |= byte(length) 214 case length < 65536: 215 b |= 126 216 lengthFields = 2 217 default: 218 b |= 127 219 lengthFields = 8 220 } 221 header = append(header, b) 222 for i := 0; i < lengthFields; i++ { 223 j := uint((lengthFields - i - 1) * 8) 224 b = byte((length >> j) & 0xff) 225 header = append(header, b) 226 } 227 if frame.header.MaskingKey != nil { 228 if len(frame.header.MaskingKey) != 4 { 229 return 0, ErrBadMaskingKey 230 } 231 header = append(header, frame.header.MaskingKey...) 232 frame.writer.Write(header) 233 data := make([]byte, length) 234 for i := range data { 235 data[i] = msg[i] ^ frame.header.MaskingKey[i%4] 236 } 237 frame.writer.Write(data) 238 err = frame.writer.Flush() 239 return length, err 240 } 241 frame.writer.Write(header) 242 frame.writer.Write(msg) 243 err = frame.writer.Flush() 244 return length, err 245 } 246 247 func (frame *hybiFrameWriter) Close() error { return nil } 248 249 type hybiFrameWriterFactory struct { 250 *bufio.Writer 251 needMaskingKey bool 252 } 253 254 func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) { 255 frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType} 256 if buf.needMaskingKey { 257 frameHeader.MaskingKey, err = generateMaskingKey() 258 if err != nil { 259 return nil, err 260 } 261 } 262 return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil 263 } 264 265 type hybiFrameHandler struct { 266 conn *Conn 267 payloadType byte 268 } 269 270 func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (frameReader, error) { 271 if handler.conn.IsServerConn() { 272 // The client MUST mask all frames sent to the server. 273 if frame.(*hybiFrameReader).header.MaskingKey == nil { 274 handler.WriteClose(closeStatusProtocolError) 275 return nil, io.EOF 276 } 277 } else { 278 // The server MUST NOT mask all frames. 279 if frame.(*hybiFrameReader).header.MaskingKey != nil { 280 handler.WriteClose(closeStatusProtocolError) 281 return nil, io.EOF 282 } 283 } 284 if header := frame.HeaderReader(); header != nil { 285 io.Copy(ioutil.Discard, header) 286 } 287 switch frame.PayloadType() { 288 case ContinuationFrame: 289 frame.(*hybiFrameReader).header.OpCode = handler.payloadType 290 case TextFrame, BinaryFrame: 291 handler.payloadType = frame.PayloadType() 292 case CloseFrame: 293 return nil, io.EOF 294 case PingFrame, PongFrame: 295 b := make([]byte, maxControlFramePayloadLength) 296 n, err := io.ReadFull(frame, b) 297 if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { 298 return nil, err 299 } 300 io.Copy(ioutil.Discard, frame) 301 if frame.PayloadType() == PingFrame { 302 if _, err := handler.WritePong(b[:n]); err != nil { 303 return nil, err 304 } 305 } 306 return nil, nil 307 } 308 return frame, nil 309 } 310 311 func (handler *hybiFrameHandler) WriteClose(status int) (err error) { 312 handler.conn.wio.Lock() 313 defer handler.conn.wio.Unlock() 314 w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame) 315 if err != nil { 316 return err 317 } 318 msg := make([]byte, 2) 319 binary.BigEndian.PutUint16(msg, uint16(status)) 320 _, err = w.Write(msg) 321 w.Close() 322 return err 323 } 324 325 func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) { 326 handler.conn.wio.Lock() 327 defer handler.conn.wio.Unlock() 328 w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame) 329 if err != nil { 330 return 0, err 331 } 332 n, err = w.Write(msg) 333 w.Close() 334 return n, err 335 } 336 337 // newHybiConn creates a new WebSocket connection speaking hybi draft protocol. 338 func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { 339 if buf == nil { 340 br := bufio.NewReader(rwc) 341 bw := bufio.NewWriter(rwc) 342 buf = bufio.NewReadWriter(br, bw) 343 } 344 ws := &Conn{config: config, request: request, buf: buf, rwc: rwc, 345 frameReaderFactory: hybiFrameReaderFactory{buf.Reader}, 346 frameWriterFactory: hybiFrameWriterFactory{ 347 buf.Writer, request == nil}, 348 PayloadType: TextFrame, 349 defaultCloseStatus: closeStatusNormal} 350 ws.frameHandler = &hybiFrameHandler{conn: ws} 351 return ws 352 } 353 354 // generateMaskingKey generates a masking key for a frame. 355 func generateMaskingKey() (maskingKey []byte, err error) { 356 maskingKey = make([]byte, 4) 357 if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil { 358 return 359 } 360 return 361 } 362 363 // generateNonce generates a nonce consisting of a randomly selected 16-byte 364 // value that has been base64-encoded. 365 func generateNonce() (nonce []byte) { 366 key := make([]byte, 16) 367 if _, err := io.ReadFull(rand.Reader, key); err != nil { 368 panic(err) 369 } 370 nonce = make([]byte, 24) 371 base64.StdEncoding.Encode(nonce, key) 372 return 373 } 374 375 // removeZone removes IPv6 zone identifer from host. 376 // E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080" 377 func removeZone(host string) string { 378 if !strings.HasPrefix(host, "[") { 379 return host 380 } 381 i := strings.LastIndex(host, "]") 382 if i < 0 { 383 return host 384 } 385 j := strings.LastIndex(host[:i], "%") 386 if j < 0 { 387 return host 388 } 389 return host[:j] + host[i:] 390 } 391 392 // getNonceAccept computes the base64-encoded SHA-1 of the concatenation of 393 // the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string. 394 func getNonceAccept(nonce []byte) (expected []byte, err error) { 395 h := sha1.New() 396 if _, err = h.Write(nonce); err != nil { 397 return 398 } 399 if _, err = h.Write([]byte(websocketGUID)); err != nil { 400 return 401 } 402 expected = make([]byte, 28) 403 base64.StdEncoding.Encode(expected, h.Sum(nil)) 404 return 405 } 406 407 // Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17 408 func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) { 409 bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n") 410 411 // According to RFC 6874, an HTTP client, proxy, or other 412 // intermediary must remove any IPv6 zone identifier attached 413 // to an outgoing URI. 414 bw.WriteString("Host: " + removeZone(config.Location.Host) + "\r\n") 415 bw.WriteString("Upgrade: websocket\r\n") 416 bw.WriteString("Connection: Upgrade\r\n") 417 nonce := generateNonce() 418 if config.handshakeData != nil { 419 nonce = []byte(config.handshakeData["key"]) 420 } 421 bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n") 422 bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n") 423 424 if config.Version != ProtocolVersionHybi13 { 425 return ErrBadProtocolVersion 426 } 427 428 bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n") 429 if len(config.Protocol) > 0 { 430 bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n") 431 } 432 // TODO(ukai): send Sec-WebSocket-Extensions. 433 err = config.Header.WriteSubset(bw, handshakeHeader) 434 if err != nil { 435 return err 436 } 437 438 bw.WriteString("\r\n") 439 if err = bw.Flush(); err != nil { 440 return err 441 } 442 443 resp, err := http.ReadResponse(br, &http.Request{Method: "GET"}) 444 if err != nil { 445 return err 446 } 447 if resp.StatusCode != 101 { 448 return ErrBadStatus 449 } 450 if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" || 451 strings.ToLower(resp.Header.Get("Connection")) != "upgrade" { 452 return ErrBadUpgrade 453 } 454 expectedAccept, err := getNonceAccept(nonce) 455 if err != nil { 456 return err 457 } 458 if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) { 459 return ErrChallengeResponse 460 } 461 if resp.Header.Get("Sec-WebSocket-Extensions") != "" { 462 return ErrUnsupportedExtensions 463 } 464 offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol") 465 if offeredProtocol != "" { 466 protocolMatched := false 467 for i := 0; i < len(config.Protocol); i++ { 468 if config.Protocol[i] == offeredProtocol { 469 protocolMatched = true 470 break 471 } 472 } 473 if !protocolMatched { 474 return ErrBadWebSocketProtocol 475 } 476 config.Protocol = []string{offeredProtocol} 477 } 478 479 return nil 480 } 481 482 // newHybiClientConn creates a client WebSocket connection after handshake. 483 func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn { 484 return newHybiConn(config, buf, rwc, nil) 485 } 486 487 // A HybiServerHandshaker performs a server handshake using hybi draft protocol. 488 type hybiServerHandshaker struct { 489 *Config 490 accept []byte 491 } 492 493 func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) { 494 c.Version = ProtocolVersionHybi13 495 if req.Method != "GET" { 496 return http.StatusMethodNotAllowed, ErrBadRequestMethod 497 } 498 // HTTP version can be safely ignored. 499 500 if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" || 501 !strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") { 502 return http.StatusBadRequest, ErrNotWebSocket 503 } 504 505 key := req.Header.Get("Sec-Websocket-Key") 506 if key == "" { 507 return http.StatusBadRequest, ErrChallengeResponse 508 } 509 version := req.Header.Get("Sec-Websocket-Version") 510 switch version { 511 case "13": 512 c.Version = ProtocolVersionHybi13 513 default: 514 return http.StatusBadRequest, ErrBadWebSocketVersion 515 } 516 var scheme string 517 if req.TLS != nil { 518 scheme = "wss" 519 } else { 520 scheme = "ws" 521 } 522 c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI()) 523 if err != nil { 524 return http.StatusBadRequest, err 525 } 526 protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol")) 527 if protocol != "" { 528 protocols := strings.Split(protocol, ",") 529 for i := 0; i < len(protocols); i++ { 530 c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i])) 531 } 532 } 533 c.accept, err = getNonceAccept([]byte(key)) 534 if err != nil { 535 return http.StatusInternalServerError, err 536 } 537 return http.StatusSwitchingProtocols, nil 538 } 539 540 // Origin parses the Origin header in req. 541 // If the Origin header is not set, it returns nil and nil. 542 func Origin(config *Config, req *http.Request) (*url.URL, error) { 543 var origin string 544 switch config.Version { 545 case ProtocolVersionHybi13: 546 origin = req.Header.Get("Origin") 547 } 548 if origin == "" { 549 return nil, nil 550 } 551 return url.ParseRequestURI(origin) 552 } 553 554 func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) { 555 if len(c.Protocol) > 0 { 556 if len(c.Protocol) != 1 { 557 // You need choose a Protocol in Handshake func in Server. 558 return ErrBadWebSocketProtocol 559 } 560 } 561 buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n") 562 buf.WriteString("Upgrade: websocket\r\n") 563 buf.WriteString("Connection: Upgrade\r\n") 564 buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n") 565 if len(c.Protocol) > 0 { 566 buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n") 567 } 568 // TODO(ukai): send Sec-WebSocket-Extensions. 569 if c.Header != nil { 570 err := c.Header.WriteSubset(buf, handshakeHeader) 571 if err != nil { 572 return err 573 } 574 } 575 buf.WriteString("\r\n") 576 return buf.Flush() 577 } 578 579 func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { 580 return newHybiServerConn(c.Config, buf, rwc, request) 581 } 582 583 // newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol. 584 func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { 585 return newHybiConn(config, buf, rwc, request) 586 }