Add initial websocket implementation
This commit is contained in:
		
							
								
								
									
										8
									
								
								vendor/github.com/leavengood/websocket/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/leavengood/websocket/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| # This is the official list of Gorilla WebSocket authors for copyright | ||||
| # purposes. | ||||
| # | ||||
| # Please keep the list sorted. | ||||
|  | ||||
| Gary Burd <gary@beagledreams.com> | ||||
| Joachim Bauch <mail@joachim-bauch.de> | ||||
|  | ||||
							
								
								
									
										22
									
								
								vendor/github.com/leavengood/websocket/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/leavengood/websocket/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
|  | ||||
|   Redistributions of source code must retain the above copyright notice, this | ||||
|   list of conditions and the following disclaimer. | ||||
|  | ||||
|   Redistributions in binary form must reproduce the above copyright notice, | ||||
|   this list of conditions and the following disclaimer in the documentation | ||||
|   and/or other materials provided with the distribution. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
| FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										68
									
								
								vendor/github.com/leavengood/websocket/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								vendor/github.com/leavengood/websocket/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| # Gorilla WebSocket | ||||
|  | ||||
| Gorilla WebSocket is a [Go](http://golang.org/) implementation of the | ||||
| [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. | ||||
|  | ||||
| *This fork adds support for the Go HTTP package | ||||
| [fasthttp](https://github.com/valyala/fasthttp), which is a high performance, | ||||
| byte slice oriented alternative to `net/http`.* | ||||
|  | ||||
| [](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 | ||||
|  | ||||
| The Gorilla WebSocket package provides a complete and tested implementation of | ||||
| the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. The | ||||
| package API is stable. | ||||
|  | ||||
| ### Installation | ||||
|  | ||||
|     go get github.com/gorilla/websocket | ||||
|  | ||||
| ### Protocol Compliance | ||||
|  | ||||
| The Gorilla WebSocket package passes the server tests in the [Autobahn Test | ||||
| Suite](http://autobahn.ws/testsuite) using the application in the [examples/autobahn | ||||
| subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn). | ||||
|  | ||||
| ### Gorilla WebSocket compared with other packages | ||||
|  | ||||
| <table> | ||||
| <tr> | ||||
| <th></th> | ||||
| <th><a href="http://godoc.org/github.com/gorilla/websocket">github.com/gorilla</a></th> | ||||
| <th><a href="http://godoc.org/golang.org/x/net/websocket">golang.org/x/net</a></th> | ||||
| </tr> | ||||
| <tr> | ||||
| <tr><td colspan="3"><a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> Features</td></tr> | ||||
| <tr><td>Passes <a href="http://autobahn.ws/testsuite/">Autobahn Test Suite</a></td><td><a href="https://github.com/gorilla/websocket/tree/master/examples/autobahn">Yes</a></td><td>No</td></tr> | ||||
| <tr><td>Receive <a href="https://tools.ietf.org/html/rfc6455#section-5.4">fragmented</a> message<td>Yes</td><td><a href="https://code.google.com/p/go/issues/detail?id=7632">No</a>, see note 1</td></tr> | ||||
| <tr><td>Send <a href="https://tools.ietf.org/html/rfc6455#section-5.5.1">close</a> message</td><td><a href="http://godoc.org/github.com/gorilla/websocket#hdr-Control_Messages">Yes</a></td><td><a href="https://code.google.com/p/go/issues/detail?id=4588">No</a></td></tr> | ||||
| <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><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> | ||||
|  | ||||
| Notes: | ||||
|  | ||||
| 1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html). | ||||
| 2. The application can get the type of a received data message by implementing | ||||
|    a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal) | ||||
|    function. | ||||
| 3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries. | ||||
|   Read returns when the input buffer is full or a frame boundary is | ||||
|   encountered. Each call to Write sends a single frame message. The Gorilla | ||||
|   io.Reader and io.WriteCloser operate on a single WebSocket message. | ||||
|  | ||||
							
								
								
									
										420
									
								
								vendor/github.com/leavengood/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										420
									
								
								vendor/github.com/leavengood/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,420 @@ | ||||
| // 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. | ||||
|  | ||||
| package websocket | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"crypto/tls" | ||||
| 	"encoding/base64" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // ErrBadHandshake is returned when the server response to opening handshake is | ||||
| // 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 | ||||
| // (Cookie). Use the response.Header to get the selected subprotocol | ||||
| // (Sec-WebSocket-Protocol) and cookies (Set-Cookie). | ||||
| // | ||||
| // 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) { | ||||
| 	d := Dialer{ | ||||
| 		ReadBufferSize:  readBufSize, | ||||
| 		WriteBufferSize: writeBufSize, | ||||
| 		NetDial: func(net, addr string) (net.Conn, error) { | ||||
| 			return netConn, nil | ||||
| 		}, | ||||
| 	} | ||||
| 	return d.Dial(u.String(), requestHeader) | ||||
| } | ||||
|  | ||||
| // A Dialer contains options for connecting to WebSocket server. | ||||
| type Dialer struct { | ||||
| 	// NetDial specifies the dial function for creating TCP connections. If | ||||
| 	// 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 | ||||
|  | ||||
| 	// 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, 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. | ||||
| // | ||||
| // 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 ] | ||||
| 	var u url.URL | ||||
| 	switch { | ||||
| 	case strings.HasPrefix(s, "ws://"): | ||||
| 		u.Scheme = "ws" | ||||
| 		s = s[len("ws://"):] | ||||
| 	case strings.HasPrefix(s, "wss://"): | ||||
| 		u.Scheme = "wss" | ||||
| 		s = s[len("wss://"):] | ||||
| 	default: | ||||
| 		return nil, errMalformedURL | ||||
| 	} | ||||
|  | ||||
| 	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, "@") { | ||||
| 		// Don't bother parsing user information because user information is | ||||
| 		// not allowed in websocket URIs. | ||||
| 		return nil, errMalformedURL | ||||
| 	} | ||||
|  | ||||
| 	return &u, nil | ||||
| } | ||||
|  | ||||
| func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) { | ||||
| 	hostPort = u.Host | ||||
| 	hostNoPort = u.Host | ||||
| 	if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") { | ||||
| 		hostNoPort = hostNoPort[:i] | ||||
| 	} else { | ||||
| 		switch u.Scheme { | ||||
| 		case "wss": | ||||
| 			hostPort += ":443" | ||||
| 		case "https": | ||||
| 			hostPort += ":443" | ||||
| 		default: | ||||
| 			hostPort += ":80" | ||||
| 		} | ||||
| 	} | ||||
| 	return hostPort, hostNoPort | ||||
| } | ||||
|  | ||||
| // DefaultDialer is a dialer with all fields set to the default zero values. | ||||
| 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). | ||||
| // Use the response.Header to get the selected subprotocol | ||||
| // (Sec-WebSocket-Protocol) and cookies (Set-Cookie). | ||||
| // | ||||
| // If the WebSocket handshake fails, ErrBadHandshake is returned along with a | ||||
| // non-nil *http.Response so that callers can handle redirects, authentication, | ||||
| // 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) | ||||
|  | ||||
| 	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 | ||||
| 	if d.HandshakeTimeout != 0 { | ||||
| 		deadline = time.Now().Add(d.HandshakeTimeout) | ||||
| 	} | ||||
|  | ||||
| 	netDial := d.NetDial | ||||
| 	if netDial == nil { | ||||
| 		netDialer := &net.Dialer{Deadline: deadline} | ||||
| 		netDial = netDialer.Dial | ||||
| 	} | ||||
|  | ||||
| 	netConn, err := netDial("tcp", targetHostPort) | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	defer func() { | ||||
| 		if netConn != nil { | ||||
| 			netConn.Close() | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	if err := netConn.SetDeadline(deadline); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	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) | ||||
| 		netConn = tlsConn | ||||
| 		if err := tlsConn.Handshake(); err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| 		if !cfg.InsecureSkipVerify { | ||||
| 			if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { | ||||
| 				return nil, nil, err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize) | ||||
|  | ||||
| 	if err := req.Write(netConn); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	resp, err := http.ReadResponse(conn.br, req) | ||||
| 	if err != nil { | ||||
| 		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(req.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 | ||||
| } | ||||
|  | ||||
| // 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, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										135
									
								
								vendor/github.com/leavengood/websocket/compression.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								vendor/github.com/leavengood/websocket/compression.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | ||||
| // 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" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	flateWriterPool = sync.Pool{New: func() interface{} { | ||||
| 		fw, _ := flate.NewWriter(nil, 3) | ||||
| 		return fw | ||||
| 	}} | ||||
| 	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 compressNoContextTakeover(w io.WriteCloser) io.WriteCloser { | ||||
| 	tw := &truncWriter{w: w} | ||||
| 	fw, _ := flateWriterPool.Get().(*flate.Writer) | ||||
| 	fw.Reset(tw) | ||||
| 	return &flateWriteWrapper{fw: fw, tw: tw} | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| } | ||||
|  | ||||
| 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() | ||||
| 	flateWriterPool.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 | ||||
| } | ||||
							
								
								
									
										1055
									
								
								vendor/github.com/leavengood/websocket/conn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1055
									
								
								vendor/github.com/leavengood/websocket/conn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										18
									
								
								vendor/github.com/leavengood/websocket/conn_read.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/leavengood/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/leavengood/websocket/conn_read_legacy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/leavengood/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 | ||||
| } | ||||
							
								
								
									
										173
									
								
								vendor/github.com/leavengood/websocket/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								vendor/github.com/leavengood/websocket/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,173 @@ | ||||
| // 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. | ||||
|  | ||||
| // Package websocket implements the WebSocket protocol defined in RFC 6455. | ||||
| // | ||||
| // 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: | ||||
| // | ||||
| //  var upgrader = websocket.Upgrader{ | ||||
| //      ReadBufferSize:  1024, | ||||
| //      WriteBufferSize: 1024, | ||||
| //  } | ||||
| // | ||||
| //  func handler(w http.ResponseWriter, r *http.Request) { | ||||
| //      conn, err := upgrader.Upgrade(w, r, nil) | ||||
| //      if err != nil { | ||||
| //          log.Println(err) | ||||
| //          return | ||||
| //      } | ||||
| //      ... Use conn to send and receive messages. | ||||
| //  } | ||||
| // | ||||
| // Call the connection's WriteMessage and ReadMessage methods to send and | ||||
| // receive messages as a slice of bytes. This snippet of code shows how to echo | ||||
| // messages using these methods: | ||||
| // | ||||
| //  for { | ||||
| //      messageType, p, err := conn.ReadMessage() | ||||
| //      if err != nil { | ||||
| //          return | ||||
| //      } | ||||
| //      if err = conn.WriteMessage(messageType, p); err != nil { | ||||
| //          return err | ||||
| //      } | ||||
| //  } | ||||
| // | ||||
| // In above snippet of code, p is a []byte and messageType is an int with value | ||||
| // websocket.BinaryMessage or websocket.TextMessage. | ||||
| // | ||||
| // An application can also send and receive messages using the io.WriteCloser | ||||
| // and io.Reader interfaces. To send a message, call the connection NextWriter | ||||
| // 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 | ||||
| // shows how to echo messages using the NextWriter and NextReader methods: | ||||
| // | ||||
| //  for { | ||||
| //      messageType, r, err := conn.NextReader() | ||||
| //      if err != nil { | ||||
| //          return | ||||
| //      } | ||||
| //      w, err := conn.NextWriter(messageType) | ||||
| //      if err != nil { | ||||
| //          return err | ||||
| //      } | ||||
| //      if _, err := io.Copy(w, r); err != nil { | ||||
| //          return err | ||||
| //      } | ||||
| //      if err := w.Close(); err != nil { | ||||
| //          return err | ||||
| //      } | ||||
| //  } | ||||
| // | ||||
| // Data Messages | ||||
| // | ||||
| // The WebSocket protocol distinguishes between text and binary data messages. | ||||
| // Text messages are interpreted as UTF-8 encoded text. The interpretation of | ||||
| // binary messages is left to the application. | ||||
| // | ||||
| // This package uses the TextMessage and BinaryMessage integer constants to | ||||
| // identify the two data message types. The ReadMessage and NextReader methods | ||||
| // return the type of the received message. The messageType argument to the | ||||
| // WriteMessage and NextWriter methods specifies the type of a sent message. | ||||
| // | ||||
| // It is the application's responsibility to ensure that text messages are | ||||
| // valid UTF-8 encoded text. | ||||
| // | ||||
| // Control Messages | ||||
| // | ||||
| // The WebSocket protocol defines three types of control messages: close, ping | ||||
| // and pong. Call the connection WriteControl, WriteMessage or NextWriter | ||||
| // methods to send a control message to the peer. | ||||
| // | ||||
| // 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 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. | ||||
| // | ||||
| // 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, 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 { | ||||
| //          if _, _, err := c.NextReader(); err != nil { | ||||
| //              c.Close() | ||||
| //              break | ||||
| //          } | ||||
| //      } | ||||
| //  } | ||||
| // | ||||
| // 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) 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 | ||||
| // any host. It's up to the server to enforce an origin policy using the Origin | ||||
| // request header sent by the browser. | ||||
| // | ||||
| // The Upgrader calls the function specified in the CheckOrigin field to check | ||||
| // the origin. If the CheckOrigin function returns false, then the Upgrade | ||||
| // method fails the WebSocket handshake with HTTP status 403. | ||||
| // | ||||
| // If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail | ||||
| // the handshake if the Origin request header is present and not equal to the | ||||
| // Host request header. | ||||
| // | ||||
| // An application can allow connections from any origin by specifying a | ||||
| // function that always returns true: | ||||
| // | ||||
| //  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. | ||||
| // | ||||
| // Compression | ||||
| // | ||||
| // 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. 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(true) | ||||
| // | ||||
| // 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 | ||||
							
								
								
									
										137
									
								
								vendor/github.com/leavengood/websocket/fasthttp.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								vendor/github.com/leavengood/websocket/fasthttp.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| // Copyright 2015 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.4 | ||||
|  | ||||
| package websocket | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"net" | ||||
|  | ||||
| 	"github.com/valyala/fasthttp" | ||||
| ) | ||||
|  | ||||
| func checkSameOriginFastHTTP(ctx *fasthttp.RequestCtx) bool { | ||||
| 	return checkSameOriginFromHeaderAndHost(string(ctx.Request.Header.Peek(originHeader)), string(ctx.Host())) | ||||
| } | ||||
|  | ||||
| func fastHTTPHeaderContainsValue(hdr fasthttp.RequestHeader, header string, value string) bool { | ||||
| 	result := false | ||||
| 	matchKey := []byte(header) | ||||
| 	hdr.VisitAll(func(key []byte, val []byte) { | ||||
| 		if !result { | ||||
| 			if bytes.Equal(key, matchKey) { | ||||
| 				headerValue := string(val) | ||||
| 				if tokenContainsValue(headerValue, value) { | ||||
| 					result = true | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // FastHTTPUpgrader is used to upgrade a fasthttp request into a websocket | ||||
| // connection. A Handler function must be provided to receive that connection. | ||||
| type FastHTTPUpgrader struct { | ||||
| 	// Handler receives a websocket connection after the handshake has been | ||||
| 	// completed. This must be provided. | ||||
| 	Handler func(*Conn) | ||||
|  | ||||
| 	// 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. | ||||
| 	ReadBufferSize, WriteBufferSize int | ||||
|  | ||||
| 	// Subprotocols specifies the server's supported protocols in order of | ||||
| 	// preference. If this field is set, then the Upgrade method negotiates a | ||||
| 	// subprotocol by selecting the first match in this list with a protocol | ||||
| 	// requested by the client. | ||||
| 	Subprotocols []string | ||||
|  | ||||
| 	// CheckOrigin returns true if the request Origin header is acceptable. If | ||||
| 	// CheckOrigin is nil, the host in the Origin header must not be set or | ||||
| 	// must match the host of the request. | ||||
| 	CheckOrigin func(ctx *fasthttp.RequestCtx) bool | ||||
| } | ||||
|  | ||||
| var websocketVersionByte = []byte(websocketVersion) | ||||
|  | ||||
| // UpgradeHandler handles a request for a websocket connection and does all the | ||||
| // checks necessary to ensure the request is valid. If a CheckOrigin function | ||||
| // was provided it will be called, otherwise the Origin will be checked against | ||||
| // the request host value. If a subprotocol has not already been set, the best | ||||
| // choice will be made from the values provided to the upgrader and from the | ||||
| // client. | ||||
| // | ||||
| // Once the request has been verified and the response sent, the connection will | ||||
| // be hijacked and the provided Handler will be called. | ||||
| func (f *FastHTTPUpgrader) UpgradeHandler(ctx *fasthttp.RequestCtx) { | ||||
| 	if f.Handler == nil { | ||||
| 		panic("FastHTTPUpgrader does not have a Handler set") | ||||
| 	} | ||||
|  | ||||
| 	if !ctx.IsGet() { | ||||
| 		ctx.Error("websocket: method not GET", fasthttp.StatusMethodNotAllowed) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if !bytes.Equal(ctx.Request.Header.Peek("Sec-Websocket-Version"), websocketVersionByte) { | ||||
| 		ctx.Error("websocket: version != 13", fasthttp.StatusBadRequest) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if !fastHTTPHeaderContainsValue(ctx.Request.Header, "Connection", "upgrade") { | ||||
| 		ctx.Error("websocket: could not find connection header with token 'upgrade'", fasthttp.StatusBadRequest) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if !fastHTTPHeaderContainsValue(ctx.Request.Header, "Upgrade", "websocket") { | ||||
| 		ctx.Error("websocket: could not find upgrade header with token 'websocket'", fasthttp.StatusBadRequest) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	checkOrigin := f.CheckOrigin | ||||
| 	if checkOrigin == nil { | ||||
| 		checkOrigin = checkSameOriginFastHTTP | ||||
| 	} | ||||
| 	if !checkOrigin(ctx) { | ||||
| 		ctx.Error("websocket: origin not allowed", fasthttp.StatusForbidden) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	challengeKey := ctx.Request.Header.Peek("Sec-Websocket-Key") | ||||
| 	if len(challengeKey) == 0 { | ||||
| 		ctx.Error("websocket: key missing or blank", fasthttp.StatusBadRequest) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ctx.SetStatusCode(fasthttp.StatusSwitchingProtocols) | ||||
| 	ctx.Response.Header.Set("Upgrade", "websocket") | ||||
| 	ctx.Response.Header.Set("Connection", "Upgrade") | ||||
| 	ctx.Response.Header.Set("Sec-WebSocket-Accept", computeAcceptKeyByte(challengeKey)) | ||||
|  | ||||
| 	// The subprotocol may have already been set in the response | ||||
| 	subprotocol := string(ctx.Response.Header.Peek(protocolHeader)) | ||||
| 	if subprotocol == "" { | ||||
| 		// Find the best protocol, if any | ||||
| 		clientProtocols := subprotocolsFromHeader(string(ctx.Request.Header.Peek(protocolHeader))) | ||||
| 		if len(clientProtocols) != 0 { | ||||
| 			subprotocol = matchSubprotocol(clientProtocols, f.Subprotocols) | ||||
| 			if subprotocol != "" { | ||||
| 				ctx.Response.Header.Set(protocolHeader, subprotocol) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	ctx.Hijack(func(conn net.Conn) { | ||||
| 		c := newConn(conn, true, f.ReadBufferSize, f.WriteBufferSize) | ||||
| 		if subprotocol != "" { | ||||
| 			c.subprotocol = subprotocol | ||||
| 		} | ||||
| 		f.Handler(c) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										55
									
								
								vendor/github.com/leavengood/websocket/json.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								vendor/github.com/leavengood/websocket/json.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| // 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. | ||||
|  | ||||
| package websocket | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| // WriteJSON is 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. | ||||
| // | ||||
| // See the documentation for encoding/json Marshal for details about the | ||||
| // conversion of Go values to JSON. | ||||
| func (c *Conn) WriteJSON(v interface{}) error { | ||||
| 	w, err := c.NextWriter(TextMessage) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err1 := json.NewEncoder(w).Encode(v) | ||||
| 	err2 := w.Close() | ||||
| 	if err1 != nil { | ||||
| 		return err1 | ||||
| 	} | ||||
| 	return err2 | ||||
| } | ||||
|  | ||||
| // ReadJSON is deprecated, use c.ReadJSON instead. | ||||
| func ReadJSON(c *Conn, v interface{}) error { | ||||
| 	return c.ReadJSON(v) | ||||
| } | ||||
|  | ||||
| // ReadJSON reads the next JSON-encoded message from the connection and stores | ||||
| // it in the value pointed to by v. | ||||
| // | ||||
| // See the documentation for the encoding/json Unmarshal function for details | ||||
| // about the conversion of JSON to a Go value. | ||||
| func (c *Conn) ReadJSON(v interface{}) error { | ||||
| 	_, r, err := c.NextReader() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = json.NewDecoder(r).Decode(v) | ||||
| 	if err == io.EOF { | ||||
| 		// One value is expected in the message. | ||||
| 		err = io.ErrUnexpectedEOF | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										55
									
								
								vendor/github.com/leavengood/websocket/mask.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								vendor/github.com/leavengood/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/leavengood/websocket/mask_safe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/leavengood/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 | ||||
| } | ||||
							
								
								
									
										314
									
								
								vendor/github.com/leavengood/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										314
									
								
								vendor/github.com/leavengood/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,314 @@ | ||||
| // Copyright 2013-2015 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 ( | ||||
| 	"bufio" | ||||
| 	"errors" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	originHeader     = "Origin" | ||||
| 	protocolHeader   = "Sec-Websocket-Protocol" | ||||
| 	websocketVersion = "13" | ||||
| ) | ||||
|  | ||||
| // HandshakeError describes an error with the handshake from the peer. | ||||
| type HandshakeError struct { | ||||
| 	message string | ||||
| } | ||||
|  | ||||
| func (e HandshakeError) Error() string { return e.message } | ||||
|  | ||||
| // Upgrader specifies parameters for upgrading an HTTP connection to a | ||||
| // WebSocket connection. | ||||
| type Upgrader struct { | ||||
| 	// HandshakeTimeout specifies the duration for the handshake to complete. | ||||
| 	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. | ||||
| 	ReadBufferSize, WriteBufferSize int | ||||
|  | ||||
| 	// Subprotocols specifies the server's supported protocols in order of | ||||
| 	// preference. If this field is set, then the Upgrade method negotiates a | ||||
| 	// subprotocol by selecting the first match in this list with a protocol | ||||
| 	// requested by the client. | ||||
| 	Subprotocols []string | ||||
|  | ||||
| 	// Error specifies the function for generating HTTP error responses. If Error | ||||
| 	// is nil, then http.Error is used to generate the HTTP response. | ||||
| 	Error func(w http.ResponseWriter, r *http.Request, status int, reason error) | ||||
|  | ||||
| 	// CheckOrigin returns true if the request Origin header is acceptable. If | ||||
| 	// 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) { | ||||
| 	err := HandshakeError{reason} | ||||
| 	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 | ||||
| } | ||||
|  | ||||
| // checkSameOrigin returns true if the origin is not set or is equal to the request host. | ||||
| func checkSameOrigin(r *http.Request) bool { | ||||
| 	origin := r.Header[originHeader] | ||||
| 	if len(origin) == 0 { | ||||
| 		return true | ||||
| 	} | ||||
| 	return checkSameOriginFromHeaderAndHost(origin[0], r.Host) | ||||
| } | ||||
|  | ||||
| func checkSameOriginFromHeaderAndHost(origin, reqHost string) bool { | ||||
| 	if len(origin) == 0 { | ||||
| 		return true | ||||
| 	} | ||||
| 	u, err := url.Parse(origin) | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	return u.Host == reqHost | ||||
| } | ||||
|  | ||||
| func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string { | ||||
| 	if u.Subprotocols != nil { | ||||
| 		return matchSubprotocol(Subprotocols(r), u.Subprotocols) | ||||
| 	} else if responseHeader != nil { | ||||
| 		return responseHeader.Get(protocolHeader) | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func matchSubprotocol(clientProtocols, serverProtocols []string) string { | ||||
| 	for _, serverProtocol := range serverProtocols { | ||||
| 		for _, clientProtocol := range clientProtocols { | ||||
| 			if clientProtocol == serverProtocol { | ||||
| 				return clientProtocol | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| // Upgrade upgrades the HTTP server connection to the WebSocket protocol. | ||||
| // | ||||
| // 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 r.Method != "GET" { | ||||
| 		return u.returnError(w, r, http.StatusMethodNotAllowed, "websocket: method 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, "Sec-Websocket-Version", "13") { | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13") | ||||
| 	} | ||||
|  | ||||
| 	if !tokenListContainsValue(r.Header, "Connection", "upgrade") { | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find connection header with token 'upgrade'") | ||||
| 	} | ||||
|  | ||||
| 	if !tokenListContainsValue(r.Header, "Upgrade", "websocket") { | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find upgrade header with token 'websocket'") | ||||
| 	} | ||||
|  | ||||
| 	checkOrigin := u.CheckOrigin | ||||
| 	if checkOrigin == nil { | ||||
| 		checkOrigin = checkSameOrigin | ||||
| 	} | ||||
| 	if !checkOrigin(r) { | ||||
| 		return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed") | ||||
| 	} | ||||
|  | ||||
| 	challengeKey := r.Header.Get("Sec-Websocket-Key") | ||||
| 	if challengeKey == "" { | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, "websocket: key 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 | ||||
| 	) | ||||
|  | ||||
| 	h, ok := w.(http.Hijacker) | ||||
| 	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() | ||||
| 	if err != nil { | ||||
| 		return u.returnError(w, r, http.StatusInternalServerError, err.Error()) | ||||
| 	} | ||||
| 	br = rw.Reader | ||||
|  | ||||
| 	if br.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.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)...) | ||||
| 	p = append(p, "\r\n"...) | ||||
| 	if c.subprotocol != "" { | ||||
| 		p = append(p, "Sec-Websocket-Protocol: "...) | ||||
| 		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 == protocolHeader { | ||||
| 			continue | ||||
| 		} | ||||
| 		for _, v := range vs { | ||||
| 			p = append(p, k...) | ||||
| 			p = append(p, ": "...) | ||||
| 			for i := 0; i < len(v); i++ { | ||||
| 				b := v[i] | ||||
| 				if b <= 31 { | ||||
| 					// prevent response splitting. | ||||
| 					b = ' ' | ||||
| 				} | ||||
| 				p = append(p, b) | ||||
| 			} | ||||
| 			p = append(p, "\r\n"...) | ||||
| 		} | ||||
| 	} | ||||
| 	p = append(p, "\r\n"...) | ||||
|  | ||||
| 	// Clear deadlines set by HTTP server. | ||||
| 	netConn.SetDeadline(time.Time{}) | ||||
|  | ||||
| 	if u.HandshakeTimeout > 0 { | ||||
| 		netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout)) | ||||
| 	} | ||||
| 	if _, err = netConn.Write(p); err != nil { | ||||
| 		netConn.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if u.HandshakeTimeout > 0 { | ||||
| 		netConn.SetWriteDeadline(time.Time{}) | ||||
| 	} | ||||
|  | ||||
| 	return c, nil | ||||
| } | ||||
|  | ||||
| // Upgrade upgrades the HTTP server connection to the WebSocket protocol. | ||||
| // | ||||
| // This function is 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: | ||||
| // | ||||
| //	if req.Header.Get("Origin") != "http://"+req.Host { | ||||
| //		http.Error(w, "Origin not allowed", 403) | ||||
| //		return | ||||
| //	} | ||||
| // | ||||
| // If the endpoint supports subprotocols, then the application is responsible | ||||
| // for negotiating the protocol used on the connection. Use the Subprotocols() | ||||
| // function to get the subprotocols requested by the client. Use the | ||||
| // Sec-Websocket-Protocol response header to specify the subprotocol selected | ||||
| // by the application. | ||||
| // | ||||
| // The responseHeader is included in the response to the client's upgrade | ||||
| // request. Use the responseHeader to specify cookies (Set-Cookie) and the | ||||
| // negotiated subprotocol (Sec-Websocket-Protocol). | ||||
| // | ||||
| // The connection buffers IO to the underlying network connection. The | ||||
| // readBufSize and writeBufSize parameters specify the size of the buffers to | ||||
| // use. Messages can be larger than the buffers. | ||||
| // | ||||
| // If the request is not a valid WebSocket handshake, then Upgrade returns an | ||||
| // error of type HandshakeError. Applications should handle this error by | ||||
| // replying to the client with an HTTP error response. | ||||
| func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) { | ||||
| 	u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize} | ||||
| 	u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) { | ||||
| 		// don't return errors to maintain backwards compatibility | ||||
| 	} | ||||
| 	u.CheckOrigin = func(r *http.Request) bool { | ||||
| 		// allow all connections by default | ||||
| 		return true | ||||
| 	} | ||||
| 	return u.Upgrade(w, r, responseHeader) | ||||
| } | ||||
|  | ||||
| // Subprotocols returns the subprotocols requested by the client in the | ||||
| // Sec-Websocket-Protocol header. | ||||
| func Subprotocols(r *http.Request) []string { | ||||
| 	return subprotocolsFromHeader(r.Header.Get(protocolHeader)) | ||||
| } | ||||
|  | ||||
| func subprotocolsFromHeader(header string) []string { | ||||
| 	h := strings.TrimSpace(header) | ||||
| 	if h == "" { | ||||
| 		return nil | ||||
| 	} | ||||
| 	protocols := strings.Split(h, ",") | ||||
| 	for i := range protocols { | ||||
| 		protocols[i] = strings.TrimSpace(protocols[i]) | ||||
| 	} | ||||
| 	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") | ||||
| } | ||||
							
								
								
									
										227
									
								
								vendor/github.com/leavengood/websocket/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								vendor/github.com/leavengood/websocket/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,227 @@ | ||||
| // Copyright 2013-2015 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 ( | ||||
| 	"crypto/rand" | ||||
| 	"crypto/sha1" | ||||
| 	"encoding/base64" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") | ||||
|  | ||||
| func computeAcceptKey(challengeKey string) string { | ||||
| 	return computeAcceptKeyByte([]byte(challengeKey)) | ||||
| } | ||||
|  | ||||
| func computeAcceptKeyByte(challengeKey []byte) string { | ||||
| 	h := sha1.New() | ||||
| 	h.Write(challengeKey) | ||||
| 	h.Write(keyGUID) | ||||
| 	return base64.StdEncoding.EncodeToString(h.Sum(nil)) | ||||
| } | ||||
|  | ||||
| func generateChallengeKey() (string, error) { | ||||
| 	p := make([]byte, 16) | ||||
| 	if _, err := io.ReadFull(rand.Reader, p); err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	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, "\"") { | ||||
| 		v, r := nextToken(s) | ||||
| 		return v, r | ||||
| 	} | ||||
| 	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 += 1 | ||||
| 				case b == '\\': | ||||
| 					escape = true | ||||
| 				case b == '"': | ||||
| 					return string(p[:j]), s[i+1:] | ||||
| 				default: | ||||
| 					p[j] = b | ||||
| 					j += 1 | ||||
| 				} | ||||
| 			} | ||||
| 			return "", "" | ||||
| 		} | ||||
| 	} | ||||
| 	return "", "" | ||||
| } | ||||
|  | ||||
| // tokenContainsValue takes a string and tokenizes it, checking | ||||
| // to see if any of the values match a value, returning true if so, | ||||
| // false otherwise | ||||
| func tokenContainsValue(token string, value string) bool { | ||||
| 	for { | ||||
| 		var t string | ||||
| 		t, token = nextToken(skipSpace(token)) | ||||
| 		if t == "" { | ||||
| 			return false | ||||
| 		} | ||||
| 		token = skipSpace(token) | ||||
| 		if token != "" && token[0] != ',' { | ||||
| 			return false | ||||
| 		} | ||||
| 		if strings.EqualFold(t, value) { | ||||
| 			return true | ||||
| 		} | ||||
| 		if token == "" { | ||||
| 			return false | ||||
| 		} | ||||
| 		token = token[1:] | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 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 _, s := range header[name] { | ||||
| 		if tokenContainsValue(s, value) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	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