mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-30 21:30:16 +00:00 
			
		
		
		
	Update etcd client to 3.3.9
This commit is contained in:
		
							
								
								
									
										3
									
								
								vendor/github.com/gorilla/websocket/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/gorilla/websocket/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -20,3 +20,6 @@ _cgo_export.* | ||||
| _testmain.go | ||||
|  | ||||
| *.exe | ||||
|  | ||||
| .idea/ | ||||
| *.iml | ||||
							
								
								
									
										22
									
								
								vendor/github.com/gorilla/websocket/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/gorilla/websocket/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,6 +1,20 @@ | ||||
| language: go | ||||
| sudo: false | ||||
|  | ||||
| go: | ||||
|   - 1.1 | ||||
|   - 1.2 | ||||
|   - tip | ||||
| matrix: | ||||
|   include: | ||||
|     - go: 1.4 | ||||
|     - go: 1.5 | ||||
|     - go: 1.6 | ||||
|     - go: 1.7 | ||||
|     - go: 1.8 | ||||
|     - go: 1.9 | ||||
|     - go: tip | ||||
|   allow_failures: | ||||
|     - go: tip | ||||
|  | ||||
| script: | ||||
|   - go get -t -v ./... | ||||
|   - diff -u <(echo -n) <(gofmt -d .) | ||||
|   - go vet $(go list ./... | grep -v /vendor/) | ||||
|   - go test -v -race ./... | ||||
|   | ||||
							
								
								
									
										7
									
								
								vendor/github.com/gorilla/websocket/BUILD
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/gorilla/websocket/BUILD
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -4,9 +4,16 @@ go_library( | ||||
|     name = "go_default_library", | ||||
|     srcs = [ | ||||
|         "client.go", | ||||
|         "client_clone.go", | ||||
|         "client_clone_legacy.go", | ||||
|         "compression.go", | ||||
|         "conn.go", | ||||
|         "conn_read.go", | ||||
|         "conn_read_legacy.go", | ||||
|         "doc.go", | ||||
|         "json.go", | ||||
|         "mask.go", | ||||
|         "prepared.go", | ||||
|         "server.go", | ||||
|         "util.go", | ||||
|     ], | ||||
|   | ||||
							
								
								
									
										7
									
								
								vendor/github.com/gorilla/websocket/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/gorilla/websocket/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,10 +3,15 @@ | ||||
| Gorilla WebSocket is a [Go](http://golang.org/) implementation of the | ||||
| [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. | ||||
|  | ||||
| [](https://travis-ci.org/gorilla/websocket) | ||||
| [](https://godoc.org/github.com/gorilla/websocket) | ||||
|  | ||||
| ### Documentation | ||||
|  | ||||
| * [API Reference](http://godoc.org/github.com/gorilla/websocket) | ||||
| * [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat) | ||||
| * [Command example](https://github.com/gorilla/websocket/tree/master/examples/command) | ||||
| * [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo) | ||||
| * [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch) | ||||
|  | ||||
| ### Status | ||||
| @@ -41,7 +46,7 @@ subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn | ||||
| <tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">pings</a> and receive <a href="https://tools.ietf.org/html/rfc6455#section-5.5.3">pongs</a></td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td>No</td></tr> | ||||
| <tr><td>Get the <a href="https://tools.ietf.org/html/rfc6455#section-5.6">type</a> of a received data message</td><td>Yes</td><td>Yes, see note 2</td></tr> | ||||
| <tr><td colspan="3">Other Features</tr></td> | ||||
| <tr><td>Limit size of received message</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.SetReadLimit">Yes</a></td><td><a href="https://code.google.com/p/go/issues/detail?id=5082">No</a></td></tr> | ||||
| <tr><td><a href="https://tools.ietf.org/html/rfc7692">Compression Extensions</a></td><td>Experimental</td><td>No</td></tr> | ||||
| <tr><td>Read message using io.Reader</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextReader">Yes</a></td><td>No, see note 3</td></tr> | ||||
| <tr><td>Write message using io.WriteCloser</td><td><a href="http://godoc.org/github.com/gorilla/websocket#Conn.NextWriter">Yes</a></td><td>No, see note 3</td></tr> | ||||
| </table> | ||||
|   | ||||
							
								
								
									
										331
									
								
								vendor/github.com/gorilla/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										331
									
								
								vendor/github.com/gorilla/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -5,8 +5,10 @@ | ||||
| package websocket | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"crypto/tls" | ||||
| 	"encoding/base64" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| @@ -21,6 +23,8 @@ import ( | ||||
| // invalid. | ||||
| var ErrBadHandshake = errors.New("websocket: bad handshake") | ||||
|  | ||||
| var errInvalidCompression = errors.New("websocket: invalid compression negotiation") | ||||
|  | ||||
| // NewClient creates a new client connection using the given net connection. | ||||
| // The URL u specifies the host and request URI. Use requestHeader to specify | ||||
| // the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies | ||||
| @@ -30,50 +34,17 @@ var ErrBadHandshake = errors.New("websocket: bad handshake") | ||||
| // If the WebSocket handshake fails, ErrBadHandshake is returned along with a | ||||
| // non-nil *http.Response so that callers can handle redirects, authentication, | ||||
| // etc. | ||||
| // | ||||
| // Deprecated: Use Dialer instead. | ||||
| func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) { | ||||
| 	challengeKey, err := generateChallengeKey() | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	d := Dialer{ | ||||
| 		ReadBufferSize:  readBufSize, | ||||
| 		WriteBufferSize: writeBufSize, | ||||
| 		NetDial: func(net, addr string) (net.Conn, error) { | ||||
| 			return netConn, nil | ||||
| 		}, | ||||
| 	} | ||||
| 	acceptKey := computeAcceptKey(challengeKey) | ||||
|  | ||||
| 	c = newConn(netConn, false, readBufSize, writeBufSize) | ||||
| 	p := c.writeBuf[:0] | ||||
| 	p = append(p, "GET "...) | ||||
| 	p = append(p, u.RequestURI()...) | ||||
| 	p = append(p, " HTTP/1.1\r\nHost: "...) | ||||
| 	p = append(p, u.Host...) | ||||
| 	// "Upgrade" is capitalized for servers that do not use case insensitive | ||||
| 	// comparisons on header tokens. | ||||
| 	p = append(p, "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: "...) | ||||
| 	p = append(p, challengeKey...) | ||||
| 	p = append(p, "\r\n"...) | ||||
| 	for k, vs := range requestHeader { | ||||
| 		for _, v := range vs { | ||||
| 			p = append(p, k...) | ||||
| 			p = append(p, ": "...) | ||||
| 			p = append(p, v...) | ||||
| 			p = append(p, "\r\n"...) | ||||
| 		} | ||||
| 	} | ||||
| 	p = append(p, "\r\n"...) | ||||
|  | ||||
| 	if _, err := netConn.Write(p); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	resp, err := http.ReadResponse(c.br, &http.Request{Method: "GET", URL: u}) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	if resp.StatusCode != 101 || | ||||
| 		!strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") || | ||||
| 		!strings.EqualFold(resp.Header.Get("Connection"), "upgrade") || | ||||
| 		resp.Header.Get("Sec-Websocket-Accept") != acceptKey { | ||||
| 		return nil, resp, ErrBadHandshake | ||||
| 	} | ||||
| 	c.subprotocol = resp.Header.Get("Sec-Websocket-Protocol") | ||||
| 	return c, resp, nil | ||||
| 	return d.Dial(u.String(), requestHeader) | ||||
| } | ||||
|  | ||||
| // A Dialer contains options for connecting to WebSocket server. | ||||
| @@ -82,6 +53,12 @@ type Dialer struct { | ||||
| 	// NetDial is nil, net.Dial is used. | ||||
| 	NetDial func(network, addr string) (net.Conn, error) | ||||
|  | ||||
| 	// Proxy specifies a function to return a proxy for a given | ||||
| 	// Request. If the function returns a non-nil error, the | ||||
| 	// request is aborted with the provided error. | ||||
| 	// If Proxy is nil or returns a nil *URL, no proxy is used. | ||||
| 	Proxy func(*http.Request) (*url.URL, error) | ||||
|  | ||||
| 	// TLSClientConfig specifies the TLS configuration to use with tls.Client. | ||||
| 	// If nil, the default configuration is used. | ||||
| 	TLSClientConfig *tls.Config | ||||
| @@ -89,28 +66,37 @@ type Dialer struct { | ||||
| 	// HandshakeTimeout specifies the duration for the handshake to complete. | ||||
| 	HandshakeTimeout time.Duration | ||||
|  | ||||
| 	// Input and output buffer sizes. If the buffer size is zero, then a | ||||
| 	// default value of 4096 is used. | ||||
| 	// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer | ||||
| 	// size is zero, then a useful default size is used. The I/O buffer sizes | ||||
| 	// do not limit the size of the messages that can be sent or received. | ||||
| 	ReadBufferSize, WriteBufferSize int | ||||
|  | ||||
| 	// Subprotocols specifies the client's requested subprotocols. | ||||
| 	Subprotocols []string | ||||
|  | ||||
| 	// EnableCompression specifies if the client should attempt to negotiate | ||||
| 	// per message compression (RFC 7692). Setting this value to true does not | ||||
| 	// guarantee that compression will be supported. Currently only "no context | ||||
| 	// takeover" modes are supported. | ||||
| 	EnableCompression bool | ||||
|  | ||||
| 	// Jar specifies the cookie jar. | ||||
| 	// If Jar is nil, cookies are not sent in requests and ignored | ||||
| 	// in responses. | ||||
| 	Jar http.CookieJar | ||||
| } | ||||
|  | ||||
| var errMalformedURL = errors.New("malformed ws or wss URL") | ||||
|  | ||||
| // parseURL parses the URL. The url.Parse function is not used here because | ||||
| // url.Parse mangles the path. | ||||
| // parseURL parses the URL. | ||||
| // | ||||
| // This function is a replacement for the standard library url.Parse function. | ||||
| // In Go 1.4 and earlier, url.Parse loses information from the path. | ||||
| func parseURL(s string) (*url.URL, error) { | ||||
| 	// From the RFC: | ||||
| 	// | ||||
| 	// ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ] | ||||
| 	// wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ] | ||||
| 	// | ||||
| 	// We don't use the net/url parser here because the dialer interface does | ||||
| 	// not provide a way for applications to work around percent deocding in | ||||
| 	// the net/url parser. | ||||
|  | ||||
| 	var u url.URL | ||||
| 	switch { | ||||
| 	case strings.HasPrefix(s, "ws://"): | ||||
| @@ -123,15 +109,23 @@ func parseURL(s string) (*url.URL, error) { | ||||
| 		return nil, errMalformedURL | ||||
| 	} | ||||
|  | ||||
| 	u.Host = s | ||||
| 	u.Opaque = "/" | ||||
| 	if i := strings.Index(s, "/"); i >= 0 { | ||||
| 		u.Host = s[:i] | ||||
| 		u.Opaque = s[i:] | ||||
| 	if i := strings.Index(s, "?"); i >= 0 { | ||||
| 		u.RawQuery = s[i+1:] | ||||
| 		s = s[:i] | ||||
| 	} | ||||
|  | ||||
| 	if i := strings.Index(s, "/"); i >= 0 { | ||||
| 		u.Opaque = s[i:] | ||||
| 		s = s[:i] | ||||
| 	} else { | ||||
| 		u.Opaque = "/" | ||||
| 	} | ||||
|  | ||||
| 	u.Host = s | ||||
|  | ||||
| 	if strings.Contains(u.Host, "@") { | ||||
| 		// WebSocket URIs do not contain user information. | ||||
| 		// Don't bother parsing user information because user information is | ||||
| 		// not allowed in websocket URIs. | ||||
| 		return nil, errMalformedURL | ||||
| 	} | ||||
|  | ||||
| @@ -144,9 +138,12 @@ func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) { | ||||
| 	if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") { | ||||
| 		hostNoPort = hostNoPort[:i] | ||||
| 	} else { | ||||
| 		if u.Scheme == "wss" { | ||||
| 		switch u.Scheme { | ||||
| 		case "wss": | ||||
| 			hostPort += ":443" | ||||
| 		} else { | ||||
| 		case "https": | ||||
| 			hostPort += ":443" | ||||
| 		default: | ||||
| 			hostPort += ":80" | ||||
| 		} | ||||
| 	} | ||||
| @@ -154,7 +151,9 @@ func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) { | ||||
| } | ||||
|  | ||||
| // DefaultDialer is a dialer with all fields set to the default zero values. | ||||
| var DefaultDialer *Dialer | ||||
| var DefaultDialer = &Dialer{ | ||||
| 	Proxy: http.ProxyFromEnvironment, | ||||
| } | ||||
|  | ||||
| // Dial creates a new client connection. Use requestHeader to specify the | ||||
| // origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie). | ||||
| @@ -166,15 +165,103 @@ var DefaultDialer *Dialer | ||||
| // etcetera. The response body may not contain the entire response and does not | ||||
| // need to be closed by the application. | ||||
| func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) { | ||||
|  | ||||
| 	if d == nil { | ||||
| 		d = &Dialer{ | ||||
| 			Proxy: http.ProxyFromEnvironment, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	challengeKey, err := generateChallengeKey() | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	u, err := parseURL(urlStr) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	switch u.Scheme { | ||||
| 	case "ws": | ||||
| 		u.Scheme = "http" | ||||
| 	case "wss": | ||||
| 		u.Scheme = "https" | ||||
| 	default: | ||||
| 		return nil, nil, errMalformedURL | ||||
| 	} | ||||
|  | ||||
| 	if u.User != nil { | ||||
| 		// User name and password are not allowed in websocket URIs. | ||||
| 		return nil, nil, errMalformedURL | ||||
| 	} | ||||
|  | ||||
| 	req := &http.Request{ | ||||
| 		Method:     "GET", | ||||
| 		URL:        u, | ||||
| 		Proto:      "HTTP/1.1", | ||||
| 		ProtoMajor: 1, | ||||
| 		ProtoMinor: 1, | ||||
| 		Header:     make(http.Header), | ||||
| 		Host:       u.Host, | ||||
| 	} | ||||
|  | ||||
| 	// Set the cookies present in the cookie jar of the dialer | ||||
| 	if d.Jar != nil { | ||||
| 		for _, cookie := range d.Jar.Cookies(u) { | ||||
| 			req.AddCookie(cookie) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Set the request headers using the capitalization for names and values in | ||||
| 	// RFC examples. Although the capitalization shouldn't matter, there are | ||||
| 	// servers that depend on it. The Header.Set method is not used because the | ||||
| 	// method canonicalizes the header names. | ||||
| 	req.Header["Upgrade"] = []string{"websocket"} | ||||
| 	req.Header["Connection"] = []string{"Upgrade"} | ||||
| 	req.Header["Sec-WebSocket-Key"] = []string{challengeKey} | ||||
| 	req.Header["Sec-WebSocket-Version"] = []string{"13"} | ||||
| 	if len(d.Subprotocols) > 0 { | ||||
| 		req.Header["Sec-WebSocket-Protocol"] = []string{strings.Join(d.Subprotocols, ", ")} | ||||
| 	} | ||||
| 	for k, vs := range requestHeader { | ||||
| 		switch { | ||||
| 		case k == "Host": | ||||
| 			if len(vs) > 0 { | ||||
| 				req.Host = vs[0] | ||||
| 			} | ||||
| 		case k == "Upgrade" || | ||||
| 			k == "Connection" || | ||||
| 			k == "Sec-Websocket-Key" || | ||||
| 			k == "Sec-Websocket-Version" || | ||||
| 			k == "Sec-Websocket-Extensions" || | ||||
| 			(k == "Sec-Websocket-Protocol" && len(d.Subprotocols) > 0): | ||||
| 			return nil, nil, errors.New("websocket: duplicate header not allowed: " + k) | ||||
| 		default: | ||||
| 			req.Header[k] = vs | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if d.EnableCompression { | ||||
| 		req.Header.Set("Sec-Websocket-Extensions", "permessage-deflate; server_no_context_takeover; client_no_context_takeover") | ||||
| 	} | ||||
|  | ||||
| 	hostPort, hostNoPort := hostPortNoPort(u) | ||||
|  | ||||
| 	if d == nil { | ||||
| 		d = &Dialer{} | ||||
| 	var proxyURL *url.URL | ||||
| 	// Check wether the proxy method has been configured | ||||
| 	if d.Proxy != nil { | ||||
| 		proxyURL, err = d.Proxy(req) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	var targetHostPort string | ||||
| 	if proxyURL != nil { | ||||
| 		targetHostPort, _ = hostPortNoPort(proxyURL) | ||||
| 	} else { | ||||
| 		targetHostPort = hostPort | ||||
| 	} | ||||
|  | ||||
| 	var deadline time.Time | ||||
| @@ -188,7 +275,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re | ||||
| 		netDial = netDialer.Dial | ||||
| 	} | ||||
|  | ||||
| 	netConn, err := netDial("tcp", hostPort) | ||||
| 	netConn, err := netDial("tcp", targetHostPort) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| @@ -203,13 +290,41 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	if u.Scheme == "wss" { | ||||
| 		cfg := d.TLSClientConfig | ||||
| 		if cfg == nil { | ||||
| 			cfg = &tls.Config{ServerName: hostNoPort} | ||||
| 		} else if cfg.ServerName == "" { | ||||
| 			shallowCopy := *cfg | ||||
| 			cfg = &shallowCopy | ||||
| 	if proxyURL != nil { | ||||
| 		connectHeader := make(http.Header) | ||||
| 		if user := proxyURL.User; user != nil { | ||||
| 			proxyUser := user.Username() | ||||
| 			if proxyPassword, passwordSet := user.Password(); passwordSet { | ||||
| 				credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword)) | ||||
| 				connectHeader.Set("Proxy-Authorization", "Basic "+credential) | ||||
| 			} | ||||
| 		} | ||||
| 		connectReq := &http.Request{ | ||||
| 			Method: "CONNECT", | ||||
| 			URL:    &url.URL{Opaque: hostPort}, | ||||
| 			Host:   hostPort, | ||||
| 			Header: connectHeader, | ||||
| 		} | ||||
|  | ||||
| 		connectReq.Write(netConn) | ||||
|  | ||||
| 		// Read response. | ||||
| 		// Okay to use and discard buffered reader here, because | ||||
| 		// TLS server will not speak until spoken to. | ||||
| 		br := bufio.NewReader(netConn) | ||||
| 		resp, err := http.ReadResponse(br, connectReq) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| 		if resp.StatusCode != 200 { | ||||
| 			f := strings.SplitN(resp.Status, " ", 2) | ||||
| 			return nil, nil, errors.New(f[1]) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if u.Scheme == "https" { | ||||
| 		cfg := cloneTLSConfig(d.TLSClientConfig) | ||||
| 		if cfg.ServerName == "" { | ||||
| 			cfg.ServerName = hostNoPort | ||||
| 		} | ||||
| 		tlsConn := tls.Client(netConn, cfg) | ||||
| @@ -224,45 +339,53 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(d.Subprotocols) > 0 { | ||||
| 		h := http.Header{} | ||||
| 		for k, v := range requestHeader { | ||||
| 			h[k] = v | ||||
| 		} | ||||
| 		h.Set("Sec-Websocket-Protocol", strings.Join(d.Subprotocols, ", ")) | ||||
| 		requestHeader = h | ||||
| 	conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize) | ||||
|  | ||||
| 	if err := req.Write(netConn); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	if len(requestHeader["Host"]) > 0 { | ||||
| 		// This can be used to supply a Host: header which is different from | ||||
| 		// the dial address. | ||||
| 		u.Host = requestHeader.Get("Host") | ||||
|  | ||||
| 		// Drop "Host" header | ||||
| 		h := http.Header{} | ||||
| 		for k, v := range requestHeader { | ||||
| 			if k == "Host" { | ||||
| 				continue | ||||
| 			} | ||||
| 			h[k] = v | ||||
| 		} | ||||
| 		requestHeader = h | ||||
| 	} | ||||
|  | ||||
| 	conn, resp, err := NewClient(netConn, u, requestHeader, d.ReadBufferSize, d.WriteBufferSize) | ||||
|  | ||||
| 	resp, err := http.ReadResponse(conn.br, req) | ||||
| 	if err != nil { | ||||
| 		if err == ErrBadHandshake { | ||||
| 			// Before closing the network connection on return from this | ||||
| 			// function, slurp up some of the response to aid application | ||||
| 			// debugging. | ||||
| 			buf := make([]byte, 1024) | ||||
| 			n, _ := io.ReadFull(resp.Body, buf) | ||||
| 			resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n])) | ||||
| 		} | ||||
| 		return nil, resp, err | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	if d.Jar != nil { | ||||
| 		if rc := resp.Cookies(); len(rc) > 0 { | ||||
| 			d.Jar.SetCookies(u, rc) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if resp.StatusCode != 101 || | ||||
| 		!strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") || | ||||
| 		!strings.EqualFold(resp.Header.Get("Connection"), "upgrade") || | ||||
| 		resp.Header.Get("Sec-Websocket-Accept") != computeAcceptKey(challengeKey) { | ||||
| 		// Before closing the network connection on return from this | ||||
| 		// function, slurp up some of the response to aid application | ||||
| 		// debugging. | ||||
| 		buf := make([]byte, 1024) | ||||
| 		n, _ := io.ReadFull(resp.Body, buf) | ||||
| 		resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n])) | ||||
| 		return nil, resp, ErrBadHandshake | ||||
| 	} | ||||
|  | ||||
| 	for _, ext := range parseExtensions(resp.Header) { | ||||
| 		if ext[""] != "permessage-deflate" { | ||||
| 			continue | ||||
| 		} | ||||
| 		_, snct := ext["server_no_context_takeover"] | ||||
| 		_, cnct := ext["client_no_context_takeover"] | ||||
| 		if !snct || !cnct { | ||||
| 			return nil, resp, errInvalidCompression | ||||
| 		} | ||||
| 		conn.newCompressionWriter = compressNoContextTakeover | ||||
| 		conn.newDecompressionReader = decompressNoContextTakeover | ||||
| 		break | ||||
| 	} | ||||
|  | ||||
| 	resp.Body = ioutil.NopCloser(bytes.NewReader([]byte{})) | ||||
| 	conn.subprotocol = resp.Header.Get("Sec-Websocket-Protocol") | ||||
|  | ||||
| 	netConn.SetDeadline(time.Time{}) | ||||
| 	netConn = nil // to avoid close in defer. | ||||
| 	return conn, resp, nil | ||||
|   | ||||
							
								
								
									
										16
									
								
								vendor/github.com/gorilla/websocket/client_clone.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/gorilla/websocket/client_clone.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // +build go1.8 | ||||
|  | ||||
| package websocket | ||||
|  | ||||
| import "crypto/tls" | ||||
|  | ||||
| func cloneTLSConfig(cfg *tls.Config) *tls.Config { | ||||
| 	if cfg == nil { | ||||
| 		return &tls.Config{} | ||||
| 	} | ||||
| 	return cfg.Clone() | ||||
| } | ||||
							
								
								
									
										38
									
								
								vendor/github.com/gorilla/websocket/client_clone_legacy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/gorilla/websocket/client_clone_legacy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // +build !go1.8 | ||||
|  | ||||
| package websocket | ||||
|  | ||||
| import "crypto/tls" | ||||
|  | ||||
| // cloneTLSConfig clones all public fields except the fields | ||||
| // SessionTicketsDisabled and SessionTicketKey. This avoids copying the | ||||
| // sync.Mutex in the sync.Once and makes it safe to call cloneTLSConfig on a | ||||
| // config in active use. | ||||
| func cloneTLSConfig(cfg *tls.Config) *tls.Config { | ||||
| 	if cfg == nil { | ||||
| 		return &tls.Config{} | ||||
| 	} | ||||
| 	return &tls.Config{ | ||||
| 		Rand:                     cfg.Rand, | ||||
| 		Time:                     cfg.Time, | ||||
| 		Certificates:             cfg.Certificates, | ||||
| 		NameToCertificate:        cfg.NameToCertificate, | ||||
| 		GetCertificate:           cfg.GetCertificate, | ||||
| 		RootCAs:                  cfg.RootCAs, | ||||
| 		NextProtos:               cfg.NextProtos, | ||||
| 		ServerName:               cfg.ServerName, | ||||
| 		ClientAuth:               cfg.ClientAuth, | ||||
| 		ClientCAs:                cfg.ClientCAs, | ||||
| 		InsecureSkipVerify:       cfg.InsecureSkipVerify, | ||||
| 		CipherSuites:             cfg.CipherSuites, | ||||
| 		PreferServerCipherSuites: cfg.PreferServerCipherSuites, | ||||
| 		ClientSessionCache:       cfg.ClientSessionCache, | ||||
| 		MinVersion:               cfg.MinVersion, | ||||
| 		MaxVersion:               cfg.MaxVersion, | ||||
| 		CurvePreferences:         cfg.CurvePreferences, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										148
									
								
								vendor/github.com/gorilla/websocket/compression.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								vendor/github.com/gorilla/websocket/compression.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,148 @@ | ||||
| // Copyright 2017 The Gorilla WebSocket 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 | ||||
|  | ||||
| import ( | ||||
| 	"compress/flate" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	minCompressionLevel     = -2 // flate.HuffmanOnly not defined in Go < 1.6 | ||||
| 	maxCompressionLevel     = flate.BestCompression | ||||
| 	defaultCompressionLevel = 1 | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	flateWriterPools [maxCompressionLevel - minCompressionLevel + 1]sync.Pool | ||||
| 	flateReaderPool  = sync.Pool{New: func() interface{} { | ||||
| 		return flate.NewReader(nil) | ||||
| 	}} | ||||
| ) | ||||
|  | ||||
| func decompressNoContextTakeover(r io.Reader) io.ReadCloser { | ||||
| 	const tail = | ||||
| 	// Add four bytes as specified in RFC | ||||
| 	"\x00\x00\xff\xff" + | ||||
| 		// Add final block to squelch unexpected EOF error from flate reader. | ||||
| 		"\x01\x00\x00\xff\xff" | ||||
|  | ||||
| 	fr, _ := flateReaderPool.Get().(io.ReadCloser) | ||||
| 	fr.(flate.Resetter).Reset(io.MultiReader(r, strings.NewReader(tail)), nil) | ||||
| 	return &flateReadWrapper{fr} | ||||
| } | ||||
|  | ||||
| func isValidCompressionLevel(level int) bool { | ||||
| 	return minCompressionLevel <= level && level <= maxCompressionLevel | ||||
| } | ||||
|  | ||||
| func compressNoContextTakeover(w io.WriteCloser, level int) io.WriteCloser { | ||||
| 	p := &flateWriterPools[level-minCompressionLevel] | ||||
| 	tw := &truncWriter{w: w} | ||||
| 	fw, _ := p.Get().(*flate.Writer) | ||||
| 	if fw == nil { | ||||
| 		fw, _ = flate.NewWriter(tw, level) | ||||
| 	} else { | ||||
| 		fw.Reset(tw) | ||||
| 	} | ||||
| 	return &flateWriteWrapper{fw: fw, tw: tw, p: p} | ||||
| } | ||||
|  | ||||
| // truncWriter is an io.Writer that writes all but the last four bytes of the | ||||
| // stream to another io.Writer. | ||||
| type truncWriter struct { | ||||
| 	w io.WriteCloser | ||||
| 	n int | ||||
| 	p [4]byte | ||||
| } | ||||
|  | ||||
| func (w *truncWriter) Write(p []byte) (int, error) { | ||||
| 	n := 0 | ||||
|  | ||||
| 	// fill buffer first for simplicity. | ||||
| 	if w.n < len(w.p) { | ||||
| 		n = copy(w.p[w.n:], p) | ||||
| 		p = p[n:] | ||||
| 		w.n += n | ||||
| 		if len(p) == 0 { | ||||
| 			return n, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	m := len(p) | ||||
| 	if m > len(w.p) { | ||||
| 		m = len(w.p) | ||||
| 	} | ||||
|  | ||||
| 	if nn, err := w.w.Write(w.p[:m]); err != nil { | ||||
| 		return n + nn, err | ||||
| 	} | ||||
|  | ||||
| 	copy(w.p[:], w.p[m:]) | ||||
| 	copy(w.p[len(w.p)-m:], p[len(p)-m:]) | ||||
| 	nn, err := w.w.Write(p[:len(p)-m]) | ||||
| 	return n + nn, err | ||||
| } | ||||
|  | ||||
| type flateWriteWrapper struct { | ||||
| 	fw *flate.Writer | ||||
| 	tw *truncWriter | ||||
| 	p  *sync.Pool | ||||
| } | ||||
|  | ||||
| func (w *flateWriteWrapper) Write(p []byte) (int, error) { | ||||
| 	if w.fw == nil { | ||||
| 		return 0, errWriteClosed | ||||
| 	} | ||||
| 	return w.fw.Write(p) | ||||
| } | ||||
|  | ||||
| func (w *flateWriteWrapper) Close() error { | ||||
| 	if w.fw == nil { | ||||
| 		return errWriteClosed | ||||
| 	} | ||||
| 	err1 := w.fw.Flush() | ||||
| 	w.p.Put(w.fw) | ||||
| 	w.fw = nil | ||||
| 	if w.tw.p != [4]byte{0, 0, 0xff, 0xff} { | ||||
| 		return errors.New("websocket: internal error, unexpected bytes at end of flate stream") | ||||
| 	} | ||||
| 	err2 := w.tw.w.Close() | ||||
| 	if err1 != nil { | ||||
| 		return err1 | ||||
| 	} | ||||
| 	return err2 | ||||
| } | ||||
|  | ||||
| type flateReadWrapper struct { | ||||
| 	fr io.ReadCloser | ||||
| } | ||||
|  | ||||
| func (r *flateReadWrapper) Read(p []byte) (int, error) { | ||||
| 	if r.fr == nil { | ||||
| 		return 0, io.ErrClosedPipe | ||||
| 	} | ||||
| 	n, err := r.fr.Read(p) | ||||
| 	if err == io.EOF { | ||||
| 		// Preemptively place the reader back in the pool. This helps with | ||||
| 		// scenarios where the application does not call NextReader() soon after | ||||
| 		// this final read. | ||||
| 		r.Close() | ||||
| 	} | ||||
| 	return n, err | ||||
| } | ||||
|  | ||||
| func (r *flateReadWrapper) Close() error { | ||||
| 	if r.fr == nil { | ||||
| 		return io.ErrClosedPipe | ||||
| 	} | ||||
| 	err := r.fr.Close() | ||||
| 	flateReaderPool.Put(r.fr) | ||||
| 	r.fr = nil | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										780
									
								
								vendor/github.com/gorilla/websocket/conn.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										780
									
								
								vendor/github.com/gorilla/websocket/conn.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										18
									
								
								vendor/github.com/gorilla/websocket/conn_read.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/gorilla/websocket/conn_read.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| // Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // +build go1.5 | ||||
|  | ||||
| package websocket | ||||
|  | ||||
| import "io" | ||||
|  | ||||
| func (c *Conn) read(n int) ([]byte, error) { | ||||
| 	p, err := c.br.Peek(n) | ||||
| 	if err == io.EOF { | ||||
| 		err = errUnexpectedEOF | ||||
| 	} | ||||
| 	c.br.Discard(len(p)) | ||||
| 	return p, err | ||||
| } | ||||
							
								
								
									
										21
									
								
								vendor/github.com/gorilla/websocket/conn_read_legacy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/gorilla/websocket/conn_read_legacy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| // Copyright 2016 The Gorilla WebSocket Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // +build !go1.5 | ||||
|  | ||||
| package websocket | ||||
|  | ||||
| import "io" | ||||
|  | ||||
| func (c *Conn) read(n int) ([]byte, error) { | ||||
| 	p, err := c.br.Peek(n) | ||||
| 	if err == io.EOF { | ||||
| 		err = errUnexpectedEOF | ||||
| 	} | ||||
| 	if len(p) > 0 { | ||||
| 		// advance over the bytes just read | ||||
| 		io.ReadFull(c.br, p) | ||||
| 	} | ||||
| 	return p, err | ||||
| } | ||||
							
								
								
									
										95
									
								
								vendor/github.com/gorilla/websocket/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										95
									
								
								vendor/github.com/gorilla/websocket/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -6,9 +6,8 @@ | ||||
| // | ||||
| // Overview | ||||
| // | ||||
| // The Conn type represents a WebSocket connection. A server application uses | ||||
| // the Upgrade function from an Upgrader object with a HTTP request handler | ||||
| // to get a pointer to a Conn: | ||||
| // The Conn type represents a WebSocket connection. A server application calls | ||||
| // the Upgrader.Upgrade method from an HTTP request handler to get a *Conn: | ||||
| // | ||||
| //  var upgrader = websocket.Upgrader{ | ||||
| //      ReadBufferSize:  1024, | ||||
| @@ -33,7 +32,7 @@ | ||||
| //      if err != nil { | ||||
| //          return | ||||
| //      } | ||||
| //      if err = conn.WriteMessage(messageType, p); err != nil { | ||||
| //      if err := conn.WriteMessage(messageType, p); err != nil { | ||||
| //          return err | ||||
| //      } | ||||
| //  } | ||||
| @@ -46,8 +45,7 @@ | ||||
| // method to get an io.WriteCloser, write the message to the writer and close | ||||
| // the writer when done. To receive a message, call the connection NextReader | ||||
| // method to get an io.Reader and read until io.EOF is returned. This snippet | ||||
| // snippet shows how to echo messages using the NextWriter and NextReader | ||||
| // methods: | ||||
| // shows how to echo messages using the NextWriter and NextReader methods: | ||||
| // | ||||
| //  for { | ||||
| //      messageType, r, err := conn.NextReader() | ||||
| @@ -86,31 +84,23 @@ | ||||
| // and pong. Call the connection WriteControl, WriteMessage or NextWriter | ||||
| // methods to send a control message to the peer. | ||||
| // | ||||
| // Connections handle received ping and pong messages by invoking a callback | ||||
| // function set with SetPingHandler and SetPongHandler methods. These callback | ||||
| // functions can be invoked from the ReadMessage method, the NextReader method | ||||
| // or from a call to the data message reader returned from NextReader. | ||||
| // Connections handle received close messages by sending a close message to the | ||||
| // peer and returning a *CloseError from the the NextReader, ReadMessage or the | ||||
| // message Read method. | ||||
| // | ||||
| // Connections handle received close messages by returning an error from the | ||||
| // ReadMessage method, the NextReader method or from a call to the data message | ||||
| // reader returned from NextReader. | ||||
| // | ||||
| // Concurrency | ||||
| // | ||||
| // Connections do not support concurrent calls to the write methods | ||||
| // (NextWriter, SetWriteDeadline, WriteMessage) or concurrent calls to the read | ||||
| // methods methods (NextReader, SetReadDeadline, ReadMessage).  Connections do | ||||
| // support a concurrent reader and writer. | ||||
| // | ||||
| // The Close and WriteControl methods can be called concurrently with all other | ||||
| // Connections handle received ping and pong messages by invoking callback | ||||
| // functions set with SetPingHandler and SetPongHandler methods. The callback | ||||
| // functions are called from the NextReader, ReadMessage and the message Read | ||||
| // methods. | ||||
| // | ||||
| // Read is Required | ||||
| // The default ping handler sends a pong to the peer. The application's reading | ||||
| // goroutine can block for a short time while the handler writes the pong data | ||||
| // to the connection. | ||||
| // | ||||
| // The application must read the connection to process ping and close messages | ||||
| // sent from the peer. If the application is not otherwise interested in | ||||
| // messages from the peer, then the application should start a goroutine to read | ||||
| // and discard messages from the peer. A simple example is: | ||||
| // The application must read the connection to process ping, pong and close | ||||
| // messages sent from the peer. If the application is not otherwise interested | ||||
| // in messages from the peer, then the application should start a goroutine to | ||||
| // read and discard messages from the peer. A simple example is: | ||||
| // | ||||
| //  func readLoop(c *websocket.Conn) { | ||||
| //      for { | ||||
| @@ -121,6 +111,20 @@ | ||||
| //      } | ||||
| //  } | ||||
| // | ||||
| // Concurrency | ||||
| // | ||||
| // Connections support one concurrent reader and one concurrent writer. | ||||
| // | ||||
| // Applications are responsible for ensuring that no more than one goroutine | ||||
| // calls the write methods (NextWriter, SetWriteDeadline, WriteMessage, | ||||
| // WriteJSON, EnableWriteCompression, SetCompressionLevel) concurrently and | ||||
| // that no more than one goroutine calls the read methods (NextReader, | ||||
| // SetReadDeadline, ReadMessage, ReadJSON, SetPongHandler, SetPingHandler) | ||||
| // concurrently. | ||||
| // | ||||
| // The Close and WriteControl methods can be called concurrently with all other | ||||
| // methods. | ||||
| // | ||||
| // Origin Considerations | ||||
| // | ||||
| // Web browsers allow Javascript applications to open a WebSocket connection to | ||||
| @@ -138,11 +142,38 @@ | ||||
| // An application can allow connections from any origin by specifying a | ||||
| // function that always returns true: | ||||
| // | ||||
| //    var upgrader = websocket.Upgrader{ | ||||
| //  var upgrader = websocket.Upgrader{ | ||||
| //      CheckOrigin: func(r *http.Request) bool { return true }, | ||||
| //   } | ||||
| //  } | ||||
| // | ||||
| // The deprecated Upgrade function does not enforce an origin policy. It's the | ||||
| // application's responsibility to check the Origin header before calling | ||||
| // Upgrade. | ||||
| // The deprecated package-level Upgrade function does not perform origin | ||||
| // checking. The application is responsible for checking the Origin header | ||||
| // before calling the Upgrade function. | ||||
| // | ||||
| // Compression EXPERIMENTAL | ||||
| // | ||||
| // Per message compression extensions (RFC 7692) are experimentally supported | ||||
| // by this package in a limited capacity. Setting the EnableCompression option | ||||
| // to true in Dialer or Upgrader will attempt to negotiate per message deflate | ||||
| // support. | ||||
| // | ||||
| //  var upgrader = websocket.Upgrader{ | ||||
| //      EnableCompression: true, | ||||
| //  } | ||||
| // | ||||
| // If compression was successfully negotiated with the connection's peer, any | ||||
| // message received in compressed form will be automatically decompressed. | ||||
| // All Read methods will return uncompressed bytes. | ||||
| // | ||||
| // Per message compression of messages written to a connection can be enabled | ||||
| // or disabled by calling the corresponding Conn method: | ||||
| // | ||||
| //  conn.EnableWriteCompression(false) | ||||
| // | ||||
| // Currently this package does not support compression with "context takeover". | ||||
| // This means that messages must be compressed and decompressed in isolation, | ||||
| // without retaining sliding window or dictionary state across messages. For | ||||
| // more details refer to RFC 7692. | ||||
| // | ||||
| // Use of compression is experimental and may result in decreased performance. | ||||
| package websocket | ||||
|   | ||||
							
								
								
									
										15
									
								
								vendor/github.com/gorilla/websocket/json.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/gorilla/websocket/json.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -9,12 +9,14 @@ import ( | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| // WriteJSON is deprecated, use c.WriteJSON instead. | ||||
| // WriteJSON writes the JSON encoding of v as a message. | ||||
| // | ||||
| // Deprecated: Use c.WriteJSON instead. | ||||
| func WriteJSON(c *Conn, v interface{}) error { | ||||
| 	return c.WriteJSON(v) | ||||
| } | ||||
|  | ||||
| // WriteJSON writes the JSON encoding of v to the connection. | ||||
| // WriteJSON writes the JSON encoding of v as a message. | ||||
| // | ||||
| // See the documentation for encoding/json Marshal for details about the | ||||
| // conversion of Go values to JSON. | ||||
| @@ -31,7 +33,10 @@ func (c *Conn) WriteJSON(v interface{}) error { | ||||
| 	return err2 | ||||
| } | ||||
|  | ||||
| // ReadJSON is deprecated, use c.ReadJSON instead. | ||||
| // ReadJSON reads the next JSON-encoded message from the connection and stores | ||||
| // it in the value pointed to by v. | ||||
| // | ||||
| // Deprecated: Use c.ReadJSON instead. | ||||
| func ReadJSON(c *Conn, v interface{}) error { | ||||
| 	return c.ReadJSON(v) | ||||
| } | ||||
| @@ -48,9 +53,7 @@ func (c *Conn) ReadJSON(v interface{}) error { | ||||
| 	} | ||||
| 	err = json.NewDecoder(r).Decode(v) | ||||
| 	if err == io.EOF { | ||||
| 		// Decode returns io.EOF when the message is empty or all whitespace. | ||||
| 		// Convert to io.ErrUnexpectedEOF so that application can distinguish | ||||
| 		// between an error reading the JSON value and the connection closing. | ||||
| 		// One value is expected in the message. | ||||
| 		err = io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	return err | ||||
|   | ||||
							
								
								
									
										55
									
								
								vendor/github.com/gorilla/websocket/mask.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								vendor/github.com/gorilla/websocket/mask.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| // Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.  Use of | ||||
| // this source code is governed by a BSD-style license that can be found in the | ||||
| // LICENSE file. | ||||
|  | ||||
| // +build !appengine | ||||
|  | ||||
| package websocket | ||||
|  | ||||
| import "unsafe" | ||||
|  | ||||
| const wordSize = int(unsafe.Sizeof(uintptr(0))) | ||||
|  | ||||
| func maskBytes(key [4]byte, pos int, b []byte) int { | ||||
|  | ||||
| 	// Mask one byte at a time for small buffers. | ||||
| 	if len(b) < 2*wordSize { | ||||
| 		for i := range b { | ||||
| 			b[i] ^= key[pos&3] | ||||
| 			pos++ | ||||
| 		} | ||||
| 		return pos & 3 | ||||
| 	} | ||||
|  | ||||
| 	// Mask one byte at a time to word boundary. | ||||
| 	if n := int(uintptr(unsafe.Pointer(&b[0]))) % wordSize; n != 0 { | ||||
| 		n = wordSize - n | ||||
| 		for i := range b[:n] { | ||||
| 			b[i] ^= key[pos&3] | ||||
| 			pos++ | ||||
| 		} | ||||
| 		b = b[n:] | ||||
| 	} | ||||
|  | ||||
| 	// Create aligned word size key. | ||||
| 	var k [wordSize]byte | ||||
| 	for i := range k { | ||||
| 		k[i] = key[(pos+i)&3] | ||||
| 	} | ||||
| 	kw := *(*uintptr)(unsafe.Pointer(&k)) | ||||
|  | ||||
| 	// Mask one word at a time. | ||||
| 	n := (len(b) / wordSize) * wordSize | ||||
| 	for i := 0; i < n; i += wordSize { | ||||
| 		*(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&b[0])) + uintptr(i))) ^= kw | ||||
| 	} | ||||
|  | ||||
| 	// Mask one byte at a time for remaining bytes. | ||||
| 	b = b[n:] | ||||
| 	for i := range b { | ||||
| 		b[i] ^= key[pos&3] | ||||
| 		pos++ | ||||
| 	} | ||||
|  | ||||
| 	return pos & 3 | ||||
| } | ||||
							
								
								
									
										15
									
								
								vendor/github.com/gorilla/websocket/mask_safe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/gorilla/websocket/mask_safe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| // Copyright 2016 The Gorilla WebSocket Authors. All rights reserved.  Use of | ||||
| // this source code is governed by a BSD-style license that can be found in the | ||||
| // LICENSE file. | ||||
|  | ||||
| // +build appengine | ||||
|  | ||||
| package websocket | ||||
|  | ||||
| func maskBytes(key [4]byte, pos int, b []byte) int { | ||||
| 	for i := range b { | ||||
| 		b[i] ^= key[pos&3] | ||||
| 		pos++ | ||||
| 	} | ||||
| 	return pos & 3 | ||||
| } | ||||
							
								
								
									
										103
									
								
								vendor/github.com/gorilla/websocket/prepared.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								vendor/github.com/gorilla/websocket/prepared.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| // Copyright 2017 The Gorilla WebSocket 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 | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"net" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // PreparedMessage caches on the wire representations of a message payload. | ||||
| // Use PreparedMessage to efficiently send a message payload to multiple | ||||
| // connections. PreparedMessage is especially useful when compression is used | ||||
| // because the CPU and memory expensive compression operation can be executed | ||||
| // once for a given set of compression options. | ||||
| type PreparedMessage struct { | ||||
| 	messageType int | ||||
| 	data        []byte | ||||
| 	err         error | ||||
| 	mu          sync.Mutex | ||||
| 	frames      map[prepareKey]*preparedFrame | ||||
| } | ||||
|  | ||||
| // prepareKey defines a unique set of options to cache prepared frames in PreparedMessage. | ||||
| type prepareKey struct { | ||||
| 	isServer         bool | ||||
| 	compress         bool | ||||
| 	compressionLevel int | ||||
| } | ||||
|  | ||||
| // preparedFrame contains data in wire representation. | ||||
| type preparedFrame struct { | ||||
| 	once sync.Once | ||||
| 	data []byte | ||||
| } | ||||
|  | ||||
| // NewPreparedMessage returns an initialized PreparedMessage. You can then send | ||||
| // it to connection using WritePreparedMessage method. Valid wire | ||||
| // representation will be calculated lazily only once for a set of current | ||||
| // connection options. | ||||
| func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error) { | ||||
| 	pm := &PreparedMessage{ | ||||
| 		messageType: messageType, | ||||
| 		frames:      make(map[prepareKey]*preparedFrame), | ||||
| 		data:        data, | ||||
| 	} | ||||
|  | ||||
| 	// Prepare a plain server frame. | ||||
| 	_, frameData, err := pm.frame(prepareKey{isServer: true, compress: false}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// To protect against caller modifying the data argument, remember the data | ||||
| 	// copied to the plain server frame. | ||||
| 	pm.data = frameData[len(frameData)-len(data):] | ||||
| 	return pm, nil | ||||
| } | ||||
|  | ||||
| func (pm *PreparedMessage) frame(key prepareKey) (int, []byte, error) { | ||||
| 	pm.mu.Lock() | ||||
| 	frame, ok := pm.frames[key] | ||||
| 	if !ok { | ||||
| 		frame = &preparedFrame{} | ||||
| 		pm.frames[key] = frame | ||||
| 	} | ||||
| 	pm.mu.Unlock() | ||||
|  | ||||
| 	var err error | ||||
| 	frame.once.Do(func() { | ||||
| 		// Prepare a frame using a 'fake' connection. | ||||
| 		// TODO: Refactor code in conn.go to allow more direct construction of | ||||
| 		// the frame. | ||||
| 		mu := make(chan bool, 1) | ||||
| 		mu <- true | ||||
| 		var nc prepareConn | ||||
| 		c := &Conn{ | ||||
| 			conn:                   &nc, | ||||
| 			mu:                     mu, | ||||
| 			isServer:               key.isServer, | ||||
| 			compressionLevel:       key.compressionLevel, | ||||
| 			enableWriteCompression: true, | ||||
| 			writeBuf:               make([]byte, defaultWriteBufferSize+maxFrameHeaderSize), | ||||
| 		} | ||||
| 		if key.compress { | ||||
| 			c.newCompressionWriter = compressNoContextTakeover | ||||
| 		} | ||||
| 		err = c.WriteMessage(pm.messageType, pm.data) | ||||
| 		frame.data = nc.buf.Bytes() | ||||
| 	}) | ||||
| 	return pm.messageType, frame.data, err | ||||
| } | ||||
|  | ||||
| type prepareConn struct { | ||||
| 	buf bytes.Buffer | ||||
| 	net.Conn | ||||
| } | ||||
|  | ||||
| func (pc *prepareConn) Write(p []byte) (int, error)        { return pc.buf.Write(p) } | ||||
| func (pc *prepareConn) SetWriteDeadline(t time.Time) error { return nil } | ||||
							
								
								
									
										79
									
								
								vendor/github.com/gorilla/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										79
									
								
								vendor/github.com/gorilla/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -28,8 +28,9 @@ type Upgrader struct { | ||||
| 	HandshakeTimeout time.Duration | ||||
|  | ||||
| 	// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer | ||||
| 	// size is zero, then a default value of 4096 is used. The I/O buffer sizes | ||||
| 	// do not limit the size of the messages that can be sent or received. | ||||
| 	// size is zero, then buffers allocated by the HTTP server are used. The | ||||
| 	// I/O buffer sizes do not limit the size of the messages that can be sent | ||||
| 	// or received. | ||||
| 	ReadBufferSize, WriteBufferSize int | ||||
|  | ||||
| 	// Subprotocols specifies the server's supported protocols in order of | ||||
| @@ -46,6 +47,12 @@ type Upgrader struct { | ||||
| 	// CheckOrigin is nil, the host in the Origin header must not be set or | ||||
| 	// must match the host of the request. | ||||
| 	CheckOrigin func(r *http.Request) bool | ||||
|  | ||||
| 	// EnableCompression specify if the server should attempt to negotiate per | ||||
| 	// message compression (RFC 7692). Setting this value to true does not | ||||
| 	// guarantee that compression will be supported. Currently only "no context | ||||
| 	// takeover" modes are supported. | ||||
| 	EnableCompression bool | ||||
| } | ||||
|  | ||||
| func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) { | ||||
| @@ -53,6 +60,7 @@ func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status in | ||||
| 	if u.Error != nil { | ||||
| 		u.Error(w, r, status, err) | ||||
| 	} else { | ||||
| 		w.Header().Set("Sec-Websocket-Version", "13") | ||||
| 		http.Error(w, http.StatusText(status), status) | ||||
| 	} | ||||
| 	return nil, err | ||||
| @@ -92,17 +100,28 @@ func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header | ||||
| // The responseHeader is included in the response to the client's upgrade | ||||
| // request. Use the responseHeader to specify cookies (Set-Cookie) and the | ||||
| // application negotiated subprotocol (Sec-Websocket-Protocol). | ||||
| // | ||||
| // If the upgrade fails, then Upgrade replies to the client with an HTTP error | ||||
| // response. | ||||
| func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) { | ||||
| 	if values := r.Header["Sec-Websocket-Version"]; len(values) == 0 || values[0] != "13" { | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13") | ||||
| 	if r.Method != "GET" { | ||||
| 		return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: not a websocket handshake: request method is not GET") | ||||
| 	} | ||||
|  | ||||
| 	if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok { | ||||
| 		return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-Websocket-Extensions' headers are unsupported") | ||||
| 	} | ||||
|  | ||||
| 	if !tokenListContainsValue(r.Header, "Connection", "upgrade") { | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find connection header with token 'upgrade'") | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'upgrade' token not found in 'Connection' header") | ||||
| 	} | ||||
|  | ||||
| 	if !tokenListContainsValue(r.Header, "Upgrade", "websocket") { | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find upgrade header with token 'websocket'") | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: 'websocket' token not found in 'Upgrade' header") | ||||
| 	} | ||||
|  | ||||
| 	if !tokenListContainsValue(r.Header, "Sec-Websocket-Version", "13") { | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, "websocket: unsupported version: 13 not found in 'Sec-Websocket-Version' header") | ||||
| 	} | ||||
|  | ||||
| 	checkOrigin := u.CheckOrigin | ||||
| @@ -110,19 +129,30 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade | ||||
| 		checkOrigin = checkSameOrigin | ||||
| 	} | ||||
| 	if !checkOrigin(r) { | ||||
| 		return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed") | ||||
| 		return u.returnError(w, r, http.StatusForbidden, "websocket: 'Origin' header value not allowed") | ||||
| 	} | ||||
|  | ||||
| 	challengeKey := r.Header.Get("Sec-Websocket-Key") | ||||
| 	if challengeKey == "" { | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank") | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, "websocket: not a websocket handshake: `Sec-Websocket-Key' header is missing or blank") | ||||
| 	} | ||||
|  | ||||
| 	subprotocol := u.selectSubprotocol(r, responseHeader) | ||||
|  | ||||
| 	// Negotiate PMCE | ||||
| 	var compress bool | ||||
| 	if u.EnableCompression { | ||||
| 		for _, ext := range parseExtensions(r.Header) { | ||||
| 			if ext[""] != "permessage-deflate" { | ||||
| 				continue | ||||
| 			} | ||||
| 			compress = true | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		netConn net.Conn | ||||
| 		br      *bufio.Reader | ||||
| 		err     error | ||||
| 	) | ||||
|  | ||||
| @@ -130,21 +160,25 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade | ||||
| 	if !ok { | ||||
| 		return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker") | ||||
| 	} | ||||
| 	var rw *bufio.ReadWriter | ||||
| 	netConn, rw, err = h.Hijack() | ||||
| 	var brw *bufio.ReadWriter | ||||
| 	netConn, brw, err = h.Hijack() | ||||
| 	if err != nil { | ||||
| 		return u.returnError(w, r, http.StatusInternalServerError, err.Error()) | ||||
| 	} | ||||
| 	br = rw.Reader | ||||
|  | ||||
| 	if br.Buffered() > 0 { | ||||
| 	if brw.Reader.Buffered() > 0 { | ||||
| 		netConn.Close() | ||||
| 		return nil, errors.New("websocket: client sent data before handshake is complete") | ||||
| 	} | ||||
|  | ||||
| 	c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize) | ||||
| 	c := newConnBRW(netConn, true, u.ReadBufferSize, u.WriteBufferSize, brw) | ||||
| 	c.subprotocol = subprotocol | ||||
|  | ||||
| 	if compress { | ||||
| 		c.newCompressionWriter = compressNoContextTakeover | ||||
| 		c.newDecompressionReader = decompressNoContextTakeover | ||||
| 	} | ||||
|  | ||||
| 	p := c.writeBuf[:0] | ||||
| 	p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...) | ||||
| 	p = append(p, computeAcceptKey(challengeKey)...) | ||||
| @@ -154,6 +188,9 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade | ||||
| 		p = append(p, c.subprotocol...) | ||||
| 		p = append(p, "\r\n"...) | ||||
| 	} | ||||
| 	if compress { | ||||
| 		p = append(p, "Sec-Websocket-Extensions: permessage-deflate; server_no_context_takeover; client_no_context_takeover\r\n"...) | ||||
| 	} | ||||
| 	for k, vs := range responseHeader { | ||||
| 		if k == "Sec-Websocket-Protocol" { | ||||
| 			continue | ||||
| @@ -193,10 +230,11 @@ func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeade | ||||
|  | ||||
| // Upgrade upgrades the HTTP server connection to the WebSocket protocol. | ||||
| // | ||||
| // This function is deprecated, use websocket.Upgrader instead. | ||||
| // Deprecated: Use websocket.Upgrader instead. | ||||
| // | ||||
| // The application is responsible for checking the request origin before | ||||
| // calling Upgrade. An example implementation of the same origin policy is: | ||||
| // Upgrade does not perform origin checking. The application is responsible for | ||||
| // checking the Origin header before calling Upgrade. An example implementation | ||||
| // of the same origin policy check is: | ||||
| // | ||||
| //	if req.Header.Get("Origin") != "http://"+req.Host { | ||||
| //		http.Error(w, "Origin not allowed", 403) | ||||
| @@ -245,3 +283,10 @@ func Subprotocols(r *http.Request) []string { | ||||
| 	} | ||||
| 	return protocols | ||||
| } | ||||
|  | ||||
| // IsWebSocketUpgrade returns true if the client requested upgrade to the | ||||
| // WebSocket protocol. | ||||
| func IsWebSocketUpgrade(r *http.Request) bool { | ||||
| 	return tokenListContainsValue(r.Header, "Connection", "upgrade") && | ||||
| 		tokenListContainsValue(r.Header, "Upgrade", "websocket") | ||||
| } | ||||
|   | ||||
							
								
								
									
										196
									
								
								vendor/github.com/gorilla/websocket/util.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										196
									
								
								vendor/github.com/gorilla/websocket/util.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -13,19 +13,6 @@ import ( | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // tokenListContainsValue returns true if the 1#token header with the given | ||||
| // name contains token. | ||||
| func tokenListContainsValue(header http.Header, name string, value string) bool { | ||||
| 	for _, v := range header[name] { | ||||
| 		for _, s := range strings.Split(v, ",") { | ||||
| 			if strings.EqualFold(value, strings.TrimSpace(s)) { | ||||
| 				return true | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") | ||||
|  | ||||
| func computeAcceptKey(challengeKey string) string { | ||||
| @@ -42,3 +29,186 @@ func generateChallengeKey() (string, error) { | ||||
| 	} | ||||
| 	return base64.StdEncoding.EncodeToString(p), nil | ||||
| } | ||||
|  | ||||
| // Octet types from RFC 2616. | ||||
| var octetTypes [256]byte | ||||
|  | ||||
| const ( | ||||
| 	isTokenOctet = 1 << iota | ||||
| 	isSpaceOctet | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	// From RFC 2616 | ||||
| 	// | ||||
| 	// OCTET      = <any 8-bit sequence of data> | ||||
| 	// CHAR       = <any US-ASCII character (octets 0 - 127)> | ||||
| 	// CTL        = <any US-ASCII control character (octets 0 - 31) and DEL (127)> | ||||
| 	// CR         = <US-ASCII CR, carriage return (13)> | ||||
| 	// LF         = <US-ASCII LF, linefeed (10)> | ||||
| 	// SP         = <US-ASCII SP, space (32)> | ||||
| 	// HT         = <US-ASCII HT, horizontal-tab (9)> | ||||
| 	// <">        = <US-ASCII double-quote mark (34)> | ||||
| 	// CRLF       = CR LF | ||||
| 	// LWS        = [CRLF] 1*( SP | HT ) | ||||
| 	// TEXT       = <any OCTET except CTLs, but including LWS> | ||||
| 	// separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> | ||||
| 	//              | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT | ||||
| 	// token      = 1*<any CHAR except CTLs or separators> | ||||
| 	// qdtext     = <any TEXT except <">> | ||||
|  | ||||
| 	for c := 0; c < 256; c++ { | ||||
| 		var t byte | ||||
| 		isCtl := c <= 31 || c == 127 | ||||
| 		isChar := 0 <= c && c <= 127 | ||||
| 		isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0 | ||||
| 		if strings.IndexRune(" \t\r\n", rune(c)) >= 0 { | ||||
| 			t |= isSpaceOctet | ||||
| 		} | ||||
| 		if isChar && !isCtl && !isSeparator { | ||||
| 			t |= isTokenOctet | ||||
| 		} | ||||
| 		octetTypes[c] = t | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func skipSpace(s string) (rest string) { | ||||
| 	i := 0 | ||||
| 	for ; i < len(s); i++ { | ||||
| 		if octetTypes[s[i]]&isSpaceOctet == 0 { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return s[i:] | ||||
| } | ||||
|  | ||||
| func nextToken(s string) (token, rest string) { | ||||
| 	i := 0 | ||||
| 	for ; i < len(s); i++ { | ||||
| 		if octetTypes[s[i]]&isTokenOctet == 0 { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return s[:i], s[i:] | ||||
| } | ||||
|  | ||||
| func nextTokenOrQuoted(s string) (value string, rest string) { | ||||
| 	if !strings.HasPrefix(s, "\"") { | ||||
| 		return nextToken(s) | ||||
| 	} | ||||
| 	s = s[1:] | ||||
| 	for i := 0; i < len(s); i++ { | ||||
| 		switch s[i] { | ||||
| 		case '"': | ||||
| 			return s[:i], s[i+1:] | ||||
| 		case '\\': | ||||
| 			p := make([]byte, len(s)-1) | ||||
| 			j := copy(p, s[:i]) | ||||
| 			escape := true | ||||
| 			for i = i + 1; i < len(s); i++ { | ||||
| 				b := s[i] | ||||
| 				switch { | ||||
| 				case escape: | ||||
| 					escape = false | ||||
| 					p[j] = b | ||||
| 					j++ | ||||
| 				case b == '\\': | ||||
| 					escape = true | ||||
| 				case b == '"': | ||||
| 					return string(p[:j]), s[i+1:] | ||||
| 				default: | ||||
| 					p[j] = b | ||||
| 					j++ | ||||
| 				} | ||||
| 			} | ||||
| 			return "", "" | ||||
| 		} | ||||
| 	} | ||||
| 	return "", "" | ||||
| } | ||||
|  | ||||
| // tokenListContainsValue returns true if the 1#token header with the given | ||||
| // name contains token. | ||||
| func tokenListContainsValue(header http.Header, name string, value string) bool { | ||||
| headers: | ||||
| 	for _, s := range header[name] { | ||||
| 		for { | ||||
| 			var t string | ||||
| 			t, s = nextToken(skipSpace(s)) | ||||
| 			if t == "" { | ||||
| 				continue headers | ||||
| 			} | ||||
| 			s = skipSpace(s) | ||||
| 			if s != "" && s[0] != ',' { | ||||
| 				continue headers | ||||
| 			} | ||||
| 			if strings.EqualFold(t, value) { | ||||
| 				return true | ||||
| 			} | ||||
| 			if s == "" { | ||||
| 				continue headers | ||||
| 			} | ||||
| 			s = s[1:] | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // parseExtensiosn parses WebSocket extensions from a header. | ||||
| func parseExtensions(header http.Header) []map[string]string { | ||||
|  | ||||
| 	// From RFC 6455: | ||||
| 	// | ||||
| 	//  Sec-WebSocket-Extensions = extension-list | ||||
| 	//  extension-list = 1#extension | ||||
| 	//  extension = extension-token *( ";" extension-param ) | ||||
| 	//  extension-token = registered-token | ||||
| 	//  registered-token = token | ||||
| 	//  extension-param = token [ "=" (token | quoted-string) ] | ||||
| 	//     ;When using the quoted-string syntax variant, the value | ||||
| 	//     ;after quoted-string unescaping MUST conform to the | ||||
| 	//     ;'token' ABNF. | ||||
|  | ||||
| 	var result []map[string]string | ||||
| headers: | ||||
| 	for _, s := range header["Sec-Websocket-Extensions"] { | ||||
| 		for { | ||||
| 			var t string | ||||
| 			t, s = nextToken(skipSpace(s)) | ||||
| 			if t == "" { | ||||
| 				continue headers | ||||
| 			} | ||||
| 			ext := map[string]string{"": t} | ||||
| 			for { | ||||
| 				s = skipSpace(s) | ||||
| 				if !strings.HasPrefix(s, ";") { | ||||
| 					break | ||||
| 				} | ||||
| 				var k string | ||||
| 				k, s = nextToken(skipSpace(s[1:])) | ||||
| 				if k == "" { | ||||
| 					continue headers | ||||
| 				} | ||||
| 				s = skipSpace(s) | ||||
| 				var v string | ||||
| 				if strings.HasPrefix(s, "=") { | ||||
| 					v, s = nextTokenOrQuoted(skipSpace(s[1:])) | ||||
| 					s = skipSpace(s) | ||||
| 				} | ||||
| 				if s != "" && s[0] != ',' && s[0] != ';' { | ||||
| 					continue headers | ||||
| 				} | ||||
| 				ext[k] = v | ||||
| 			} | ||||
| 			if s != "" && s[0] != ',' { | ||||
| 				continue headers | ||||
| 			} | ||||
| 			result = append(result, ext) | ||||
| 			if s == "" { | ||||
| 				continue headers | ||||
| 			} | ||||
| 			s = s[1:] | ||||
| 		} | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user