Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(95)

Delta Between Two Patch Sets: websocket/hixie.go

Issue 5574065: code review 5574065: go.net: initial code (Closed)
Left Patch Set: Created 13 years, 1 month ago
Right Patch Set: diff -r b50a7fb49394 https://code.google.com/p/go.net Created 13 years, 1 month ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « websocket/client.go ('k') | websocket/hixie_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
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
6
7 // This file implements a protocol of Hixie draft version 75 and 76
8 // (draft 76 equals to hybi 00)
9
10 import (
11 "bufio"
12 "bytes"
13 "crypto/md5"
14 "encoding/binary"
15 "fmt"
16 "io"
17 "io/ioutil"
18 "math/rand"
19 "net/http"
20 "net/url"
21 "strconv"
22 "strings"
23 )
24
25 // An aray of characters to be randomly inserted to construct Sec-WebSocket-Key
26 // value. It holds characters from ranges U+0021 to U+002F and U+003A to U+007E.
27 // See Step 21 in Section 4.1 Opening handshake.
28 // http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00#page-22
29 var secKeyRandomChars [0x30 - 0x21 + 0x7F - 0x3A]byte
30
31 func init() {
32 i := 0
33 for ch := byte(0x21); ch < 0x30; ch++ {
34 secKeyRandomChars[i] = ch
35 i++
36 }
37 for ch := byte(0x3a); ch < 0x7F; ch++ {
38 secKeyRandomChars[i] = ch
39 i++
40 }
41 }
42
43 type byteReader interface {
44 ReadByte() (byte, error)
45 }
46
47 // readHixieLength reads frame length for frame type 0x80-0xFF
48 // as defined in Hixie draft.
49 // See section 4.2 Data framing.
50 // http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00#section-4. 2
51 func readHixieLength(r byteReader) (length int64, lengthFields []byte, err error ) {
52 for {
53 c, err := r.ReadByte()
54 if err != nil {
55 return 0, nil, err
56 }
57 lengthFields = append(lengthFields, c)
58 length = length*128 + int64(c&0x7f)
59 if c&0x80 == 0 {
60 break
61 }
62 }
63 return
64 }
65
66 // A hixieLengthFrameReader is a reader for frame type 0x80-0xFF
67 // as defined in hixie draft.
68 type hixieLengthFrameReader struct {
69 reader io.Reader
70 FrameType byte
71 Length int64
72 header *bytes.Buffer
73 length int
74 }
75
76 func (frame *hixieLengthFrameReader) Read(msg []byte) (n int, err error) {
77 return frame.reader.Read(msg)
78 }
79
80 func (frame *hixieLengthFrameReader) PayloadType() byte {
81 if frame.FrameType == '\xff' && frame.Length == 0 {
82 return CloseFrame
83 }
84 return UnknownFrame
85 }
86
87 func (frame *hixieLengthFrameReader) HeaderReader() io.Reader {
88 if frame.header == nil {
89 return nil
90 }
91 if frame.header.Len() == 0 {
92 frame.header = nil
93 return nil
94 }
95 return frame.header
96 }
97
98 func (frame *hixieLengthFrameReader) TrailerReader() io.Reader { return nil }
99
100 func (frame *hixieLengthFrameReader) Len() (n int) { return frame.length }
101
102 // A HixieSentinelFrameReader is a reader for frame type 0x00-0x7F
103 // as defined in hixie draft.
104 type hixieSentinelFrameReader struct {
105 reader *bufio.Reader
106 FrameType byte
107 header *bytes.Buffer
108 data []byte
109 seenTrailer bool
110 trailer *bytes.Buffer
111 }
112
113 func (frame *hixieSentinelFrameReader) Read(msg []byte) (n int, err error) {
114 if len(frame.data) == 0 {
115 if frame.seenTrailer {
116 return 0, io.EOF
117 }
118 frame.data, err = frame.reader.ReadSlice('\xff')
119 if err == nil {
120 frame.seenTrailer = true
121 frame.data = frame.data[:len(frame.data)-1] // trim \xff
122 frame.trailer = bytes.NewBuffer([]byte{0xff})
123 }
124 }
125 n = copy(msg, frame.data)
126 frame.data = frame.data[n:]
127 return n, err
128 }
129
130 func (frame *hixieSentinelFrameReader) PayloadType() byte {
131 if frame.FrameType == 0 {
132 return TextFrame
133 }
134 return UnknownFrame
135 }
136
137 func (frame *hixieSentinelFrameReader) HeaderReader() io.Reader {
138 if frame.header == nil {
139 return nil
140 }
141 if frame.header.Len() == 0 {
142 frame.header = nil
143 return nil
144 }
145 return frame.header
146 }
147
148 func (frame *hixieSentinelFrameReader) TrailerReader() io.Reader {
149 if frame.trailer == nil {
150 return nil
151 }
152 if frame.trailer.Len() == 0 {
153 frame.trailer = nil
154 return nil
155 }
156 return frame.trailer
157 }
158
159 func (frame *hixieSentinelFrameReader) Len() int { return -1 }
160
161 // A HixieFrameReaderFactory creates new frame reader based on its frame type.
162 type hixieFrameReaderFactory struct {
163 *bufio.Reader
164 }
165
166 func (buf hixieFrameReaderFactory) NewFrameReader() (r frameReader, err error) {
167 var header []byte
168 var b byte
169 b, err = buf.ReadByte()
170 if err != nil {
171 return
172 }
173 header = append(header, b)
174 if b&0x80 == 0x80 {
175 length, lengthFields, err := readHixieLength(buf.Reader)
176 if err != nil {
177 return nil, err
178 }
179 if length == 0 {
180 return nil, io.EOF
181 }
182 header = append(header, lengthFields...)
183 return &hixieLengthFrameReader{
184 reader: io.LimitReader(buf.Reader, length),
185 FrameType: b,
186 Length: length,
187 header: bytes.NewBuffer(header)}, err
188 }
189 return &hixieSentinelFrameReader{
190 reader: buf.Reader,
191 FrameType: b,
192 header: bytes.NewBuffer(header)}, err
193 }
194
195 type hixiFrameWriter struct {
196 writer *bufio.Writer
197 }
198
199 func (frame *hixiFrameWriter) Write(msg []byte) (n int, err error) {
200 frame.writer.WriteByte(0)
201 frame.writer.Write(msg)
202 frame.writer.WriteByte(0xff)
203 err = frame.writer.Flush()
204 return len(msg), err
205 }
206
207 func (frame *hixiFrameWriter) Close() error { return nil }
208
209 type hixiFrameWriterFactory struct {
210 *bufio.Writer
211 }
212
213 func (buf hixiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameW riter, err error) {
214 if payloadType != TextFrame {
215 return nil, ErrNotSupported
216 }
217 return &hixiFrameWriter{writer: buf.Writer}, nil
218 }
219
220 type hixiFrameHandler struct {
221 conn *Conn
222 }
223
224 func (handler *hixiFrameHandler) HandleFrame(frame frameReader) (r frameReader, err error) {
225 if header := frame.HeaderReader(); header != nil {
226 io.Copy(ioutil.Discard, header)
227 }
228 if frame.PayloadType() != TextFrame {
229 io.Copy(ioutil.Discard, frame)
230 return nil, nil
231 }
232 return frame, nil
233 }
234
235 func (handler *hixiFrameHandler) WriteClose(_ int) (err error) {
236 handler.conn.wio.Lock()
237 defer handler.conn.wio.Unlock()
238 closingFrame := []byte{'\xff', '\x00'}
239 handler.conn.buf.Write(closingFrame)
240 return handler.conn.buf.Flush()
241 }
242
243 // newHixiConn creates a new WebSocket connection speaking hixie draft protocol.
244 func newHixieConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
245 if buf == nil {
246 br := bufio.NewReader(rwc)
247 bw := bufio.NewWriter(rwc)
248 buf = bufio.NewReadWriter(br, bw)
249 }
250 ws := &Conn{config: config, request: request, buf: buf, rwc: rwc,
251 frameReaderFactory: hixieFrameReaderFactory{buf.Reader},
252 frameWriterFactory: hixiFrameWriterFactory{buf.Writer},
253 PayloadType: TextFrame}
254 ws.frameHandler = &hixiFrameHandler{ws}
255 return ws
256 }
257
258 // getChallengeResponse computes the expected response from the
259 // challenge as described in section 5.1 Opening Handshake steps 42 to
260 // 43 of http://www.whatwg.org/specs/web-socket-protocol/
261 func getChallengeResponse(number1, number2 uint32, key3 []byte) (expected []byte , err error) {
262 // 41. Let /challenge/ be the concatenation of /number_1/, expressed
263 // a big-endian 32 bit integer, /number_2/, expressed in a big-
264 // endian 32 bit integer, and the eight bytes of /key_3/ in the
265 // order they were sent to the wire.
266 challenge := make([]byte, 16)
267 binary.BigEndian.PutUint32(challenge[0:], number1)
268 binary.BigEndian.PutUint32(challenge[4:], number2)
269 copy(challenge[8:], key3)
270
271 // 42. Let /expected/ be the MD5 fingerprint of /challenge/ as a big-
272 // endian 128 bit string.
273 h := md5.New()
274 if _, err = h.Write(challenge); err != nil {
275 return
276 }
277 expected = h.Sum(nil)
278 return
279 }
280
281 // Generates handshake key as described in 4.1 Opening handshake step 16 to 22.
282 // cf. http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
283 func generateKeyNumber() (key string, number uint32) {
284 // 16. Let /spaces_n/ be a random integer from 1 to 12 inclusive.
285 spaces := rand.Intn(12) + 1
286
287 // 17. Let /max_n/ be the largest integer not greater than
288 // 4,294,967,295 divided by /spaces_n/
289 max := int(4294967295 / uint32(spaces))
290
291 // 18. Let /number_n/ be a random integer from 0 to /max_n/ inclusive.
292 number = uint32(rand.Intn(max + 1))
293
294 // 19. Let /product_n/ be the result of multiplying /number_n/ and
295 // /spaces_n/ together.
296 product := number * uint32(spaces)
297
298 // 20. Let /key_n/ be a string consisting of /product_n/, expressed
299 // in base ten using the numerals in the range U+0030 DIGIT ZERO (0)
300 // to U+0039 DIGIT NINE (9).
301 key = fmt.Sprintf("%d", product)
302
303 // 21. Insert between one and twelve random characters from the ranges
304 // U+0021 to U+002F and U+003A to U+007E into /key_n/ at random
305 // positions.
306 n := rand.Intn(12) + 1
307 for i := 0; i < n; i++ {
308 pos := rand.Intn(len(key)) + 1
309 ch := secKeyRandomChars[rand.Intn(len(secKeyRandomChars))]
310 key = key[0:pos] + string(ch) + key[pos:]
311 }
312
313 // 22. Insert /spaces_n/ U+0020 SPACE characters into /key_n/ at random
314 // positions other than the start or end of the string.
315 for i := 0; i < spaces; i++ {
316 pos := rand.Intn(len(key)-1) + 1
317 key = key[0:pos] + " " + key[pos:]
318 }
319
320 return
321 }
322
323 // Generates handshake key_3 as described in 4.1 Opening handshake step 26.
324 // cf. http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
325 func generateKey3() (key []byte) {
326 // 26. Let /key3/ be a string consisting of eight random bytes (or
327 // equivalently, a random 64 bit integer encoded in big-endian order).
328 key = make([]byte, 8)
329 for i := 0; i < 8; i++ {
330 key[i] = byte(rand.Intn(256))
331 }
332 return
333 }
334
335 // Cilent handhake described in (soon obsolete)
336 // draft-ietf-hybi-thewebsocket-protocol-00
337 // (draft-hixie-thewebsocket-protocol-76)·
338 func hixie76ClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
339 switch config.Version {
340 case ProtocolVersionHixie76, ProtocolVersionHybi00:
341 default:
342 panic("wrong protocol version.")
343 }
344 // 4.1. Opening handshake.
345 // Step 5. send a request line.
346 bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
347
348 // Step 6-14. push request headers in fields.
349 fields := []string{
350 "Upgrade: WebSocket\r\n",
351 "Connection: Upgrade\r\n",
352 "Host: " + config.Location.Host + "\r\n",
353 "Origin: " + config.Origin.String() + "\r\n",
354 }
355 if len(config.Protocol) > 0 {
356 if len(config.Protocol) != 1 {
357 return ErrBadWebSocketProtocol
358 }
359 fields = append(fields, "Sec-WebSocket-Protocol: "+config.Protoc ol[0]+"\r\n")
360 }
361 // TODO(ukai): Step 15. send cookie if any.
362
363 // Step 16-23. generate keys and push Sec-WebSocket-Key<n> in fields.
364 key1, number1 := generateKeyNumber()
365 key2, number2 := generateKeyNumber()
366 if config.handshakeData != nil {
367 key1 = config.handshakeData["key1"]
368 n, err := strconv.ParseUint(config.handshakeData["number1"], 10, 32)
369 if err != nil {
370 panic(err)
371 }
372 number1 = uint32(n)
373 key2 = config.handshakeData["key2"]
374 n, err = strconv.ParseUint(config.handshakeData["number2"], 10, 32)
375 if err != nil {
376 panic(err)
377 }
378 number2 = uint32(n)
379 }
380 fields = append(fields, "Sec-WebSocket-Key1: "+key1+"\r\n")
381 fields = append(fields, "Sec-WebSocket-Key2: "+key2+"\r\n")
382
383 // Step 24. shuffle fields and send them out.
384 for i := 1; i < len(fields); i++ {
385 j := rand.Intn(i)
386 fields[i], fields[j] = fields[j], fields[i]
387 }
388 for i := 0; i < len(fields); i++ {
389 bw.WriteString(fields[i])
390 }
391 // Step 25. send CRLF.
392 bw.WriteString("\r\n")
393
394 // Step 26. generate 8 bytes random key.
395 key3 := generateKey3()
396 if config.handshakeData != nil {
397 key3 = []byte(config.handshakeData["key3"])
398 }
399 // Step 27. send it out.
400 bw.Write(key3)
401 if err = bw.Flush(); err != nil {
402 return
403 }
404
405 // Step 28-29, 32-40. read response from server.
406 resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
407 if err != nil {
408 return err
409 }
410 // Step 30. check response code is 101.
411 if resp.StatusCode != 101 {
412 return ErrBadStatus
413 }
414
415 // Step 41. check websocket headers.
416 if resp.Header.Get("Upgrade") != "WebSocket" ||
417 strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
418 return ErrBadUpgrade
419 }
420
421 if resp.Header.Get("Sec-Websocket-Origin") != config.Origin.String() {
422 return ErrBadWebSocketOrigin
423 }
424
425 if resp.Header.Get("Sec-Websocket-Location") != config.Location.String() {
426 return ErrBadWebSocketLocation
427 }
428
429 if len(config.Protocol) > 0 && resp.Header.Get("Sec-Websocket-Protocol") != config.Protocol[0] {
430 return ErrBadWebSocketProtocol
431 }
432
433 // Step 42-43. get expected data from challenge data.
434 expected, err := getChallengeResponse(number1, number2, key3)
435 if err != nil {
436 return err
437 }
438
439 // Step 44. read 16 bytes from server.
440 reply := make([]byte, 16)
441 if _, err = io.ReadFull(br, reply); err != nil {
442 return err
443 }
444
445 // Step 45. check the reply equals to expected data.
446 if !bytes.Equal(expected, reply) {
447 return ErrChallengeResponse
448 }
449 // WebSocket connection is established.
450 return
451 }
452
453 // Client Handshake described in (soon obsolete)
454 // draft-hixie-thewebsocket-protocol-75.
455 func hixie75ClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
456 if config.Version != ProtocolVersionHixie75 {
457 panic("wrong protocol version.")
458 }
459 bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
460 bw.WriteString("Upgrade: WebSocket\r\n")
461 bw.WriteString("Connection: Upgrade\r\n")
462 bw.WriteString("Host: " + config.Location.Host + "\r\n")
463 bw.WriteString("Origin: " + config.Origin.String() + "\r\n")
464 if len(config.Protocol) > 0 {
465 if len(config.Protocol) != 1 {
466 return ErrBadWebSocketProtocol
467 }
468 bw.WriteString("WebSocket-Protocol: " + config.Protocol[0] + "\r \n")
469 }
470 bw.WriteString("\r\n")
471 bw.Flush()
472 resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
473 if err != nil {
474 return
475 }
476 if resp.Status != "101 Web Socket Protocol Handshake" {
477 return ErrBadStatus
478 }
479 if resp.Header.Get("Upgrade") != "WebSocket" ||
480 resp.Header.Get("Connection") != "Upgrade" {
481 return ErrBadUpgrade
482 }
483 if resp.Header.Get("Websocket-Origin") != config.Origin.String() {
484 return ErrBadWebSocketOrigin
485 }
486 if resp.Header.Get("Websocket-Location") != config.Location.String() {
487 return ErrBadWebSocketLocation
488 }
489 if len(config.Protocol) > 0 && resp.Header.Get("Websocket-Protocol") != config.Protocol[0] {
490 return ErrBadWebSocketProtocol
491 }
492 return
493 }
494
495 // newHixieClientConn returns new WebSocket connection speaking hixie draft prot ocol.
496 func newHixieClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteC loser) *Conn {
497 return newHixieConn(config, buf, rwc, nil)
498 }
499
500 // Gets key number from Sec-WebSocket-Key<n>: field as described
501 // in 5.2 Sending the server's opening handshake, 4.
502 func getKeyNumber(s string) (r uint32) {
503 // 4. Let /key-number_n/ be the digits (characters in the range
504 // U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9)) in /key_1/,
505 // interpreted as a base ten integer, ignoring all other characters
506 // in /key_n/.
507 r = 0
508 for i := 0; i < len(s); i++ {
509 if s[i] >= '0' && s[i] <= '9' {
510 r = r*10 + uint32(s[i]) - '0'
511 }
512 }
513 return
514 }
515
516 // A Hixie76ServerHandshaker performs a server handshake using
517 // hixie draft 76 protocol.
518 type hixie76ServerHandshaker struct {
519 *Config
520 challengeResponse []byte
521 }
522
523 func (c *hixie76ServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Req uest) (code int, err error) {
524 c.Version = ProtocolVersionHybi00
525 if req.Method != "GET" {
526 return http.StatusMethodNotAllowed, ErrBadRequestMethod
527 }
528 // HTTP version can be safely ignored.
529
530 if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
531 strings.ToLower(req.Header.Get("Connection")) != "upgrade" {
532 return http.StatusBadRequest, ErrNotWebSocket
533 }
534
535 // TODO(ukai): check Host
536 c.Origin, err = url.ParseRequest(req.Header.Get("Origin"))
537 if err != nil {
538 return http.StatusBadRequest, err
539 }
540
541 key1 := req.Header.Get("Sec-Websocket-Key1")
542 if key1 == "" {
543 return http.StatusBadRequest, ErrChallengeResponse
544 }
545 key2 := req.Header.Get("Sec-Websocket-Key2")
546 if key2 == "" {
547 return http.StatusBadRequest, ErrChallengeResponse
548 }
549 key3 := make([]byte, 8)
550 if _, err := io.ReadFull(buf, key3); err != nil {
551 return http.StatusBadRequest, ErrChallengeResponse
552 }
553
554 var scheme string
555 if req.TLS != nil {
556 scheme = "wss"
557 } else {
558 scheme = "ws"
559 }
560 c.Location, err = url.ParseRequest(scheme + "://" + req.Host + req.URL.R equestURI())
561 if err != nil {
562 return http.StatusBadRequest, err
563 }
564
565 // Step 4. get key number in Sec-WebSocket-Key<n> fields.
566 keyNumber1 := getKeyNumber(key1)
567 keyNumber2 := getKeyNumber(key2)
568
569 // Step 5. get number of spaces in Sec-WebSocket-Key<n> fields.
570 space1 := uint32(strings.Count(key1, " "))
571 space2 := uint32(strings.Count(key2, " "))
572 if space1 == 0 || space2 == 0 {
573 return http.StatusBadRequest, ErrChallengeResponse
574 }
575
576 // Step 6. key number must be an integral multiple of spaces.
577 if keyNumber1%space1 != 0 || keyNumber2%space2 != 0 {
578 return http.StatusBadRequest, ErrChallengeResponse
579 }
580
581 // Step 7. let part be key number divided by spaces.
582 part1 := keyNumber1 / space1
583 part2 := keyNumber2 / space2
584
585 // Step 8. let challenge be concatenation of part1, part2 and key3.
586 // Step 9. get MD5 fingerprint of challenge.
587 c.challengeResponse, err = getChallengeResponse(part1, part2, key3)
588 if err != nil {
589 return http.StatusInternalServerError, err
590 }
591 protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
592 protocols := strings.Split(protocol, ",")
593 for i := 0; i < len(protocols); i++ {
594 c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
595 }
596
597 return http.StatusSwitchingProtocols, nil
598 }
599
600 func (c *hixie76ServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
601 if len(c.Protocol) > 0 {
602 if len(c.Protocol) != 1 {
603 return ErrBadWebSocketProtocol
604 }
605 }
606
607 // Step 10. send response status line.
608 buf.WriteString("HTTP/1.1 101 WebSocket Protocol Handshake\r\n")
609 // Step 11. send response headers.
610 buf.WriteString("Upgrade: WebSocket\r\n")
611 buf.WriteString("Connection: Upgrade\r\n")
612 buf.WriteString("Sec-WebSocket-Origin: " + c.Origin.String() + "\r\n")
613 buf.WriteString("Sec-WebSocket-Location: " + c.Location.String() + "\r\n ")
614 if len(c.Protocol) > 0 {
615 buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r \n")
616 }
617 // Step 12. send CRLF.
618 buf.WriteString("\r\n")
619 // Step 13. send response data.
620 buf.Write(c.challengeResponse)
621 return buf.Flush()
622 }
623
624 func (c *hixie76ServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.Re adWriteCloser, request *http.Request) (conn *Conn) {
625 return newHixieServerConn(c.Config, buf, rwc, request)
626 }
627
628 // A hixie75ServerHandshaker performs a server handshake using
629 // hixie draft 75 protocol.
630 type hixie75ServerHandshaker struct {
631 *Config
632 }
633
634 func (c *hixie75ServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Req uest) (code int, err error) {
635 c.Version = ProtocolVersionHixie75
636 if req.Method != "GET" || req.Proto != "HTTP/1.1" {
637 return http.StatusMethodNotAllowed, ErrBadRequestMethod
638 }
639 if req.Header.Get("Upgrade") != "WebSocket" {
640 return http.StatusBadRequest, ErrNotWebSocket
641 }
642 if req.Header.Get("Connection") != "Upgrade" {
643 return http.StatusBadRequest, ErrNotWebSocket
644 }
645 c.Origin, err = url.ParseRequest(strings.TrimSpace(req.Header.Get("Origi n")))
646 if err != nil {
647 return http.StatusBadRequest, err
648 }
649
650 var scheme string
651 if req.TLS != nil {
652 scheme = "wss"
653 } else {
654 scheme = "ws"
655 }
656 c.Location, err = url.ParseRequest(scheme + "://" + req.Host + req.URL.R equestURI())
657 if err != nil {
658 return http.StatusBadRequest, err
659 }
660 protocol := strings.TrimSpace(req.Header.Get("Websocket-Protocol"))
661 protocols := strings.Split(protocol, ",")
662 for i := 0; i < len(protocols); i++ {
663 c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
664 }
665
666 return http.StatusSwitchingProtocols, nil
667 }
668
669 func (c *hixie75ServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
670 if len(c.Protocol) > 0 {
671 if len(c.Protocol) != 1 {
672 return ErrBadWebSocketProtocol
673 }
674 }
675
676 buf.WriteString("HTTP/1.1 101 Web Socket Protocol Handshake\r\n")
677 buf.WriteString("Upgrade: WebSocket\r\n")
678 buf.WriteString("Connection: Upgrade\r\n")
679 buf.WriteString("WebSocket-Origin: " + c.Origin.String() + "\r\n")
680 buf.WriteString("WebSocket-Location: " + c.Location.String() + "\r\n")
681 if len(c.Protocol) > 0 {
682 buf.WriteString("WebSocket-Protocol: " + c.Protocol[0] + "\r\n")
683 }
684 buf.WriteString("\r\n")
685 return buf.Flush()
686 }
687
688 func (c *hixie75ServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.Re adWriteCloser, request *http.Request) (conn *Conn) {
689 return newHixieServerConn(c.Config, buf, rwc, request)
690 }
691
692 // newHixieServerConn returns a new WebSocket connection speaking hixie draft pr otocol.
693 func newHixieServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteC loser, request *http.Request) *Conn {
694 return newHixieConn(config, buf, rwc, request)
695 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b