mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 12:42:25 -05:00 
			
		
		
		
	Grand test fixup (#138)
* start fixing up tests * fix up tests + automate with drone * fiddle with linting * messing about with drone.yml * some more fiddling * hmmm * add cache * add vendor directory * verbose * ci updates * update some little things * update sig
This commit is contained in:
		
					parent
					
						
							
								329a5e8144
							
						
					
				
			
			
				commit
				
					
						98263a7de6
					
				
			
		
					 2677 changed files with 1090869 additions and 219 deletions
				
			
		
							
								
								
									
										25
									
								
								vendor/github.com/gorilla/websocket/.gitignore
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/gorilla/websocket/.gitignore
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| # Compiled Object files, Static and Dynamic libs (Shared Objects) | ||||
| *.o | ||||
| *.a | ||||
| *.so | ||||
| 
 | ||||
| # Folders | ||||
| _obj | ||||
| _test | ||||
| 
 | ||||
| # Architecture specific extensions/prefixes | ||||
| *.[568vq] | ||||
| [568vq].out | ||||
| 
 | ||||
| *.cgo1.go | ||||
| *.cgo2.c | ||||
| _cgo_defun.c | ||||
| _cgo_gotypes.go | ||||
| _cgo_export.* | ||||
| 
 | ||||
| _testmain.go | ||||
| 
 | ||||
| *.exe | ||||
| 
 | ||||
| .idea/ | ||||
| *.iml | ||||
							
								
								
									
										9
									
								
								vendor/github.com/gorilla/websocket/AUTHORS
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/gorilla/websocket/AUTHORS
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| # This is the official list of Gorilla WebSocket authors for copyright | ||||
| # purposes. | ||||
| # | ||||
| # Please keep the list sorted. | ||||
| 
 | ||||
| Gary Burd <gary@beagledreams.com> | ||||
| Google LLC (https://opensource.google.com/) | ||||
| Joachim Bauch <mail@joachim-bauch.de> | ||||
| 
 | ||||
							
								
								
									
										22
									
								
								vendor/github.com/gorilla/websocket/LICENSE
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/gorilla/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. | ||||
							
								
								
									
										64
									
								
								vendor/github.com/gorilla/websocket/README.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								vendor/github.com/gorilla/websocket/README.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,64 @@ | |||
| # Gorilla WebSocket | ||||
| 
 | ||||
| [](https://godoc.org/github.com/gorilla/websocket) | ||||
| [](https://circleci.com/gh/gorilla/websocket) | ||||
| 
 | ||||
| Gorilla WebSocket is a [Go](http://golang.org/) implementation of the | ||||
| [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. | ||||
| 
 | ||||
| ### Documentation | ||||
| 
 | ||||
| * [API Reference](https://pkg.go.dev/github.com/gorilla/websocket?tab=doc) | ||||
| * [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](https://github.com/crossbario/autobahn-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="https://github.com/crossbario/autobahn-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. | ||||
| 
 | ||||
							
								
								
									
										395
									
								
								vendor/github.com/gorilla/websocket/client.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										395
									
								
								vendor/github.com/gorilla/websocket/client.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,395 @@ | |||
| // 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 ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"crypto/tls" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"net/http/httptrace" | ||||
| 	"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) | ||||
| 
 | ||||
| 	// NetDialContext specifies the dial function for creating TCP connections. If | ||||
| 	// NetDialContext is nil, net.DialContext is used. | ||||
| 	NetDialContext func(ctx context.Context, 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 | ||||
| 
 | ||||
| 	// ReadBufferSize and WriteBufferSize specify I/O buffer sizes in bytes. 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 | ||||
| 
 | ||||
| 	// WriteBufferPool is a pool of buffers for write operations. If the value | ||||
| 	// is not set, then write buffers are allocated to the connection for the | ||||
| 	// lifetime of the connection. | ||||
| 	// | ||||
| 	// A pool is most useful when the application has a modest volume of writes | ||||
| 	// across a large number of connections. | ||||
| 	// | ||||
| 	// Applications should use a single pool for each unique value of | ||||
| 	// WriteBufferSize. | ||||
| 	WriteBufferPool BufferPool | ||||
| 
 | ||||
| 	// 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 | ||||
| } | ||||
| 
 | ||||
| // Dial creates a new client connection by calling DialContext with a background context. | ||||
| func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) { | ||||
| 	return d.DialContext(context.Background(), urlStr, requestHeader) | ||||
| } | ||||
| 
 | ||||
| var errMalformedURL = errors.New("malformed ws or wss URL") | ||||
| 
 | ||||
| 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 values. | ||||
| var DefaultDialer = &Dialer{ | ||||
| 	Proxy:            http.ProxyFromEnvironment, | ||||
| 	HandshakeTimeout: 45 * time.Second, | ||||
| } | ||||
| 
 | ||||
| // nilDialer is dialer to use when receiver is nil. | ||||
| var nilDialer = *DefaultDialer | ||||
| 
 | ||||
| // DialContext 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). | ||||
| // | ||||
| // The context will be used in the request and in the Dialer. | ||||
| // | ||||
| // 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) DialContext(ctx context.Context, urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) { | ||||
| 	if d == nil { | ||||
| 		d = &nilDialer | ||||
| 	} | ||||
| 
 | ||||
| 	challengeKey, err := generateChallengeKey() | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	u, err := url.Parse(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, | ||||
| 	} | ||||
| 	req = req.WithContext(ctx) | ||||
| 
 | ||||
| 	// 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) | ||||
| 		case k == "Sec-Websocket-Protocol": | ||||
| 			req.Header["Sec-WebSocket-Protocol"] = vs | ||||
| 		default: | ||||
| 			req.Header[k] = vs | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if d.EnableCompression { | ||||
| 		req.Header["Sec-WebSocket-Extensions"] = []string{"permessage-deflate; server_no_context_takeover; client_no_context_takeover"} | ||||
| 	} | ||||
| 
 | ||||
| 	if d.HandshakeTimeout != 0 { | ||||
| 		var cancel func() | ||||
| 		ctx, cancel = context.WithTimeout(ctx, d.HandshakeTimeout) | ||||
| 		defer cancel() | ||||
| 	} | ||||
| 
 | ||||
| 	// Get network dial function. | ||||
| 	var netDial func(network, add string) (net.Conn, error) | ||||
| 
 | ||||
| 	if d.NetDialContext != nil { | ||||
| 		netDial = func(network, addr string) (net.Conn, error) { | ||||
| 			return d.NetDialContext(ctx, network, addr) | ||||
| 		} | ||||
| 	} else if d.NetDial != nil { | ||||
| 		netDial = d.NetDial | ||||
| 	} else { | ||||
| 		netDialer := &net.Dialer{} | ||||
| 		netDial = func(network, addr string) (net.Conn, error) { | ||||
| 			return netDialer.DialContext(ctx, network, addr) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// If needed, wrap the dial function to set the connection deadline. | ||||
| 	if deadline, ok := ctx.Deadline(); ok { | ||||
| 		forwardDial := netDial | ||||
| 		netDial = func(network, addr string) (net.Conn, error) { | ||||
| 			c, err := forwardDial(network, addr) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			err = c.SetDeadline(deadline) | ||||
| 			if err != nil { | ||||
| 				c.Close() | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			return c, nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// If needed, wrap the dial function to connect through a proxy. | ||||
| 	if d.Proxy != nil { | ||||
| 		proxyURL, err := d.Proxy(req) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| 		if proxyURL != nil { | ||||
| 			dialer, err := proxy_FromURL(proxyURL, netDialerFunc(netDial)) | ||||
| 			if err != nil { | ||||
| 				return nil, nil, err | ||||
| 			} | ||||
| 			netDial = dialer.Dial | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	hostPort, hostNoPort := hostPortNoPort(u) | ||||
| 	trace := httptrace.ContextClientTrace(ctx) | ||||
| 	if trace != nil && trace.GetConn != nil { | ||||
| 		trace.GetConn(hostPort) | ||||
| 	} | ||||
| 
 | ||||
| 	netConn, err := netDial("tcp", hostPort) | ||||
| 	if trace != nil && trace.GotConn != nil { | ||||
| 		trace.GotConn(httptrace.GotConnInfo{ | ||||
| 			Conn: netConn, | ||||
| 		}) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	defer func() { | ||||
| 		if netConn != nil { | ||||
| 			netConn.Close() | ||||
| 		} | ||||
| 	}() | ||||
| 
 | ||||
| 	if u.Scheme == "https" { | ||||
| 		cfg := cloneTLSConfig(d.TLSClientConfig) | ||||
| 		if cfg.ServerName == "" { | ||||
| 			cfg.ServerName = hostNoPort | ||||
| 		} | ||||
| 		tlsConn := tls.Client(netConn, cfg) | ||||
| 		netConn = tlsConn | ||||
| 
 | ||||
| 		var err error | ||||
| 		if trace != nil { | ||||
| 			err = doHandshakeWithTrace(trace, tlsConn, cfg) | ||||
| 		} else { | ||||
| 			err = doHandshake(tlsConn, cfg) | ||||
| 		} | ||||
| 
 | ||||
| 		if err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	conn := newConn(netConn, false, d.ReadBufferSize, d.WriteBufferSize, d.WriteBufferPool, nil, nil) | ||||
| 
 | ||||
| 	if err := req.Write(netConn); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if trace != nil && trace.GotFirstResponseByte != nil { | ||||
| 		if peek, err := conn.br.Peek(1); err == nil && len(peek) == 1 { | ||||
| 			trace.GotFirstResponseByte() | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	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(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 | ||||
| } | ||||
| 
 | ||||
| func doHandshake(tlsConn *tls.Conn, cfg *tls.Config) error { | ||||
| 	if err := tlsConn.Handshake(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if !cfg.InsecureSkipVerify { | ||||
| 		if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return 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 | ||||
| } | ||||
							
								
								
									
										1201
									
								
								vendor/github.com/gorilla/websocket/conn.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1201
									
								
								vendor/github.com/gorilla/websocket/conn.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										15
									
								
								vendor/github.com/gorilla/websocket/conn_write.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/gorilla/websocket/conn_write.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 go1.8 | ||||
| 
 | ||||
| package websocket | ||||
| 
 | ||||
| import "net" | ||||
| 
 | ||||
| func (c *Conn) writeBufs(bufs ...[]byte) error { | ||||
| 	b := net.Buffers(bufs) | ||||
| 	_, err := b.WriteTo(c.conn) | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										18
									
								
								vendor/github.com/gorilla/websocket/conn_write_legacy.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/gorilla/websocket/conn_write_legacy.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.8 | ||||
| 
 | ||||
| package websocket | ||||
| 
 | ||||
| func (c *Conn) writeBufs(bufs ...[]byte) error { | ||||
| 	for _, buf := range bufs { | ||||
| 		if len(buf) > 0 { | ||||
| 			if _, err := c.conn.Write(buf); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										227
									
								
								vendor/github.com/gorilla/websocket/doc.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								vendor/github.com/gorilla/websocket/doc.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,227 @@ | |||
| // 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 calls | ||||
| // the Upgrader.Upgrade method from an HTTP request handler to get 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 { | ||||
| //          log.Println(err) | ||||
| //          return | ||||
| //      } | ||||
| //      if err := conn.WriteMessage(messageType, p); err != nil { | ||||
| //          log.Println(err) | ||||
| //          return | ||||
| //      } | ||||
| //  } | ||||
| // | ||||
| // 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 calling the handler function | ||||
| // set with the SetCloseHandler method and by returning a *CloseError from the | ||||
| // NextReader, ReadMessage or the message Read method. The default close | ||||
| // handler sends a close message to the peer. | ||||
| // | ||||
| // Connections handle received ping messages by calling the handler function | ||||
| // set with the SetPingHandler method. The default ping handler sends a pong | ||||
| // message to the peer. | ||||
| // | ||||
| // Connections handle received pong messages by calling the handler function | ||||
| // set with the SetPongHandler method. The default pong handler does nothing. | ||||
| // If an application sends ping messages, then the application should set a | ||||
| // pong handler to receive the corresponding pong. | ||||
| // | ||||
| // The control message handler functions are called from the NextReader, | ||||
| // ReadMessage and message reader Read methods. The default close and ping | ||||
| // handlers can block these methods for a short time when the handler writes to | ||||
| // the connection. | ||||
| // | ||||
| // The application must read the connection to process close, ping and pong | ||||
| // 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, 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 | ||||
| // 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 the Origin host is | ||||
| // not equal to the Host request header. | ||||
| // | ||||
| // 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. | ||||
| // | ||||
| // Buffers | ||||
| // | ||||
| // Connections buffer network input and output to reduce the number | ||||
| // of system calls when reading or writing messages. | ||||
| // | ||||
| // Write buffers are also used for constructing WebSocket frames. See RFC 6455, | ||||
| // Section 5 for a discussion of message framing. A WebSocket frame header is | ||||
| // written to the network each time a write buffer is flushed to the network. | ||||
| // Decreasing the size of the write buffer can increase the amount of framing | ||||
| // overhead on the connection. | ||||
| // | ||||
| // The buffer sizes in bytes are specified by the ReadBufferSize and | ||||
| // WriteBufferSize fields in the Dialer and Upgrader. The Dialer uses a default | ||||
| // size of 4096 when a buffer size field is set to zero. The Upgrader reuses | ||||
| // buffers created by the HTTP server when a buffer size field is set to zero. | ||||
| // The HTTP server buffers have a size of 4096 at the time of this writing. | ||||
| // | ||||
| // The buffer sizes do not limit the size of a message that can be read or | ||||
| // written by a connection. | ||||
| // | ||||
| // Buffers are held for the lifetime of the connection by default. If the | ||||
| // Dialer or Upgrader WriteBufferPool field is set, then a connection holds the | ||||
| // write buffer only when writing a message. | ||||
| // | ||||
| // Applications should tune the buffer sizes to balance memory use and | ||||
| // performance. Increasing the buffer size uses more memory, but can reduce the | ||||
| // number of system calls to read or write the network. In the case of writing, | ||||
| // increasing the buffer size can reduce the number of frame headers written to | ||||
| // the network. | ||||
| // | ||||
| // Some guidelines for setting buffer parameters are: | ||||
| // | ||||
| // Limit the buffer sizes to the maximum expected message size. Buffers larger | ||||
| // than the largest message do not provide any benefit. | ||||
| // | ||||
| // Depending on the distribution of message sizes, setting the buffer size to | ||||
| // a value less than the maximum expected message size can greatly reduce memory | ||||
| // use with a small impact on performance. Here's an example: If 99% of the | ||||
| // messages are smaller than 256 bytes and the maximum message size is 512 | ||||
| // bytes, then a buffer size of 256 bytes will result in 1.01 more system calls | ||||
| // than a buffer size of 512 bytes. The memory savings is 50%. | ||||
| // | ||||
| // A write buffer pool is useful when the application has a modest number | ||||
| // writes over a large number of connections. when buffers are pooled, a larger | ||||
| // buffer size has a reduced impact on total memory use and has the benefit of | ||||
| // reducing system calls and frame overhead. | ||||
| // | ||||
| // 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 | ||||
							
								
								
									
										3
									
								
								vendor/github.com/gorilla/websocket/go.mod
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/gorilla/websocket/go.mod
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| module github.com/gorilla/websocket | ||||
| 
 | ||||
| go 1.12 | ||||
							
								
								
									
										0
									
								
								vendor/github.com/gorilla/websocket/go.sum
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								vendor/github.com/gorilla/websocket/go.sum
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
									
										42
									
								
								vendor/github.com/gorilla/websocket/join.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/gorilla/websocket/join.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| // Copyright 2019 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 ( | ||||
| 	"io" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| // JoinMessages concatenates received messages to create a single io.Reader. | ||||
| // The string term is appended to each message. The returned reader does not | ||||
| // support concurrent calls to the Read method. | ||||
| func JoinMessages(c *Conn, term string) io.Reader { | ||||
| 	return &joinReader{c: c, term: term} | ||||
| } | ||||
| 
 | ||||
| type joinReader struct { | ||||
| 	c    *Conn | ||||
| 	term string | ||||
| 	r    io.Reader | ||||
| } | ||||
| 
 | ||||
| func (r *joinReader) Read(p []byte) (int, error) { | ||||
| 	if r.r == nil { | ||||
| 		var err error | ||||
| 		_, r.r, err = r.c.NextReader() | ||||
| 		if err != nil { | ||||
| 			return 0, err | ||||
| 		} | ||||
| 		if r.term != "" { | ||||
| 			r.r = io.MultiReader(r.r, strings.NewReader(r.term)) | ||||
| 		} | ||||
| 	} | ||||
| 	n, err := r.r.Read(p) | ||||
| 	if err == io.EOF { | ||||
| 		err = nil | ||||
| 		r.r = nil | ||||
| 	} | ||||
| 	return n, err | ||||
| } | ||||
							
								
								
									
										60
									
								
								vendor/github.com/gorilla/websocket/json.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								vendor/github.com/gorilla/websocket/json.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| // 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 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 as a message. | ||||
| // | ||||
| // 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 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) | ||||
| } | ||||
| 
 | ||||
| // 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 | ||||
| } | ||||
							
								
								
									
										54
									
								
								vendor/github.com/gorilla/websocket/mask.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/gorilla/websocket/mask.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | |||
| // 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 | ||||
| } | ||||
							
								
								
									
										102
									
								
								vendor/github.com/gorilla/websocket/prepared.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								vendor/github.com/gorilla/websocket/prepared.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,102 @@ | |||
| // 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 | ||||
| 	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 struct{}, 1) | ||||
| 		mu <- struct{}{} | ||||
| 		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 } | ||||
							
								
								
									
										77
									
								
								vendor/github.com/gorilla/websocket/proxy.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								vendor/github.com/gorilla/websocket/proxy.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| // 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 ( | ||||
| 	"bufio" | ||||
| 	"encoding/base64" | ||||
| 	"errors" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| type netDialerFunc func(network, addr string) (net.Conn, error) | ||||
| 
 | ||||
| func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) { | ||||
| 	return fn(network, addr) | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) { | ||||
| 		return &httpProxyDialer{proxyURL: proxyURL, forwardDial: forwardDialer.Dial}, nil | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| type httpProxyDialer struct { | ||||
| 	proxyURL    *url.URL | ||||
| 	forwardDial func(network, addr string) (net.Conn, error) | ||||
| } | ||||
| 
 | ||||
| func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) { | ||||
| 	hostPort, _ := hostPortNoPort(hpd.proxyURL) | ||||
| 	conn, err := hpd.forwardDial(network, hostPort) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	connectHeader := make(http.Header) | ||||
| 	if user := hpd.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: addr}, | ||||
| 		Host:   addr, | ||||
| 		Header: connectHeader, | ||||
| 	} | ||||
| 
 | ||||
| 	if err := connectReq.Write(conn); err != nil { | ||||
| 		conn.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Read response. It's OK to use and discard buffered reader here becaue | ||||
| 	// the remote server does not speak until spoken to. | ||||
| 	br := bufio.NewReader(conn) | ||||
| 	resp, err := http.ReadResponse(br, connectReq) | ||||
| 	if err != nil { | ||||
| 		conn.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if resp.StatusCode != 200 { | ||||
| 		conn.Close() | ||||
| 		f := strings.SplitN(resp.Status, " ", 2) | ||||
| 		return nil, errors.New(f[1]) | ||||
| 	} | ||||
| 	return conn, nil | ||||
| } | ||||
							
								
								
									
										363
									
								
								vendor/github.com/gorilla/websocket/server.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								vendor/github.com/gorilla/websocket/server.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,363 @@ | |||
| // 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" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| // 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 in bytes. If a buffer | ||||
| 	// 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 | ||||
| 
 | ||||
| 	// WriteBufferPool is a pool of buffers for write operations. If the value | ||||
| 	// is not set, then write buffers are allocated to the connection for the | ||||
| 	// lifetime of the connection. | ||||
| 	// | ||||
| 	// A pool is most useful when the application has a modest volume of writes | ||||
| 	// across a large number of connections. | ||||
| 	// | ||||
| 	// Applications should use a single pool for each unique value of | ||||
| 	// WriteBufferSize. | ||||
| 	WriteBufferPool BufferPool | ||||
| 
 | ||||
| 	// Subprotocols specifies the server's supported protocols in order of | ||||
| 	// preference. If this field is not nil, then the Upgrade method negotiates a | ||||
| 	// subprotocol by selecting the first match in this list with a protocol | ||||
| 	// requested by the client. If there's no match, then no protocol is | ||||
| 	// negotiated (the Sec-Websocket-Protocol header is not included in the | ||||
| 	// handshake response). | ||||
| 	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, then a safe default is used: return false if the | ||||
| 	// Origin request header is present and the origin host is not equal to | ||||
| 	// request Host header. | ||||
| 	// | ||||
| 	// A CheckOrigin function should carefully validate the request origin to | ||||
| 	// prevent cross-site request forgery. | ||||
| 	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["Origin"] | ||||
| 	if len(origin) == 0 { | ||||
| 		return true | ||||
| 	} | ||||
| 	u, err := url.Parse(origin[0]) | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	return equalASCIIFold(u.Host, r.Host) | ||||
| } | ||||
| 
 | ||||
| func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string { | ||||
| 	if u.Subprotocols != nil { | ||||
| 		clientProtocols := Subprotocols(r) | ||||
| 		for _, serverProtocol := range u.Subprotocols { | ||||
| 			for _, clientProtocol := range clientProtocols { | ||||
| 				if clientProtocol == serverProtocol { | ||||
| 					return clientProtocol | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} else if responseHeader != nil { | ||||
| 		return responseHeader.Get("Sec-Websocket-Protocol") | ||||
| 	} | ||||
| 	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) { | ||||
| 	const badHandshake = "websocket: the client is not using the websocket protocol: " | ||||
| 
 | ||||
| 	if !tokenListContainsValue(r.Header, "Connection", "upgrade") { | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'upgrade' token not found in 'Connection' header") | ||||
| 	} | ||||
| 
 | ||||
| 	if !tokenListContainsValue(r.Header, "Upgrade", "websocket") { | ||||
| 		return u.returnError(w, r, http.StatusBadRequest, badHandshake+"'websocket' token not found in 'Upgrade' header") | ||||
| 	} | ||||
| 
 | ||||
| 	if r.Method != "GET" { | ||||
| 		return u.returnError(w, r, http.StatusMethodNotAllowed, badHandshake+"request method is not GET") | ||||
| 	} | ||||
| 
 | ||||
| 	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") | ||||
| 	} | ||||
| 
 | ||||
| 	if _, ok := responseHeader["Sec-Websocket-Extensions"]; ok { | ||||
| 		return u.returnError(w, r, http.StatusInternalServerError, "websocket: application specific 'Sec-WebSocket-Extensions' headers are unsupported") | ||||
| 	} | ||||
| 
 | ||||
| 	checkOrigin := u.CheckOrigin | ||||
| 	if checkOrigin == nil { | ||||
| 		checkOrigin = checkSameOrigin | ||||
| 	} | ||||
| 	if !checkOrigin(r) { | ||||
| 		return u.returnError(w, r, http.StatusForbidden, "websocket: request origin not allowed by Upgrader.CheckOrigin") | ||||
| 	} | ||||
| 
 | ||||
| 	challengeKey := r.Header.Get("Sec-Websocket-Key") | ||||
| 	if challengeKey == "" { | ||||
| 		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 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	h, ok := w.(http.Hijacker) | ||||
| 	if !ok { | ||||
| 		return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker") | ||||
| 	} | ||||
| 	var brw *bufio.ReadWriter | ||||
| 	netConn, brw, err := h.Hijack() | ||||
| 	if err != nil { | ||||
| 		return u.returnError(w, r, http.StatusInternalServerError, err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	if brw.Reader.Buffered() > 0 { | ||||
| 		netConn.Close() | ||||
| 		return nil, errors.New("websocket: client sent data before handshake is complete") | ||||
| 	} | ||||
| 
 | ||||
| 	var br *bufio.Reader | ||||
| 	if u.ReadBufferSize == 0 && bufioReaderSize(netConn, brw.Reader) > 256 { | ||||
| 		// Reuse hijacked buffered reader as connection reader. | ||||
| 		br = brw.Reader | ||||
| 	} | ||||
| 
 | ||||
| 	buf := bufioWriterBuffer(netConn, brw.Writer) | ||||
| 
 | ||||
| 	var writeBuf []byte | ||||
| 	if u.WriteBufferPool == nil && u.WriteBufferSize == 0 && len(buf) >= maxFrameHeaderSize+256 { | ||||
| 		// Reuse hijacked write buffer as connection buffer. | ||||
| 		writeBuf = buf | ||||
| 	} | ||||
| 
 | ||||
| 	c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize, u.WriteBufferPool, br, writeBuf) | ||||
| 	c.subprotocol = subprotocol | ||||
| 
 | ||||
| 	if compress { | ||||
| 		c.newCompressionWriter = compressNoContextTakeover | ||||
| 		c.newDecompressionReader = decompressNoContextTakeover | ||||
| 	} | ||||
| 
 | ||||
| 	// Use larger of hijacked buffer and connection write buffer for header. | ||||
| 	p := buf | ||||
| 	if len(c.writeBuf) > len(p) { | ||||
| 		p = c.writeBuf | ||||
| 	} | ||||
| 	p = p[: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 == "Sec-Websocket-Protocol" { | ||||
| 			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. | ||||
| // | ||||
| // Deprecated: Use websocket.Upgrader instead. | ||||
| // | ||||
| // 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", http.StatusForbidden) | ||||
| //		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 { | ||||
| 	h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol")) | ||||
| 	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") | ||||
| } | ||||
| 
 | ||||
| // bufioReaderSize size returns the size of a bufio.Reader. | ||||
| func bufioReaderSize(originalReader io.Reader, br *bufio.Reader) int { | ||||
| 	// This code assumes that peek on a reset reader returns | ||||
| 	// bufio.Reader.buf[:0]. | ||||
| 	// TODO: Use bufio.Reader.Size() after Go 1.10 | ||||
| 	br.Reset(originalReader) | ||||
| 	if p, err := br.Peek(0); err == nil { | ||||
| 		return cap(p) | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| // writeHook is an io.Writer that records the last slice passed to it vio | ||||
| // io.Writer.Write. | ||||
| type writeHook struct { | ||||
| 	p []byte | ||||
| } | ||||
| 
 | ||||
| func (wh *writeHook) Write(p []byte) (int, error) { | ||||
| 	wh.p = p | ||||
| 	return len(p), nil | ||||
| } | ||||
| 
 | ||||
| // bufioWriterBuffer grabs the buffer from a bufio.Writer. | ||||
| func bufioWriterBuffer(originalWriter io.Writer, bw *bufio.Writer) []byte { | ||||
| 	// This code assumes that bufio.Writer.buf[:1] is passed to the | ||||
| 	// bufio.Writer's underlying writer. | ||||
| 	var wh writeHook | ||||
| 	bw.Reset(&wh) | ||||
| 	bw.WriteByte(0) | ||||
| 	bw.Flush() | ||||
| 
 | ||||
| 	bw.Reset(originalWriter) | ||||
| 
 | ||||
| 	return wh.p[:cap(wh.p)] | ||||
| } | ||||
							
								
								
									
										19
									
								
								vendor/github.com/gorilla/websocket/trace.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/github.com/gorilla/websocket/trace.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| // +build go1.8 | ||||
| 
 | ||||
| package websocket | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/tls" | ||||
| 	"net/http/httptrace" | ||||
| ) | ||||
| 
 | ||||
| func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error { | ||||
| 	if trace.TLSHandshakeStart != nil { | ||||
| 		trace.TLSHandshakeStart() | ||||
| 	} | ||||
| 	err := doHandshake(tlsConn, cfg) | ||||
| 	if trace.TLSHandshakeDone != nil { | ||||
| 		trace.TLSHandshakeDone(tlsConn.ConnectionState(), err) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										12
									
								
								vendor/github.com/gorilla/websocket/trace_17.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								vendor/github.com/gorilla/websocket/trace_17.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| // +build !go1.8 | ||||
| 
 | ||||
| package websocket | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/tls" | ||||
| 	"net/http/httptrace" | ||||
| ) | ||||
| 
 | ||||
| func doHandshakeWithTrace(trace *httptrace.ClientTrace, tlsConn *tls.Conn, cfg *tls.Config) error { | ||||
| 	return doHandshake(tlsConn, cfg) | ||||
| } | ||||
							
								
								
									
										283
									
								
								vendor/github.com/gorilla/websocket/util.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										283
									
								
								vendor/github.com/gorilla/websocket/util.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,283 @@ | |||
| // 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 ( | ||||
| 	"crypto/rand" | ||||
| 	"crypto/sha1" | ||||
| 	"encoding/base64" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
| 
 | ||||
| var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") | ||||
| 
 | ||||
| func computeAcceptKey(challengeKey string) string { | ||||
| 	h := sha1.New() | ||||
| 	h.Write([]byte(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 | ||||
| } | ||||
| 
 | ||||
| // Token octets per RFC 2616. | ||||
| var isTokenOctet = [256]bool{ | ||||
| 	'!':  true, | ||||
| 	'#':  true, | ||||
| 	'$':  true, | ||||
| 	'%':  true, | ||||
| 	'&':  true, | ||||
| 	'\'': true, | ||||
| 	'*':  true, | ||||
| 	'+':  true, | ||||
| 	'-':  true, | ||||
| 	'.':  true, | ||||
| 	'0':  true, | ||||
| 	'1':  true, | ||||
| 	'2':  true, | ||||
| 	'3':  true, | ||||
| 	'4':  true, | ||||
| 	'5':  true, | ||||
| 	'6':  true, | ||||
| 	'7':  true, | ||||
| 	'8':  true, | ||||
| 	'9':  true, | ||||
| 	'A':  true, | ||||
| 	'B':  true, | ||||
| 	'C':  true, | ||||
| 	'D':  true, | ||||
| 	'E':  true, | ||||
| 	'F':  true, | ||||
| 	'G':  true, | ||||
| 	'H':  true, | ||||
| 	'I':  true, | ||||
| 	'J':  true, | ||||
| 	'K':  true, | ||||
| 	'L':  true, | ||||
| 	'M':  true, | ||||
| 	'N':  true, | ||||
| 	'O':  true, | ||||
| 	'P':  true, | ||||
| 	'Q':  true, | ||||
| 	'R':  true, | ||||
| 	'S':  true, | ||||
| 	'T':  true, | ||||
| 	'U':  true, | ||||
| 	'W':  true, | ||||
| 	'V':  true, | ||||
| 	'X':  true, | ||||
| 	'Y':  true, | ||||
| 	'Z':  true, | ||||
| 	'^':  true, | ||||
| 	'_':  true, | ||||
| 	'`':  true, | ||||
| 	'a':  true, | ||||
| 	'b':  true, | ||||
| 	'c':  true, | ||||
| 	'd':  true, | ||||
| 	'e':  true, | ||||
| 	'f':  true, | ||||
| 	'g':  true, | ||||
| 	'h':  true, | ||||
| 	'i':  true, | ||||
| 	'j':  true, | ||||
| 	'k':  true, | ||||
| 	'l':  true, | ||||
| 	'm':  true, | ||||
| 	'n':  true, | ||||
| 	'o':  true, | ||||
| 	'p':  true, | ||||
| 	'q':  true, | ||||
| 	'r':  true, | ||||
| 	's':  true, | ||||
| 	't':  true, | ||||
| 	'u':  true, | ||||
| 	'v':  true, | ||||
| 	'w':  true, | ||||
| 	'x':  true, | ||||
| 	'y':  true, | ||||
| 	'z':  true, | ||||
| 	'|':  true, | ||||
| 	'~':  true, | ||||
| } | ||||
| 
 | ||||
| // skipSpace returns a slice of the string s with all leading RFC 2616 linear | ||||
| // whitespace removed. | ||||
| func skipSpace(s string) (rest string) { | ||||
| 	i := 0 | ||||
| 	for ; i < len(s); i++ { | ||||
| 		if b := s[i]; b != ' ' && b != '\t' { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return s[i:] | ||||
| } | ||||
| 
 | ||||
| // nextToken returns the leading RFC 2616 token of s and the string following | ||||
| // the token. | ||||
| func nextToken(s string) (token, rest string) { | ||||
| 	i := 0 | ||||
| 	for ; i < len(s); i++ { | ||||
| 		if !isTokenOctet[s[i]] { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return s[:i], s[i:] | ||||
| } | ||||
| 
 | ||||
| // nextTokenOrQuoted returns the leading token or quoted string per RFC 2616 | ||||
| // and the string following the token or quoted string. | ||||
| 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 "", "" | ||||
| } | ||||
| 
 | ||||
| // equalASCIIFold returns true if s is equal to t with ASCII case folding as | ||||
| // defined in RFC 4790. | ||||
| func equalASCIIFold(s, t string) bool { | ||||
| 	for s != "" && t != "" { | ||||
| 		sr, size := utf8.DecodeRuneInString(s) | ||||
| 		s = s[size:] | ||||
| 		tr, size := utf8.DecodeRuneInString(t) | ||||
| 		t = t[size:] | ||||
| 		if sr == tr { | ||||
| 			continue | ||||
| 		} | ||||
| 		if 'A' <= sr && sr <= 'Z' { | ||||
| 			sr = sr + 'a' - 'A' | ||||
| 		} | ||||
| 		if 'A' <= tr && tr <= 'Z' { | ||||
| 			tr = tr + 'a' - 'A' | ||||
| 		} | ||||
| 		if sr != tr { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return s == t | ||||
| } | ||||
| 
 | ||||
| // tokenListContainsValue returns true if the 1#token header with the given | ||||
| // name contains a token equal to value with ASCII case folding. | ||||
| 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 equalASCIIFold(t, value) { | ||||
| 				return true | ||||
| 			} | ||||
| 			if s == "" { | ||||
| 				continue headers | ||||
| 			} | ||||
| 			s = s[1:] | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // parseExtensions 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 | ||||
| } | ||||
							
								
								
									
										473
									
								
								vendor/github.com/gorilla/websocket/x_net_proxy.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										473
									
								
								vendor/github.com/gorilla/websocket/x_net_proxy.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,473 @@ | |||
| // Code generated by golang.org/x/tools/cmd/bundle. DO NOT EDIT. | ||||
| //go:generate bundle -o x_net_proxy.go golang.org/x/net/proxy | ||||
| 
 | ||||
| // Package proxy provides support for a variety of protocols to proxy network | ||||
| // data. | ||||
| // | ||||
| 
 | ||||
| package websocket | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| ) | ||||
| 
 | ||||
| type proxy_direct struct{} | ||||
| 
 | ||||
| // Direct is a direct proxy: one that makes network connections directly. | ||||
| var proxy_Direct = proxy_direct{} | ||||
| 
 | ||||
| func (proxy_direct) Dial(network, addr string) (net.Conn, error) { | ||||
| 	return net.Dial(network, addr) | ||||
| } | ||||
| 
 | ||||
| // A PerHost directs connections to a default Dialer unless the host name | ||||
| // requested matches one of a number of exceptions. | ||||
| type proxy_PerHost struct { | ||||
| 	def, bypass proxy_Dialer | ||||
| 
 | ||||
| 	bypassNetworks []*net.IPNet | ||||
| 	bypassIPs      []net.IP | ||||
| 	bypassZones    []string | ||||
| 	bypassHosts    []string | ||||
| } | ||||
| 
 | ||||
| // NewPerHost returns a PerHost Dialer that directs connections to either | ||||
| // defaultDialer or bypass, depending on whether the connection matches one of | ||||
| // the configured rules. | ||||
| func proxy_NewPerHost(defaultDialer, bypass proxy_Dialer) *proxy_PerHost { | ||||
| 	return &proxy_PerHost{ | ||||
| 		def:    defaultDialer, | ||||
| 		bypass: bypass, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Dial connects to the address addr on the given network through either | ||||
| // defaultDialer or bypass. | ||||
| func (p *proxy_PerHost) Dial(network, addr string) (c net.Conn, err error) { | ||||
| 	host, _, err := net.SplitHostPort(addr) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return p.dialerForRequest(host).Dial(network, addr) | ||||
| } | ||||
| 
 | ||||
| func (p *proxy_PerHost) dialerForRequest(host string) proxy_Dialer { | ||||
| 	if ip := net.ParseIP(host); ip != nil { | ||||
| 		for _, net := range p.bypassNetworks { | ||||
| 			if net.Contains(ip) { | ||||
| 				return p.bypass | ||||
| 			} | ||||
| 		} | ||||
| 		for _, bypassIP := range p.bypassIPs { | ||||
| 			if bypassIP.Equal(ip) { | ||||
| 				return p.bypass | ||||
| 			} | ||||
| 		} | ||||
| 		return p.def | ||||
| 	} | ||||
| 
 | ||||
| 	for _, zone := range p.bypassZones { | ||||
| 		if strings.HasSuffix(host, zone) { | ||||
| 			return p.bypass | ||||
| 		} | ||||
| 		if host == zone[1:] { | ||||
| 			// For a zone ".example.com", we match "example.com" | ||||
| 			// too. | ||||
| 			return p.bypass | ||||
| 		} | ||||
| 	} | ||||
| 	for _, bypassHost := range p.bypassHosts { | ||||
| 		if bypassHost == host { | ||||
| 			return p.bypass | ||||
| 		} | ||||
| 	} | ||||
| 	return p.def | ||||
| } | ||||
| 
 | ||||
| // AddFromString parses a string that contains comma-separated values | ||||
| // specifying hosts that should use the bypass proxy. Each value is either an | ||||
| // IP address, a CIDR range, a zone (*.example.com) or a host name | ||||
| // (localhost). A best effort is made to parse the string and errors are | ||||
| // ignored. | ||||
| func (p *proxy_PerHost) AddFromString(s string) { | ||||
| 	hosts := strings.Split(s, ",") | ||||
| 	for _, host := range hosts { | ||||
| 		host = strings.TrimSpace(host) | ||||
| 		if len(host) == 0 { | ||||
| 			continue | ||||
| 		} | ||||
| 		if strings.Contains(host, "/") { | ||||
| 			// We assume that it's a CIDR address like 127.0.0.0/8 | ||||
| 			if _, net, err := net.ParseCIDR(host); err == nil { | ||||
| 				p.AddNetwork(net) | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		if ip := net.ParseIP(host); ip != nil { | ||||
| 			p.AddIP(ip) | ||||
| 			continue | ||||
| 		} | ||||
| 		if strings.HasPrefix(host, "*.") { | ||||
| 			p.AddZone(host[1:]) | ||||
| 			continue | ||||
| 		} | ||||
| 		p.AddHost(host) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // AddIP specifies an IP address that will use the bypass proxy. Note that | ||||
| // this will only take effect if a literal IP address is dialed. A connection | ||||
| // to a named host will never match an IP. | ||||
| func (p *proxy_PerHost) AddIP(ip net.IP) { | ||||
| 	p.bypassIPs = append(p.bypassIPs, ip) | ||||
| } | ||||
| 
 | ||||
| // AddNetwork specifies an IP range that will use the bypass proxy. Note that | ||||
| // this will only take effect if a literal IP address is dialed. A connection | ||||
| // to a named host will never match. | ||||
| func (p *proxy_PerHost) AddNetwork(net *net.IPNet) { | ||||
| 	p.bypassNetworks = append(p.bypassNetworks, net) | ||||
| } | ||||
| 
 | ||||
| // AddZone specifies a DNS suffix that will use the bypass proxy. A zone of | ||||
| // "example.com" matches "example.com" and all of its subdomains. | ||||
| func (p *proxy_PerHost) AddZone(zone string) { | ||||
| 	if strings.HasSuffix(zone, ".") { | ||||
| 		zone = zone[:len(zone)-1] | ||||
| 	} | ||||
| 	if !strings.HasPrefix(zone, ".") { | ||||
| 		zone = "." + zone | ||||
| 	} | ||||
| 	p.bypassZones = append(p.bypassZones, zone) | ||||
| } | ||||
| 
 | ||||
| // AddHost specifies a host name that will use the bypass proxy. | ||||
| func (p *proxy_PerHost) AddHost(host string) { | ||||
| 	if strings.HasSuffix(host, ".") { | ||||
| 		host = host[:len(host)-1] | ||||
| 	} | ||||
| 	p.bypassHosts = append(p.bypassHosts, host) | ||||
| } | ||||
| 
 | ||||
| // A Dialer is a means to establish a connection. | ||||
| type proxy_Dialer interface { | ||||
| 	// Dial connects to the given address via the proxy. | ||||
| 	Dial(network, addr string) (c net.Conn, err error) | ||||
| } | ||||
| 
 | ||||
| // Auth contains authentication parameters that specific Dialers may require. | ||||
| type proxy_Auth struct { | ||||
| 	User, Password string | ||||
| } | ||||
| 
 | ||||
| // FromEnvironment returns the dialer specified by the proxy related variables in | ||||
| // the environment. | ||||
| func proxy_FromEnvironment() proxy_Dialer { | ||||
| 	allProxy := proxy_allProxyEnv.Get() | ||||
| 	if len(allProxy) == 0 { | ||||
| 		return proxy_Direct | ||||
| 	} | ||||
| 
 | ||||
| 	proxyURL, err := url.Parse(allProxy) | ||||
| 	if err != nil { | ||||
| 		return proxy_Direct | ||||
| 	} | ||||
| 	proxy, err := proxy_FromURL(proxyURL, proxy_Direct) | ||||
| 	if err != nil { | ||||
| 		return proxy_Direct | ||||
| 	} | ||||
| 
 | ||||
| 	noProxy := proxy_noProxyEnv.Get() | ||||
| 	if len(noProxy) == 0 { | ||||
| 		return proxy | ||||
| 	} | ||||
| 
 | ||||
| 	perHost := proxy_NewPerHost(proxy, proxy_Direct) | ||||
| 	perHost.AddFromString(noProxy) | ||||
| 	return perHost | ||||
| } | ||||
| 
 | ||||
| // proxySchemes is a map from URL schemes to a function that creates a Dialer | ||||
| // from a URL with such a scheme. | ||||
| var proxy_proxySchemes map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error) | ||||
| 
 | ||||
| // RegisterDialerType takes a URL scheme and a function to generate Dialers from | ||||
| // a URL with that scheme and a forwarding Dialer. Registered schemes are used | ||||
| // by FromURL. | ||||
| func proxy_RegisterDialerType(scheme string, f func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) { | ||||
| 	if proxy_proxySchemes == nil { | ||||
| 		proxy_proxySchemes = make(map[string]func(*url.URL, proxy_Dialer) (proxy_Dialer, error)) | ||||
| 	} | ||||
| 	proxy_proxySchemes[scheme] = f | ||||
| } | ||||
| 
 | ||||
| // FromURL returns a Dialer given a URL specification and an underlying | ||||
| // Dialer for it to make network requests. | ||||
| func proxy_FromURL(u *url.URL, forward proxy_Dialer) (proxy_Dialer, error) { | ||||
| 	var auth *proxy_Auth | ||||
| 	if u.User != nil { | ||||
| 		auth = new(proxy_Auth) | ||||
| 		auth.User = u.User.Username() | ||||
| 		if p, ok := u.User.Password(); ok { | ||||
| 			auth.Password = p | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	switch u.Scheme { | ||||
| 	case "socks5": | ||||
| 		return proxy_SOCKS5("tcp", u.Host, auth, forward) | ||||
| 	} | ||||
| 
 | ||||
| 	// If the scheme doesn't match any of the built-in schemes, see if it | ||||
| 	// was registered by another package. | ||||
| 	if proxy_proxySchemes != nil { | ||||
| 		if f, ok := proxy_proxySchemes[u.Scheme]; ok { | ||||
| 			return f(u, forward) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return nil, errors.New("proxy: unknown scheme: " + u.Scheme) | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	proxy_allProxyEnv = &proxy_envOnce{ | ||||
| 		names: []string{"ALL_PROXY", "all_proxy"}, | ||||
| 	} | ||||
| 	proxy_noProxyEnv = &proxy_envOnce{ | ||||
| 		names: []string{"NO_PROXY", "no_proxy"}, | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| // envOnce looks up an environment variable (optionally by multiple | ||||
| // names) once. It mitigates expensive lookups on some platforms | ||||
| // (e.g. Windows). | ||||
| // (Borrowed from net/http/transport.go) | ||||
| type proxy_envOnce struct { | ||||
| 	names []string | ||||
| 	once  sync.Once | ||||
| 	val   string | ||||
| } | ||||
| 
 | ||||
| func (e *proxy_envOnce) Get() string { | ||||
| 	e.once.Do(e.init) | ||||
| 	return e.val | ||||
| } | ||||
| 
 | ||||
| func (e *proxy_envOnce) init() { | ||||
| 	for _, n := range e.names { | ||||
| 		e.val = os.Getenv(n) | ||||
| 		if e.val != "" { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // SOCKS5 returns a Dialer that makes SOCKSv5 connections to the given address | ||||
| // with an optional username and password. See RFC 1928 and RFC 1929. | ||||
| func proxy_SOCKS5(network, addr string, auth *proxy_Auth, forward proxy_Dialer) (proxy_Dialer, error) { | ||||
| 	s := &proxy_socks5{ | ||||
| 		network: network, | ||||
| 		addr:    addr, | ||||
| 		forward: forward, | ||||
| 	} | ||||
| 	if auth != nil { | ||||
| 		s.user = auth.User | ||||
| 		s.password = auth.Password | ||||
| 	} | ||||
| 
 | ||||
| 	return s, nil | ||||
| } | ||||
| 
 | ||||
| type proxy_socks5 struct { | ||||
| 	user, password string | ||||
| 	network, addr  string | ||||
| 	forward        proxy_Dialer | ||||
| } | ||||
| 
 | ||||
| const proxy_socks5Version = 5 | ||||
| 
 | ||||
| const ( | ||||
| 	proxy_socks5AuthNone     = 0 | ||||
| 	proxy_socks5AuthPassword = 2 | ||||
| ) | ||||
| 
 | ||||
| const proxy_socks5Connect = 1 | ||||
| 
 | ||||
| const ( | ||||
| 	proxy_socks5IP4    = 1 | ||||
| 	proxy_socks5Domain = 3 | ||||
| 	proxy_socks5IP6    = 4 | ||||
| ) | ||||
| 
 | ||||
| var proxy_socks5Errors = []string{ | ||||
| 	"", | ||||
| 	"general failure", | ||||
| 	"connection forbidden", | ||||
| 	"network unreachable", | ||||
| 	"host unreachable", | ||||
| 	"connection refused", | ||||
| 	"TTL expired", | ||||
| 	"command not supported", | ||||
| 	"address type not supported", | ||||
| } | ||||
| 
 | ||||
| // Dial connects to the address addr on the given network via the SOCKS5 proxy. | ||||
| func (s *proxy_socks5) Dial(network, addr string) (net.Conn, error) { | ||||
| 	switch network { | ||||
| 	case "tcp", "tcp6", "tcp4": | ||||
| 	default: | ||||
| 		return nil, errors.New("proxy: no support for SOCKS5 proxy connections of type " + network) | ||||
| 	} | ||||
| 
 | ||||
| 	conn, err := s.forward.Dial(s.network, s.addr) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if err := s.connect(conn, addr); err != nil { | ||||
| 		conn.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return conn, nil | ||||
| } | ||||
| 
 | ||||
| // connect takes an existing connection to a socks5 proxy server, | ||||
| // and commands the server to extend that connection to target, | ||||
| // which must be a canonical address with a host and port. | ||||
| func (s *proxy_socks5) connect(conn net.Conn, target string) error { | ||||
| 	host, portStr, err := net.SplitHostPort(target) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	port, err := strconv.Atoi(portStr) | ||||
| 	if err != nil { | ||||
| 		return errors.New("proxy: failed to parse port number: " + portStr) | ||||
| 	} | ||||
| 	if port < 1 || port > 0xffff { | ||||
| 		return errors.New("proxy: port number out of range: " + portStr) | ||||
| 	} | ||||
| 
 | ||||
| 	// the size here is just an estimate | ||||
| 	buf := make([]byte, 0, 6+len(host)) | ||||
| 
 | ||||
| 	buf = append(buf, proxy_socks5Version) | ||||
| 	if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 { | ||||
| 		buf = append(buf, 2 /* num auth methods */, proxy_socks5AuthNone, proxy_socks5AuthPassword) | ||||
| 	} else { | ||||
| 		buf = append(buf, 1 /* num auth methods */, proxy_socks5AuthNone) | ||||
| 	} | ||||
| 
 | ||||
| 	if _, err := conn.Write(buf); err != nil { | ||||
| 		return errors.New("proxy: failed to write greeting to SOCKS5 proxy at " + s.addr + ": " + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	if _, err := io.ReadFull(conn, buf[:2]); err != nil { | ||||
| 		return errors.New("proxy: failed to read greeting from SOCKS5 proxy at " + s.addr + ": " + err.Error()) | ||||
| 	} | ||||
| 	if buf[0] != 5 { | ||||
| 		return errors.New("proxy: SOCKS5 proxy at " + s.addr + " has unexpected version " + strconv.Itoa(int(buf[0]))) | ||||
| 	} | ||||
| 	if buf[1] == 0xff { | ||||
| 		return errors.New("proxy: SOCKS5 proxy at " + s.addr + " requires authentication") | ||||
| 	} | ||||
| 
 | ||||
| 	// See RFC 1929 | ||||
| 	if buf[1] == proxy_socks5AuthPassword { | ||||
| 		buf = buf[:0] | ||||
| 		buf = append(buf, 1 /* password protocol version */) | ||||
| 		buf = append(buf, uint8(len(s.user))) | ||||
| 		buf = append(buf, s.user...) | ||||
| 		buf = append(buf, uint8(len(s.password))) | ||||
| 		buf = append(buf, s.password...) | ||||
| 
 | ||||
| 		if _, err := conn.Write(buf); err != nil { | ||||
| 			return errors.New("proxy: failed to write authentication request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) | ||||
| 		} | ||||
| 
 | ||||
| 		if _, err := io.ReadFull(conn, buf[:2]); err != nil { | ||||
| 			return errors.New("proxy: failed to read authentication reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) | ||||
| 		} | ||||
| 
 | ||||
| 		if buf[1] != 0 { | ||||
| 			return errors.New("proxy: SOCKS5 proxy at " + s.addr + " rejected username/password") | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	buf = buf[:0] | ||||
| 	buf = append(buf, proxy_socks5Version, proxy_socks5Connect, 0 /* reserved */) | ||||
| 
 | ||||
| 	if ip := net.ParseIP(host); ip != nil { | ||||
| 		if ip4 := ip.To4(); ip4 != nil { | ||||
| 			buf = append(buf, proxy_socks5IP4) | ||||
| 			ip = ip4 | ||||
| 		} else { | ||||
| 			buf = append(buf, proxy_socks5IP6) | ||||
| 		} | ||||
| 		buf = append(buf, ip...) | ||||
| 	} else { | ||||
| 		if len(host) > 255 { | ||||
| 			return errors.New("proxy: destination host name too long: " + host) | ||||
| 		} | ||||
| 		buf = append(buf, proxy_socks5Domain) | ||||
| 		buf = append(buf, byte(len(host))) | ||||
| 		buf = append(buf, host...) | ||||
| 	} | ||||
| 	buf = append(buf, byte(port>>8), byte(port)) | ||||
| 
 | ||||
| 	if _, err := conn.Write(buf); err != nil { | ||||
| 		return errors.New("proxy: failed to write connect request to SOCKS5 proxy at " + s.addr + ": " + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	if _, err := io.ReadFull(conn, buf[:4]); err != nil { | ||||
| 		return errors.New("proxy: failed to read connect reply from SOCKS5 proxy at " + s.addr + ": " + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	failure := "unknown error" | ||||
| 	if int(buf[1]) < len(proxy_socks5Errors) { | ||||
| 		failure = proxy_socks5Errors[buf[1]] | ||||
| 	} | ||||
| 
 | ||||
| 	if len(failure) > 0 { | ||||
| 		return errors.New("proxy: SOCKS5 proxy at " + s.addr + " failed to connect: " + failure) | ||||
| 	} | ||||
| 
 | ||||
| 	bytesToDiscard := 0 | ||||
| 	switch buf[3] { | ||||
| 	case proxy_socks5IP4: | ||||
| 		bytesToDiscard = net.IPv4len | ||||
| 	case proxy_socks5IP6: | ||||
| 		bytesToDiscard = net.IPv6len | ||||
| 	case proxy_socks5Domain: | ||||
| 		_, err := io.ReadFull(conn, buf[:1]) | ||||
| 		if err != nil { | ||||
| 			return errors.New("proxy: failed to read domain length from SOCKS5 proxy at " + s.addr + ": " + err.Error()) | ||||
| 		} | ||||
| 		bytesToDiscard = int(buf[0]) | ||||
| 	default: | ||||
| 		return errors.New("proxy: got unknown address type " + strconv.Itoa(int(buf[3])) + " from SOCKS5 proxy at " + s.addr) | ||||
| 	} | ||||
| 
 | ||||
| 	if cap(buf) < bytesToDiscard { | ||||
| 		buf = make([]byte, bytesToDiscard) | ||||
| 	} else { | ||||
| 		buf = buf[:bytesToDiscard] | ||||
| 	} | ||||
| 	if _, err := io.ReadFull(conn, buf); err != nil { | ||||
| 		return errors.New("proxy: failed to read address from SOCKS5 proxy at " + s.addr + ": " + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	// Also need to discard the port number | ||||
| 	if _, err := io.ReadFull(conn, buf[:2]); err != nil { | ||||
| 		return errors.New("proxy: failed to read port from SOCKS5 proxy at " + s.addr + ": " + err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue