mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Update vendored go.net to use golang.org/x/net canonical path
Signed-off-by: Tibor Vass <tibor@docker.com>
This commit is contained in:
parent
57aa0248af
commit
d820e00aac
9 changed files with 37 additions and 757 deletions
|
@ -14,8 +14,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.google.com/p/go.net/websocket"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"golang.org/x/net/websocket"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/api"
|
"github.com/docker/docker/api"
|
||||||
|
|
|
@ -12,8 +12,9 @@ clone() {
|
||||||
local vcs="$1"
|
local vcs="$1"
|
||||||
local pkg="$2"
|
local pkg="$2"
|
||||||
local rev="$3"
|
local rev="$3"
|
||||||
|
local url="$4"
|
||||||
|
|
||||||
local url="https://$pkg"
|
: ${url:=https://$pkg}
|
||||||
local target="vendor/src/$pkg"
|
local target="vendor/src/$pkg"
|
||||||
|
|
||||||
echo -n "$pkg @ $rev: "
|
echo -n "$pkg @ $rev: "
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
cd "$(dirname "$BASH_SOURCE")/.."
|
cd "$(dirname "$BASH_SOURCE")/.."
|
||||||
|
rm -rf vendor/
|
||||||
source 'hack/.vendor-helpers.sh'
|
source 'hack/.vendor-helpers.sh'
|
||||||
|
|
||||||
# the following lines are in sorted order, FYI
|
# the following lines are in sorted order, FYI
|
||||||
|
@ -13,7 +14,7 @@ clone git github.com/gorilla/mux e444e69cbd
|
||||||
clone git github.com/kr/pty 5cf931ef8f
|
clone git github.com/kr/pty 5cf931ef8f
|
||||||
clone git github.com/mistifyio/go-zfs v2.1.1
|
clone git github.com/mistifyio/go-zfs v2.1.1
|
||||||
clone git github.com/tchap/go-patricia v2.1.0
|
clone git github.com/tchap/go-patricia v2.1.0
|
||||||
clone hg code.google.com/p/go.net 84a4013f96e0
|
clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
|
||||||
clone hg code.google.com/p/gosqlite 74691fb6f837
|
clone hg code.google.com/p/gosqlite 74691fb6f837
|
||||||
|
|
||||||
#get libnetwork packages
|
#get libnetwork packages
|
||||||
|
|
|
@ -7,8 +7,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-check/check"
|
"github.com/go-check/check"
|
||||||
|
"golang.org/x/net/websocket"
|
||||||
"code.google.com/p/go.net/websocket"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *DockerSuite) TestGetContainersAttachWebsocket(c *check.C) {
|
func (s *DockerSuite) TestGetContainersAttachWebsocket(c *check.C) {
|
||||||
|
|
|
@ -1,695 +0,0 @@
|
||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package websocket
|
|
||||||
|
|
||||||
// This file implements a protocol of Hixie draft version 75 and 76
|
|
||||||
// (draft 76 equals to hybi 00)
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"crypto/md5"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// An array of characters to be randomly inserted to construct Sec-WebSocket-Key
|
|
||||||
// value. It holds characters from ranges U+0021 to U+002F and U+003A to U+007E.
|
|
||||||
// See Step 21 in Section 4.1 Opening handshake.
|
|
||||||
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00#page-22
|
|
||||||
var secKeyRandomChars [0x30 - 0x21 + 0x7F - 0x3A]byte
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
i := 0
|
|
||||||
for ch := byte(0x21); ch < 0x30; ch++ {
|
|
||||||
secKeyRandomChars[i] = ch
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
for ch := byte(0x3a); ch < 0x7F; ch++ {
|
|
||||||
secKeyRandomChars[i] = ch
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type byteReader interface {
|
|
||||||
ReadByte() (byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// readHixieLength reads frame length for frame type 0x80-0xFF
|
|
||||||
// as defined in Hixie draft.
|
|
||||||
// See section 4.2 Data framing.
|
|
||||||
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00#section-4.2
|
|
||||||
func readHixieLength(r byteReader) (length int64, lengthFields []byte, err error) {
|
|
||||||
for {
|
|
||||||
c, err := r.ReadByte()
|
|
||||||
if err != nil {
|
|
||||||
return 0, nil, err
|
|
||||||
}
|
|
||||||
lengthFields = append(lengthFields, c)
|
|
||||||
length = length*128 + int64(c&0x7f)
|
|
||||||
if c&0x80 == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// A hixieLengthFrameReader is a reader for frame type 0x80-0xFF
|
|
||||||
// as defined in hixie draft.
|
|
||||||
type hixieLengthFrameReader struct {
|
|
||||||
reader io.Reader
|
|
||||||
FrameType byte
|
|
||||||
Length int64
|
|
||||||
header *bytes.Buffer
|
|
||||||
length int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *hixieLengthFrameReader) Read(msg []byte) (n int, err error) {
|
|
||||||
return frame.reader.Read(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *hixieLengthFrameReader) PayloadType() byte {
|
|
||||||
if frame.FrameType == '\xff' && frame.Length == 0 {
|
|
||||||
return CloseFrame
|
|
||||||
}
|
|
||||||
return UnknownFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *hixieLengthFrameReader) HeaderReader() io.Reader {
|
|
||||||
if frame.header == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if frame.header.Len() == 0 {
|
|
||||||
frame.header = nil
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return frame.header
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *hixieLengthFrameReader) TrailerReader() io.Reader { return nil }
|
|
||||||
|
|
||||||
func (frame *hixieLengthFrameReader) Len() (n int) { return frame.length }
|
|
||||||
|
|
||||||
// A HixieSentinelFrameReader is a reader for frame type 0x00-0x7F
|
|
||||||
// as defined in hixie draft.
|
|
||||||
type hixieSentinelFrameReader struct {
|
|
||||||
reader *bufio.Reader
|
|
||||||
FrameType byte
|
|
||||||
header *bytes.Buffer
|
|
||||||
data []byte
|
|
||||||
seenTrailer bool
|
|
||||||
trailer *bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *hixieSentinelFrameReader) Read(msg []byte) (n int, err error) {
|
|
||||||
if len(frame.data) == 0 {
|
|
||||||
if frame.seenTrailer {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
frame.data, err = frame.reader.ReadSlice('\xff')
|
|
||||||
if err == nil {
|
|
||||||
frame.seenTrailer = true
|
|
||||||
frame.data = frame.data[:len(frame.data)-1] // trim \xff
|
|
||||||
frame.trailer = bytes.NewBuffer([]byte{0xff})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n = copy(msg, frame.data)
|
|
||||||
frame.data = frame.data[n:]
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *hixieSentinelFrameReader) PayloadType() byte {
|
|
||||||
if frame.FrameType == 0 {
|
|
||||||
return TextFrame
|
|
||||||
}
|
|
||||||
return UnknownFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *hixieSentinelFrameReader) HeaderReader() io.Reader {
|
|
||||||
if frame.header == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if frame.header.Len() == 0 {
|
|
||||||
frame.header = nil
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return frame.header
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *hixieSentinelFrameReader) TrailerReader() io.Reader {
|
|
||||||
if frame.trailer == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if frame.trailer.Len() == 0 {
|
|
||||||
frame.trailer = nil
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return frame.trailer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *hixieSentinelFrameReader) Len() int { return -1 }
|
|
||||||
|
|
||||||
// A HixieFrameReaderFactory creates new frame reader based on its frame type.
|
|
||||||
type hixieFrameReaderFactory struct {
|
|
||||||
*bufio.Reader
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buf hixieFrameReaderFactory) NewFrameReader() (r frameReader, err error) {
|
|
||||||
var header []byte
|
|
||||||
var b byte
|
|
||||||
b, err = buf.ReadByte()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
header = append(header, b)
|
|
||||||
if b&0x80 == 0x80 {
|
|
||||||
length, lengthFields, err := readHixieLength(buf.Reader)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if length == 0 {
|
|
||||||
return nil, io.EOF
|
|
||||||
}
|
|
||||||
header = append(header, lengthFields...)
|
|
||||||
return &hixieLengthFrameReader{
|
|
||||||
reader: io.LimitReader(buf.Reader, length),
|
|
||||||
FrameType: b,
|
|
||||||
Length: length,
|
|
||||||
header: bytes.NewBuffer(header)}, err
|
|
||||||
}
|
|
||||||
return &hixieSentinelFrameReader{
|
|
||||||
reader: buf.Reader,
|
|
||||||
FrameType: b,
|
|
||||||
header: bytes.NewBuffer(header)}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type hixiFrameWriter struct {
|
|
||||||
writer *bufio.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *hixiFrameWriter) Write(msg []byte) (n int, err error) {
|
|
||||||
frame.writer.WriteByte(0)
|
|
||||||
frame.writer.Write(msg)
|
|
||||||
frame.writer.WriteByte(0xff)
|
|
||||||
err = frame.writer.Flush()
|
|
||||||
return len(msg), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (frame *hixiFrameWriter) Close() error { return nil }
|
|
||||||
|
|
||||||
type hixiFrameWriterFactory struct {
|
|
||||||
*bufio.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (buf hixiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) {
|
|
||||||
if payloadType != TextFrame {
|
|
||||||
return nil, ErrNotSupported
|
|
||||||
}
|
|
||||||
return &hixiFrameWriter{writer: buf.Writer}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type hixiFrameHandler struct {
|
|
||||||
conn *Conn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (handler *hixiFrameHandler) HandleFrame(frame frameReader) (r frameReader, err error) {
|
|
||||||
if header := frame.HeaderReader(); header != nil {
|
|
||||||
io.Copy(ioutil.Discard, header)
|
|
||||||
}
|
|
||||||
if frame.PayloadType() != TextFrame {
|
|
||||||
io.Copy(ioutil.Discard, frame)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return frame, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (handler *hixiFrameHandler) WriteClose(_ int) (err error) {
|
|
||||||
handler.conn.wio.Lock()
|
|
||||||
defer handler.conn.wio.Unlock()
|
|
||||||
closingFrame := []byte{'\xff', '\x00'}
|
|
||||||
handler.conn.buf.Write(closingFrame)
|
|
||||||
return handler.conn.buf.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
// newHixiConn creates a new WebSocket connection speaking hixie draft protocol.
|
|
||||||
func newHixieConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
|
|
||||||
if buf == nil {
|
|
||||||
br := bufio.NewReader(rwc)
|
|
||||||
bw := bufio.NewWriter(rwc)
|
|
||||||
buf = bufio.NewReadWriter(br, bw)
|
|
||||||
}
|
|
||||||
ws := &Conn{config: config, request: request, buf: buf, rwc: rwc,
|
|
||||||
frameReaderFactory: hixieFrameReaderFactory{buf.Reader},
|
|
||||||
frameWriterFactory: hixiFrameWriterFactory{buf.Writer},
|
|
||||||
PayloadType: TextFrame}
|
|
||||||
ws.frameHandler = &hixiFrameHandler{ws}
|
|
||||||
return ws
|
|
||||||
}
|
|
||||||
|
|
||||||
// getChallengeResponse computes the expected response from the
|
|
||||||
// challenge as described in section 5.1 Opening Handshake steps 42 to
|
|
||||||
// 43 of http://www.whatwg.org/specs/web-socket-protocol/
|
|
||||||
func getChallengeResponse(number1, number2 uint32, key3 []byte) (expected []byte, err error) {
|
|
||||||
// 41. Let /challenge/ be the concatenation of /number_1/, expressed
|
|
||||||
// a big-endian 32 bit integer, /number_2/, expressed in a big-
|
|
||||||
// endian 32 bit integer, and the eight bytes of /key_3/ in the
|
|
||||||
// order they were sent to the wire.
|
|
||||||
challenge := make([]byte, 16)
|
|
||||||
binary.BigEndian.PutUint32(challenge[0:], number1)
|
|
||||||
binary.BigEndian.PutUint32(challenge[4:], number2)
|
|
||||||
copy(challenge[8:], key3)
|
|
||||||
|
|
||||||
// 42. Let /expected/ be the MD5 fingerprint of /challenge/ as a big-
|
|
||||||
// endian 128 bit string.
|
|
||||||
h := md5.New()
|
|
||||||
if _, err = h.Write(challenge); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
expected = h.Sum(nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates handshake key as described in 4.1 Opening handshake step 16 to 22.
|
|
||||||
// cf. http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
|
|
||||||
func generateKeyNumber() (key string, number uint32) {
|
|
||||||
// 16. Let /spaces_n/ be a random integer from 1 to 12 inclusive.
|
|
||||||
spaces := rand.Intn(12) + 1
|
|
||||||
|
|
||||||
// 17. Let /max_n/ be the largest integer not greater than
|
|
||||||
// 4,294,967,295 divided by /spaces_n/
|
|
||||||
max := int(4294967295 / uint32(spaces))
|
|
||||||
|
|
||||||
// 18. Let /number_n/ be a random integer from 0 to /max_n/ inclusive.
|
|
||||||
number = uint32(rand.Intn(max + 1))
|
|
||||||
|
|
||||||
// 19. Let /product_n/ be the result of multiplying /number_n/ and
|
|
||||||
// /spaces_n/ together.
|
|
||||||
product := number * uint32(spaces)
|
|
||||||
|
|
||||||
// 20. Let /key_n/ be a string consisting of /product_n/, expressed
|
|
||||||
// in base ten using the numerals in the range U+0030 DIGIT ZERO (0)
|
|
||||||
// to U+0039 DIGIT NINE (9).
|
|
||||||
key = fmt.Sprintf("%d", product)
|
|
||||||
|
|
||||||
// 21. Insert between one and twelve random characters from the ranges
|
|
||||||
// U+0021 to U+002F and U+003A to U+007E into /key_n/ at random
|
|
||||||
// positions.
|
|
||||||
n := rand.Intn(12) + 1
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
pos := rand.Intn(len(key)) + 1
|
|
||||||
ch := secKeyRandomChars[rand.Intn(len(secKeyRandomChars))]
|
|
||||||
key = key[0:pos] + string(ch) + key[pos:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 22. Insert /spaces_n/ U+0020 SPACE characters into /key_n/ at random
|
|
||||||
// positions other than the start or end of the string.
|
|
||||||
for i := 0; i < spaces; i++ {
|
|
||||||
pos := rand.Intn(len(key)-1) + 1
|
|
||||||
key = key[0:pos] + " " + key[pos:]
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates handshake key_3 as described in 4.1 Opening handshake step 26.
|
|
||||||
// cf. http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
|
|
||||||
func generateKey3() (key []byte) {
|
|
||||||
// 26. Let /key3/ be a string consisting of eight random bytes (or
|
|
||||||
// equivalently, a random 64 bit integer encoded in big-endian order).
|
|
||||||
key = make([]byte, 8)
|
|
||||||
for i := 0; i < 8; i++ {
|
|
||||||
key[i] = byte(rand.Intn(256))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client handshake described in (soon obsolete)
|
|
||||||
// draft-ietf-hybi-thewebsocket-protocol-00
|
|
||||||
// (draft-hixie-thewebsocket-protocol-76)
|
|
||||||
func hixie76ClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
|
|
||||||
switch config.Version {
|
|
||||||
case ProtocolVersionHixie76, ProtocolVersionHybi00:
|
|
||||||
default:
|
|
||||||
panic("wrong protocol version.")
|
|
||||||
}
|
|
||||||
// 4.1. Opening handshake.
|
|
||||||
// Step 5. send a request line.
|
|
||||||
bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
|
|
||||||
|
|
||||||
// Step 6-14. push request headers in fields.
|
|
||||||
fields := []string{
|
|
||||||
"Upgrade: WebSocket\r\n",
|
|
||||||
"Connection: Upgrade\r\n",
|
|
||||||
"Host: " + config.Location.Host + "\r\n",
|
|
||||||
"Origin: " + config.Origin.String() + "\r\n",
|
|
||||||
}
|
|
||||||
if len(config.Protocol) > 0 {
|
|
||||||
if len(config.Protocol) != 1 {
|
|
||||||
return ErrBadWebSocketProtocol
|
|
||||||
}
|
|
||||||
fields = append(fields, "Sec-WebSocket-Protocol: "+config.Protocol[0]+"\r\n")
|
|
||||||
}
|
|
||||||
// TODO(ukai): Step 15. send cookie if any.
|
|
||||||
|
|
||||||
// Step 16-23. generate keys and push Sec-WebSocket-Key<n> in fields.
|
|
||||||
key1, number1 := generateKeyNumber()
|
|
||||||
key2, number2 := generateKeyNumber()
|
|
||||||
if config.handshakeData != nil {
|
|
||||||
key1 = config.handshakeData["key1"]
|
|
||||||
n, err := strconv.ParseUint(config.handshakeData["number1"], 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
number1 = uint32(n)
|
|
||||||
key2 = config.handshakeData["key2"]
|
|
||||||
n, err = strconv.ParseUint(config.handshakeData["number2"], 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
number2 = uint32(n)
|
|
||||||
}
|
|
||||||
fields = append(fields, "Sec-WebSocket-Key1: "+key1+"\r\n")
|
|
||||||
fields = append(fields, "Sec-WebSocket-Key2: "+key2+"\r\n")
|
|
||||||
|
|
||||||
// Step 24. shuffle fields and send them out.
|
|
||||||
for i := 1; i < len(fields); i++ {
|
|
||||||
j := rand.Intn(i)
|
|
||||||
fields[i], fields[j] = fields[j], fields[i]
|
|
||||||
}
|
|
||||||
for i := 0; i < len(fields); i++ {
|
|
||||||
bw.WriteString(fields[i])
|
|
||||||
}
|
|
||||||
// Step 25. send CRLF.
|
|
||||||
bw.WriteString("\r\n")
|
|
||||||
|
|
||||||
// Step 26. generate 8 bytes random key.
|
|
||||||
key3 := generateKey3()
|
|
||||||
if config.handshakeData != nil {
|
|
||||||
key3 = []byte(config.handshakeData["key3"])
|
|
||||||
}
|
|
||||||
// Step 27. send it out.
|
|
||||||
bw.Write(key3)
|
|
||||||
if err = bw.Flush(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 28-29, 32-40. read response from server.
|
|
||||||
resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Step 30. check response code is 101.
|
|
||||||
if resp.StatusCode != 101 {
|
|
||||||
return ErrBadStatus
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 41. check websocket headers.
|
|
||||||
if resp.Header.Get("Upgrade") != "WebSocket" ||
|
|
||||||
strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
|
|
||||||
return ErrBadUpgrade
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.Header.Get("Sec-Websocket-Origin") != config.Origin.String() {
|
|
||||||
return ErrBadWebSocketOrigin
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.Header.Get("Sec-Websocket-Location") != config.Location.String() {
|
|
||||||
return ErrBadWebSocketLocation
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(config.Protocol) > 0 && resp.Header.Get("Sec-Websocket-Protocol") != config.Protocol[0] {
|
|
||||||
return ErrBadWebSocketProtocol
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 42-43. get expected data from challenge data.
|
|
||||||
expected, err := getChallengeResponse(number1, number2, key3)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 44. read 16 bytes from server.
|
|
||||||
reply := make([]byte, 16)
|
|
||||||
if _, err = io.ReadFull(br, reply); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 45. check the reply equals to expected data.
|
|
||||||
if !bytes.Equal(expected, reply) {
|
|
||||||
return ErrChallengeResponse
|
|
||||||
}
|
|
||||||
// WebSocket connection is established.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client Handshake described in (soon obsolete)
|
|
||||||
// draft-hixie-thewebsocket-protocol-75.
|
|
||||||
func hixie75ClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
|
|
||||||
if config.Version != ProtocolVersionHixie75 {
|
|
||||||
panic("wrong protocol version.")
|
|
||||||
}
|
|
||||||
bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
|
|
||||||
bw.WriteString("Upgrade: WebSocket\r\n")
|
|
||||||
bw.WriteString("Connection: Upgrade\r\n")
|
|
||||||
bw.WriteString("Host: " + config.Location.Host + "\r\n")
|
|
||||||
bw.WriteString("Origin: " + config.Origin.String() + "\r\n")
|
|
||||||
if len(config.Protocol) > 0 {
|
|
||||||
if len(config.Protocol) != 1 {
|
|
||||||
return ErrBadWebSocketProtocol
|
|
||||||
}
|
|
||||||
bw.WriteString("WebSocket-Protocol: " + config.Protocol[0] + "\r\n")
|
|
||||||
}
|
|
||||||
bw.WriteString("\r\n")
|
|
||||||
bw.Flush()
|
|
||||||
resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if resp.Status != "101 Web Socket Protocol Handshake" {
|
|
||||||
return ErrBadStatus
|
|
||||||
}
|
|
||||||
if resp.Header.Get("Upgrade") != "WebSocket" ||
|
|
||||||
resp.Header.Get("Connection") != "Upgrade" {
|
|
||||||
return ErrBadUpgrade
|
|
||||||
}
|
|
||||||
if resp.Header.Get("Websocket-Origin") != config.Origin.String() {
|
|
||||||
return ErrBadWebSocketOrigin
|
|
||||||
}
|
|
||||||
if resp.Header.Get("Websocket-Location") != config.Location.String() {
|
|
||||||
return ErrBadWebSocketLocation
|
|
||||||
}
|
|
||||||
if len(config.Protocol) > 0 && resp.Header.Get("Websocket-Protocol") != config.Protocol[0] {
|
|
||||||
return ErrBadWebSocketProtocol
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// newHixieClientConn returns new WebSocket connection speaking hixie draft protocol.
|
|
||||||
func newHixieClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
|
|
||||||
return newHixieConn(config, buf, rwc, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gets key number from Sec-WebSocket-Key<n>: field as described
|
|
||||||
// in 5.2 Sending the server's opening handshake, 4.
|
|
||||||
func getKeyNumber(s string) (r uint32) {
|
|
||||||
// 4. Let /key-number_n/ be the digits (characters in the range
|
|
||||||
// U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9)) in /key_1/,
|
|
||||||
// interpreted as a base ten integer, ignoring all other characters
|
|
||||||
// in /key_n/.
|
|
||||||
r = 0
|
|
||||||
for i := 0; i < len(s); i++ {
|
|
||||||
if s[i] >= '0' && s[i] <= '9' {
|
|
||||||
r = r*10 + uint32(s[i]) - '0'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Hixie76ServerHandshaker performs a server handshake using
|
|
||||||
// hixie draft 76 protocol.
|
|
||||||
type hixie76ServerHandshaker struct {
|
|
||||||
*Config
|
|
||||||
challengeResponse []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *hixie76ServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) {
|
|
||||||
c.Version = ProtocolVersionHybi00
|
|
||||||
if req.Method != "GET" {
|
|
||||||
return http.StatusMethodNotAllowed, ErrBadRequestMethod
|
|
||||||
}
|
|
||||||
// HTTP version can be safely ignored.
|
|
||||||
|
|
||||||
if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
|
|
||||||
strings.ToLower(req.Header.Get("Connection")) != "upgrade" {
|
|
||||||
return http.StatusBadRequest, ErrNotWebSocket
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(ukai): check Host
|
|
||||||
c.Origin, err = url.ParseRequestURI(req.Header.Get("Origin"))
|
|
||||||
if err != nil {
|
|
||||||
return http.StatusBadRequest, err
|
|
||||||
}
|
|
||||||
|
|
||||||
key1 := req.Header.Get("Sec-Websocket-Key1")
|
|
||||||
if key1 == "" {
|
|
||||||
return http.StatusBadRequest, ErrChallengeResponse
|
|
||||||
}
|
|
||||||
key2 := req.Header.Get("Sec-Websocket-Key2")
|
|
||||||
if key2 == "" {
|
|
||||||
return http.StatusBadRequest, ErrChallengeResponse
|
|
||||||
}
|
|
||||||
key3 := make([]byte, 8)
|
|
||||||
if _, err := io.ReadFull(buf, key3); err != nil {
|
|
||||||
return http.StatusBadRequest, ErrChallengeResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
var scheme string
|
|
||||||
if req.TLS != nil {
|
|
||||||
scheme = "wss"
|
|
||||||
} else {
|
|
||||||
scheme = "ws"
|
|
||||||
}
|
|
||||||
c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI())
|
|
||||||
if err != nil {
|
|
||||||
return http.StatusBadRequest, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 4. get key number in Sec-WebSocket-Key<n> fields.
|
|
||||||
keyNumber1 := getKeyNumber(key1)
|
|
||||||
keyNumber2 := getKeyNumber(key2)
|
|
||||||
|
|
||||||
// Step 5. get number of spaces in Sec-WebSocket-Key<n> fields.
|
|
||||||
space1 := uint32(strings.Count(key1, " "))
|
|
||||||
space2 := uint32(strings.Count(key2, " "))
|
|
||||||
if space1 == 0 || space2 == 0 {
|
|
||||||
return http.StatusBadRequest, ErrChallengeResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 6. key number must be an integral multiple of spaces.
|
|
||||||
if keyNumber1%space1 != 0 || keyNumber2%space2 != 0 {
|
|
||||||
return http.StatusBadRequest, ErrChallengeResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 7. let part be key number divided by spaces.
|
|
||||||
part1 := keyNumber1 / space1
|
|
||||||
part2 := keyNumber2 / space2
|
|
||||||
|
|
||||||
// Step 8. let challenge be concatenation of part1, part2 and key3.
|
|
||||||
// Step 9. get MD5 fingerprint of challenge.
|
|
||||||
c.challengeResponse, err = getChallengeResponse(part1, part2, key3)
|
|
||||||
if err != nil {
|
|
||||||
return http.StatusInternalServerError, err
|
|
||||||
}
|
|
||||||
protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
|
|
||||||
protocols := strings.Split(protocol, ",")
|
|
||||||
for i := 0; i < len(protocols); i++ {
|
|
||||||
c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
|
|
||||||
}
|
|
||||||
|
|
||||||
return http.StatusSwitchingProtocols, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *hixie76ServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
|
|
||||||
if len(c.Protocol) > 0 {
|
|
||||||
if len(c.Protocol) != 1 {
|
|
||||||
return ErrBadWebSocketProtocol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 10. send response status line.
|
|
||||||
buf.WriteString("HTTP/1.1 101 WebSocket Protocol Handshake\r\n")
|
|
||||||
// Step 11. send response headers.
|
|
||||||
buf.WriteString("Upgrade: WebSocket\r\n")
|
|
||||||
buf.WriteString("Connection: Upgrade\r\n")
|
|
||||||
buf.WriteString("Sec-WebSocket-Origin: " + c.Origin.String() + "\r\n")
|
|
||||||
buf.WriteString("Sec-WebSocket-Location: " + c.Location.String() + "\r\n")
|
|
||||||
if len(c.Protocol) > 0 {
|
|
||||||
buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n")
|
|
||||||
}
|
|
||||||
// Step 12. send CRLF.
|
|
||||||
buf.WriteString("\r\n")
|
|
||||||
// Step 13. send response data.
|
|
||||||
buf.Write(c.challengeResponse)
|
|
||||||
return buf.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *hixie76ServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn) {
|
|
||||||
return newHixieServerConn(c.Config, buf, rwc, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A hixie75ServerHandshaker performs a server handshake using
|
|
||||||
// hixie draft 75 protocol.
|
|
||||||
type hixie75ServerHandshaker struct {
|
|
||||||
*Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *hixie75ServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) {
|
|
||||||
c.Version = ProtocolVersionHixie75
|
|
||||||
if req.Method != "GET" || req.Proto != "HTTP/1.1" {
|
|
||||||
return http.StatusMethodNotAllowed, ErrBadRequestMethod
|
|
||||||
}
|
|
||||||
if req.Header.Get("Upgrade") != "WebSocket" {
|
|
||||||
return http.StatusBadRequest, ErrNotWebSocket
|
|
||||||
}
|
|
||||||
if req.Header.Get("Connection") != "Upgrade" {
|
|
||||||
return http.StatusBadRequest, ErrNotWebSocket
|
|
||||||
}
|
|
||||||
c.Origin, err = url.ParseRequestURI(strings.TrimSpace(req.Header.Get("Origin")))
|
|
||||||
if err != nil {
|
|
||||||
return http.StatusBadRequest, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var scheme string
|
|
||||||
if req.TLS != nil {
|
|
||||||
scheme = "wss"
|
|
||||||
} else {
|
|
||||||
scheme = "ws"
|
|
||||||
}
|
|
||||||
c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI())
|
|
||||||
if err != nil {
|
|
||||||
return http.StatusBadRequest, err
|
|
||||||
}
|
|
||||||
protocol := strings.TrimSpace(req.Header.Get("Websocket-Protocol"))
|
|
||||||
protocols := strings.Split(protocol, ",")
|
|
||||||
for i := 0; i < len(protocols); i++ {
|
|
||||||
c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
|
|
||||||
}
|
|
||||||
|
|
||||||
return http.StatusSwitchingProtocols, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *hixie75ServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
|
|
||||||
if len(c.Protocol) > 0 {
|
|
||||||
if len(c.Protocol) != 1 {
|
|
||||||
return ErrBadWebSocketProtocol
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.WriteString("HTTP/1.1 101 Web Socket Protocol Handshake\r\n")
|
|
||||||
buf.WriteString("Upgrade: WebSocket\r\n")
|
|
||||||
buf.WriteString("Connection: Upgrade\r\n")
|
|
||||||
buf.WriteString("WebSocket-Origin: " + c.Origin.String() + "\r\n")
|
|
||||||
buf.WriteString("WebSocket-Location: " + c.Location.String() + "\r\n")
|
|
||||||
if len(c.Protocol) > 0 {
|
|
||||||
buf.WriteString("WebSocket-Protocol: " + c.Protocol[0] + "\r\n")
|
|
||||||
}
|
|
||||||
buf.WriteString("\r\n")
|
|
||||||
return buf.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *hixie75ServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn) {
|
|
||||||
return newHixieServerConn(c.Config, buf, rwc, request)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newHixieServerConn returns a new WebSocket connection speaking hixie draft protocol.
|
|
||||||
func newHixieServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
|
|
||||||
return newHixieConn(config, buf, rwc, request)
|
|
||||||
}
|
|
|
@ -43,26 +43,12 @@ func NewConfig(server, origin string) (config *Config, err error) {
|
||||||
func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) {
|
func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) {
|
||||||
br := bufio.NewReader(rwc)
|
br := bufio.NewReader(rwc)
|
||||||
bw := bufio.NewWriter(rwc)
|
bw := bufio.NewWriter(rwc)
|
||||||
switch config.Version {
|
err = hybiClientHandshake(config, br, bw)
|
||||||
case ProtocolVersionHixie75:
|
|
||||||
err = hixie75ClientHandshake(config, br, bw)
|
|
||||||
case ProtocolVersionHixie76, ProtocolVersionHybi00:
|
|
||||||
err = hixie76ClientHandshake(config, br, bw)
|
|
||||||
case ProtocolVersionHybi08, ProtocolVersionHybi13:
|
|
||||||
err = hybiClientHandshake(config, br, bw)
|
|
||||||
default:
|
|
||||||
err = ErrBadProtocolVersion
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
buf := bufio.NewReadWriter(br, bw)
|
buf := bufio.NewReadWriter(br, bw)
|
||||||
switch config.Version {
|
ws = newHybiClientConn(config, buf, rwc)
|
||||||
case ProtocolVersionHixie75, ProtocolVersionHixie76, ProtocolVersionHybi00:
|
|
||||||
ws = newHixieClientConn(config, buf, rwc)
|
|
||||||
case ProtocolVersionHybi08, ProtocolVersionHybi13:
|
|
||||||
ws = newHybiClientConn(config, buf, rwc)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +64,20 @@ func Dial(url_, protocol, origin string) (ws *Conn, err error) {
|
||||||
return DialConfig(config)
|
return DialConfig(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var portMap = map[string]string{
|
||||||
|
"ws": "80",
|
||||||
|
"wss": "443",
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseAuthority(location *url.URL) string {
|
||||||
|
if _, ok := portMap[location.Scheme]; ok {
|
||||||
|
if _, _, err := net.SplitHostPort(location.Host); err != nil {
|
||||||
|
return net.JoinHostPort(location.Host, portMap[location.Scheme])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return location.Host
|
||||||
|
}
|
||||||
|
|
||||||
// DialConfig opens a new client connection to a WebSocket with a config.
|
// DialConfig opens a new client connection to a WebSocket with a config.
|
||||||
func DialConfig(config *Config) (ws *Conn, err error) {
|
func DialConfig(config *Config) (ws *Conn, err error) {
|
||||||
var client net.Conn
|
var client net.Conn
|
||||||
|
@ -89,10 +89,10 @@ func DialConfig(config *Config) (ws *Conn, err error) {
|
||||||
}
|
}
|
||||||
switch config.Location.Scheme {
|
switch config.Location.Scheme {
|
||||||
case "ws":
|
case "ws":
|
||||||
client, err = net.Dial("tcp", config.Location.Host)
|
client, err = net.Dial("tcp", parseAuthority(config.Location))
|
||||||
|
|
||||||
case "wss":
|
case "wss":
|
||||||
client, err = tls.Dial("tcp", config.Location.Host, config.TlsConfig)
|
client, err = tls.Dial("tcp", parseAuthority(config.Location), config.TlsConfig)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = ErrBadScheme
|
err = ErrBadScheme
|
||||||
|
@ -103,6 +103,7 @@ func DialConfig(config *Config) (ws *Conn, err error) {
|
||||||
|
|
||||||
ws, err = NewClient(config, client)
|
ws, err = NewClient(config, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
client.Close()
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
return
|
return
|
|
@ -385,21 +385,8 @@ func getNonceAccept(nonce []byte) (expected []byte, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func isHybiVersion(version int) bool {
|
|
||||||
switch version {
|
|
||||||
case ProtocolVersionHybi08, ProtocolVersionHybi13:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17
|
// Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17
|
||||||
func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
|
func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
|
||||||
if !isHybiVersion(config.Version) {
|
|
||||||
panic("wrong protocol version.")
|
|
||||||
}
|
|
||||||
|
|
||||||
bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
|
bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
|
||||||
|
|
||||||
bw.WriteString("Host: " + config.Location.Host + "\r\n")
|
bw.WriteString("Host: " + config.Location.Host + "\r\n")
|
||||||
|
@ -410,11 +397,12 @@ func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (er
|
||||||
nonce = []byte(config.handshakeData["key"])
|
nonce = []byte(config.handshakeData["key"])
|
||||||
}
|
}
|
||||||
bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n")
|
bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n")
|
||||||
if config.Version == ProtocolVersionHybi13 {
|
bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n")
|
||||||
bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n")
|
|
||||||
} else if config.Version == ProtocolVersionHybi08 {
|
if config.Version != ProtocolVersionHybi13 {
|
||||||
bw.WriteString("Sec-WebSocket-Origin: " + strings.ToLower(config.Origin.String()) + "\r\n")
|
return ErrBadProtocolVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n")
|
bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n")
|
||||||
if len(config.Protocol) > 0 {
|
if len(config.Protocol) > 0 {
|
||||||
bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n")
|
bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n")
|
||||||
|
@ -500,8 +488,6 @@ func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Reques
|
||||||
switch version {
|
switch version {
|
||||||
case "13":
|
case "13":
|
||||||
c.Version = ProtocolVersionHybi13
|
c.Version = ProtocolVersionHybi13
|
||||||
case "8":
|
|
||||||
c.Version = ProtocolVersionHybi08
|
|
||||||
default:
|
default:
|
||||||
return http.StatusBadRequest, ErrBadWebSocketVersion
|
return http.StatusBadRequest, ErrBadWebSocketVersion
|
||||||
}
|
}
|
||||||
|
@ -536,8 +522,6 @@ func Origin(config *Config, req *http.Request) (*url.URL, error) {
|
||||||
switch config.Version {
|
switch config.Version {
|
||||||
case ProtocolVersionHybi13:
|
case ProtocolVersionHybi13:
|
||||||
origin = req.Header.Get("Origin")
|
origin = req.Header.Get("Origin")
|
||||||
case ProtocolVersionHybi08:
|
|
||||||
origin = req.Header.Get("Sec-Websocket-Origin")
|
|
||||||
}
|
}
|
||||||
if origin == "null" {
|
if origin == "null" {
|
||||||
return nil, nil
|
return nil, nil
|
|
@ -22,14 +22,6 @@ func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Requ
|
||||||
buf.Flush()
|
buf.Flush()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
hs = &hixie76ServerHandshaker{Config: config}
|
|
||||||
code, err = hs.ReadHandshake(buf.Reader, req)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
hs = &hixie75ServerHandshaker{Config: config}
|
|
||||||
code, err = hs.ReadHandshake(buf.Reader, req)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
|
fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
|
||||||
buf.WriteString("\r\n")
|
buf.WriteString("\r\n")
|
||||||
|
@ -103,8 +95,8 @@ func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) {
|
||||||
// You might want to verify websocket.Conn.Config().Origin in the func.
|
// You might want to verify websocket.Conn.Config().Origin in the func.
|
||||||
// If you use Server instead of Handler, you could call websocket.Origin and
|
// If you use Server instead of Handler, you could call websocket.Origin and
|
||||||
// check the origin in your Handshake func. So, if you want to accept
|
// check the origin in your Handshake func. So, if you want to accept
|
||||||
// non-browser client, which doesn't send Origin header, you could use Server
|
// non-browser clients, which do not send an Origin header, set a
|
||||||
//. that doesn't check origin in its Handshake.
|
// Server.Handshake that does not check the origin.
|
||||||
type Handler func(*Conn)
|
type Handler func(*Conn)
|
||||||
|
|
||||||
func checkOrigin(config *Config, req *http.Request) (err error) {
|
func checkOrigin(config *Config, req *http.Request) (err error) {
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
// Package websocket implements a client and server for the WebSocket protocol
|
// Package websocket implements a client and server for the WebSocket protocol
|
||||||
// as specified in RFC 6455.
|
// as specified in RFC 6455.
|
||||||
package websocket
|
package websocket // import "golang.org/x/net/websocket"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
@ -21,13 +21,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ProtocolVersionHixie75 = -75
|
|
||||||
ProtocolVersionHixie76 = -76
|
|
||||||
ProtocolVersionHybi00 = 0
|
|
||||||
ProtocolVersionHybi08 = 8
|
|
||||||
ProtocolVersionHybi13 = 13
|
ProtocolVersionHybi13 = 13
|
||||||
ProtocolVersionHybi = ProtocolVersionHybi13
|
ProtocolVersionHybi = ProtocolVersionHybi13
|
||||||
SupportedProtocolVersion = "13, 8"
|
SupportedProtocolVersion = "13"
|
||||||
|
|
||||||
ContinuationFrame = 0
|
ContinuationFrame = 0
|
||||||
TextFrame = 1
|
TextFrame = 1
|
||||||
|
@ -133,7 +129,7 @@ type frameReaderFactory interface {
|
||||||
|
|
||||||
// frameWriter is an interface to write a WebSocket frame.
|
// frameWriter is an interface to write a WebSocket frame.
|
||||||
type frameWriter interface {
|
type frameWriter interface {
|
||||||
// Writer is to write playload of the frame.
|
// Writer is to write payload of the frame.
|
||||||
io.WriteCloser
|
io.WriteCloser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,10 +216,11 @@ func (ws *Conn) Write(msg []byte) (n int, err error) {
|
||||||
// Close implements the io.Closer interface.
|
// Close implements the io.Closer interface.
|
||||||
func (ws *Conn) Close() error {
|
func (ws *Conn) Close() error {
|
||||||
err := ws.frameHandler.WriteClose(ws.defaultCloseStatus)
|
err := ws.frameHandler.WriteClose(ws.defaultCloseStatus)
|
||||||
|
err1 := ws.rwc.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return ws.rwc.Close()
|
return err1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *Conn) IsClientConn() bool { return ws.request == nil }
|
func (ws *Conn) IsClientConn() bool { return ws.request == nil }
|
Loading…
Add table
Add a link
Reference in a new issue