github.com/technosophos/deis@v1.7.1-0.20150915173815-f9005256004b/Godeps/_workspace/src/golang.org/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 header = append(header, b) 161 hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b) 162 } 163 if mask { 164 // Masking key. 4 bytes. 165 for i := 0; i < 4; i++ { 166 b, err = buf.ReadByte() 167 if err != nil { 168 return 169 } 170 header = append(header, b) 171 hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b) 172 } 173 } 174 hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length) 175 hybiFrame.header.data = bytes.NewBuffer(header) 176 hybiFrame.length = len(header) + int(hybiFrame.header.Length) 177 return 178 } 179 180 // A HybiFrameWriter is a writer for hybi frame. 181 type hybiFrameWriter struct { 182 writer *bufio.Writer 183 184 header *hybiFrameHeader 185 } 186 187 func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) { 188 var header []byte 189 var b byte 190 if frame.header.Fin { 191 b |= 0x80 192 } 193 for i := 0; i < 3; i++ { 194 if frame.header.Rsv[i] { 195 j := uint(6 - i) 196 b |= 1 << j 197 } 198 } 199 b |= frame.header.OpCode 200 header = append(header, b) 201 if frame.header.MaskingKey != nil { 202 b = 0x80 203 } else { 204 b = 0 205 } 206 lengthFields := 0 207 length := len(msg) 208 switch { 209 case length <= 125: 210 b |= byte(length) 211 case length < 65536: 212 b |= 126 213 lengthFields = 2 214 default: 215 b |= 127 216 lengthFields = 8 217 } 218 header = append(header, b) 219 for i := 0; i < lengthFields; i++ { 220 j := uint((lengthFields - i - 1) * 8) 221 b = byte((length >> j) & 0xff) 222 header = append(header, b) 223 } 224 if frame.header.MaskingKey != nil { 225 if len(frame.header.MaskingKey) != 4 { 226 return 0, ErrBadMaskingKey 227 } 228 header = append(header, frame.header.MaskingKey...) 229 frame.writer.Write(header) 230 data := make([]byte, length) 231 for i := range data { 232 data[i] = msg[i] ^ frame.header.MaskingKey[i%4] 233 } 234 frame.writer.Write(data) 235 err = frame.writer.Flush() 236 return length, err 237 } 238 frame.writer.Write(header) 239 frame.writer.Write(msg) 240 err = frame.writer.Flush() 241 return length, err 242 } 243 244 func (frame *hybiFrameWriter) Close() error { return nil } 245 246 type hybiFrameWriterFactory struct { 247 *bufio.Writer 248 needMaskingKey bool 249 } 250 251 func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) { 252 frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType} 253 if buf.needMaskingKey { 254 frameHeader.MaskingKey, err = generateMaskingKey() 255 if err != nil { 256 return nil, err 257 } 258 } 259 return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil 260 } 261 262 type hybiFrameHandler struct { 263 conn *Conn 264 payloadType byte 265 } 266 267 func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (r frameReader, err error) { 268 if handler.conn.IsServerConn() { 269 // The client MUST mask all frames sent to the server. 270 if frame.(*hybiFrameReader).header.MaskingKey == nil { 271 handler.WriteClose(closeStatusProtocolError) 272 return nil, io.EOF 273 } 274 } else { 275 // The server MUST NOT mask all frames. 276 if frame.(*hybiFrameReader).header.MaskingKey != nil { 277 handler.WriteClose(closeStatusProtocolError) 278 return nil, io.EOF 279 } 280 } 281 if header := frame.HeaderReader(); header != nil { 282 io.Copy(ioutil.Discard, header) 283 } 284 switch frame.PayloadType() { 285 case ContinuationFrame: 286 frame.(*hybiFrameReader).header.OpCode = handler.payloadType 287 case TextFrame, BinaryFrame: 288 handler.payloadType = frame.PayloadType() 289 case CloseFrame: 290 return nil, io.EOF 291 case PingFrame: 292 pingMsg := make([]byte, maxControlFramePayloadLength) 293 n, err := io.ReadFull(frame, pingMsg) 294 if err != nil && err != io.ErrUnexpectedEOF { 295 return nil, err 296 } 297 io.Copy(ioutil.Discard, frame) 298 n, err = handler.WritePong(pingMsg[:n]) 299 if err != nil { 300 return nil, err 301 } 302 return nil, nil 303 case PongFrame: 304 return nil, ErrNotImplemented 305 } 306 return frame, nil 307 } 308 309 func (handler *hybiFrameHandler) WriteClose(status int) (err error) { 310 handler.conn.wio.Lock() 311 defer handler.conn.wio.Unlock() 312 w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame) 313 if err != nil { 314 return err 315 } 316 msg := make([]byte, 2) 317 binary.BigEndian.PutUint16(msg, uint16(status)) 318 _, err = w.Write(msg) 319 w.Close() 320 return err 321 } 322 323 func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) { 324 handler.conn.wio.Lock() 325 defer handler.conn.wio.Unlock() 326 w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame) 327 if err != nil { 328 return 0, err 329 } 330 n, err = w.Write(msg) 331 w.Close() 332 return n, err 333 } 334 335 // newHybiConn creates a new WebSocket connection speaking hybi draft protocol. 336 func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { 337 if buf == nil { 338 br := bufio.NewReader(rwc) 339 bw := bufio.NewWriter(rwc) 340 buf = bufio.NewReadWriter(br, bw) 341 } 342 ws := &Conn{config: config, request: request, buf: buf, rwc: rwc, 343 frameReaderFactory: hybiFrameReaderFactory{buf.Reader}, 344 frameWriterFactory: hybiFrameWriterFactory{ 345 buf.Writer, request == nil}, 346 PayloadType: TextFrame, 347 defaultCloseStatus: closeStatusNormal} 348 ws.frameHandler = &hybiFrameHandler{conn: ws} 349 return ws 350 } 351 352 // generateMaskingKey generates a masking key for a frame. 353 func generateMaskingKey() (maskingKey []byte, err error) { 354 maskingKey = make([]byte, 4) 355 if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil { 356 return 357 } 358 return 359 } 360 361 // generateNonce generates a nonce consisting of a randomly selected 16-byte 362 // value that has been base64-encoded. 363 func generateNonce() (nonce []byte) { 364 key := make([]byte, 16) 365 if _, err := io.ReadFull(rand.Reader, key); err != nil { 366 panic(err) 367 } 368 nonce = make([]byte, 24) 369 base64.StdEncoding.Encode(nonce, key) 370 return 371 } 372 373 // getNonceAccept computes the base64-encoded SHA-1 of the concatenation of 374 // the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string. 375 func getNonceAccept(nonce []byte) (expected []byte, err error) { 376 h := sha1.New() 377 if _, err = h.Write(nonce); err != nil { 378 return 379 } 380 if _, err = h.Write([]byte(websocketGUID)); err != nil { 381 return 382 } 383 expected = make([]byte, 28) 384 base64.StdEncoding.Encode(expected, h.Sum(nil)) 385 return 386 } 387 388 // Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17 389 func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) { 390 bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n") 391 392 bw.WriteString("Host: " + config.Location.Host + "\r\n") 393 bw.WriteString("Upgrade: websocket\r\n") 394 bw.WriteString("Connection: Upgrade\r\n") 395 nonce := generateNonce() 396 if config.handshakeData != nil { 397 nonce = []byte(config.handshakeData["key"]) 398 } 399 bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n") 400 bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n") 401 402 if config.Version != ProtocolVersionHybi13 { 403 return ErrBadProtocolVersion 404 } 405 406 bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n") 407 if len(config.Protocol) > 0 { 408 bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n") 409 } 410 // TODO(ukai): send Sec-WebSocket-Extensions. 411 err = config.Header.WriteSubset(bw, handshakeHeader) 412 if err != nil { 413 return err 414 } 415 416 bw.WriteString("\r\n") 417 if err = bw.Flush(); err != nil { 418 return err 419 } 420 421 resp, err := http.ReadResponse(br, &http.Request{Method: "GET"}) 422 if err != nil { 423 return err 424 } 425 if resp.StatusCode != 101 { 426 return ErrBadStatus 427 } 428 if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" || 429 strings.ToLower(resp.Header.Get("Connection")) != "upgrade" { 430 return ErrBadUpgrade 431 } 432 expectedAccept, err := getNonceAccept(nonce) 433 if err != nil { 434 return err 435 } 436 if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) { 437 return ErrChallengeResponse 438 } 439 if resp.Header.Get("Sec-WebSocket-Extensions") != "" { 440 return ErrUnsupportedExtensions 441 } 442 offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol") 443 if offeredProtocol != "" { 444 protocolMatched := false 445 for i := 0; i < len(config.Protocol); i++ { 446 if config.Protocol[i] == offeredProtocol { 447 protocolMatched = true 448 break 449 } 450 } 451 if !protocolMatched { 452 return ErrBadWebSocketProtocol 453 } 454 config.Protocol = []string{offeredProtocol} 455 } 456 457 return nil 458 } 459 460 // newHybiClientConn creates a client WebSocket connection after handshake. 461 func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn { 462 return newHybiConn(config, buf, rwc, nil) 463 } 464 465 // A HybiServerHandshaker performs a server handshake using hybi draft protocol. 466 type hybiServerHandshaker struct { 467 *Config 468 accept []byte 469 } 470 471 func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) { 472 c.Version = ProtocolVersionHybi13 473 if req.Method != "GET" { 474 return http.StatusMethodNotAllowed, ErrBadRequestMethod 475 } 476 // HTTP version can be safely ignored. 477 478 if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" || 479 !strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") { 480 return http.StatusBadRequest, ErrNotWebSocket 481 } 482 483 key := req.Header.Get("Sec-Websocket-Key") 484 if key == "" { 485 return http.StatusBadRequest, ErrChallengeResponse 486 } 487 version := req.Header.Get("Sec-Websocket-Version") 488 switch version { 489 case "13": 490 c.Version = ProtocolVersionHybi13 491 default: 492 return http.StatusBadRequest, ErrBadWebSocketVersion 493 } 494 var scheme string 495 if req.TLS != nil { 496 scheme = "wss" 497 } else { 498 scheme = "ws" 499 } 500 c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI()) 501 if err != nil { 502 return http.StatusBadRequest, err 503 } 504 protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol")) 505 if protocol != "" { 506 protocols := strings.Split(protocol, ",") 507 for i := 0; i < len(protocols); i++ { 508 c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i])) 509 } 510 } 511 c.accept, err = getNonceAccept([]byte(key)) 512 if err != nil { 513 return http.StatusInternalServerError, err 514 } 515 return http.StatusSwitchingProtocols, nil 516 } 517 518 // Origin parses Origin header in "req". 519 // If origin is "null", returns (nil, nil). 520 func Origin(config *Config, req *http.Request) (*url.URL, error) { 521 var origin string 522 switch config.Version { 523 case ProtocolVersionHybi13: 524 origin = req.Header.Get("Origin") 525 } 526 if origin == "null" { 527 return nil, nil 528 } 529 return url.ParseRequestURI(origin) 530 } 531 532 func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) { 533 if len(c.Protocol) > 0 { 534 if len(c.Protocol) != 1 { 535 // You need choose a Protocol in Handshake func in Server. 536 return ErrBadWebSocketProtocol 537 } 538 } 539 buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n") 540 buf.WriteString("Upgrade: websocket\r\n") 541 buf.WriteString("Connection: Upgrade\r\n") 542 buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n") 543 if len(c.Protocol) > 0 { 544 buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n") 545 } 546 // TODO(ukai): send Sec-WebSocket-Extensions. 547 if c.Header != nil { 548 err := c.Header.WriteSubset(buf, handshakeHeader) 549 if err != nil { 550 return err 551 } 552 } 553 buf.WriteString("\r\n") 554 return buf.Flush() 555 } 556 557 func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { 558 return newHybiServerConn(c.Config, buf, rwc, request) 559 } 560 561 // newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol. 562 func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn { 563 return newHybiConn(config, buf, rwc, request) 564 }