Naive implementation that always return min value
This commit is contained in:
		
							
								
								
									
										3
									
								
								vendor/golang.org/x/net/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/golang.org/x/net/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
# This source code refers to The Go Authors for copyright purposes.
 | 
			
		||||
# The master list of authors is in the main Go distribution,
 | 
			
		||||
# visible at http://tip.golang.org/AUTHORS.
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/golang.org/x/net/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/golang.org/x/net/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
# This source code was written by the Go contributors.
 | 
			
		||||
# The master list of contributors is in the main Go distribution,
 | 
			
		||||
# visible at http://tip.golang.org/CONTRIBUTORS.
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/golang.org/x/net/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/golang.org/x/net/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
Copyright (c) 2009 The Go 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.
 | 
			
		||||
   * Neither the name of Google Inc. nor the names of its
 | 
			
		||||
contributors may be used to endorse or promote products derived from
 | 
			
		||||
this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
OWNER 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.
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/golang.org/x/net/PATENTS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/golang.org/x/net/PATENTS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
Additional IP Rights Grant (Patents)
 | 
			
		||||
 | 
			
		||||
"This implementation" means the copyrightable works distributed by
 | 
			
		||||
Google as part of the Go project.
 | 
			
		||||
 | 
			
		||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
 | 
			
		||||
no-charge, royalty-free, irrevocable (except as stated in this section)
 | 
			
		||||
patent license to make, have made, use, offer to sell, sell, import,
 | 
			
		||||
transfer and otherwise run, modify and propagate the contents of this
 | 
			
		||||
implementation of Go, where such license applies only to those patent
 | 
			
		||||
claims, both currently owned or controlled by Google and acquired in
 | 
			
		||||
the future, licensable by Google that are necessarily infringed by this
 | 
			
		||||
implementation of Go.  This grant does not include claims that would be
 | 
			
		||||
infringed only as a consequence of further modification of this
 | 
			
		||||
implementation.  If you or your agent or exclusive licensee institute or
 | 
			
		||||
order or agree to the institution of patent litigation against any
 | 
			
		||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
 | 
			
		||||
that this implementation of Go or any code incorporated within this
 | 
			
		||||
implementation of Go constitutes direct or contributory patent
 | 
			
		||||
infringement, or inducement of patent infringement, then any patent
 | 
			
		||||
rights granted to you under this License for this implementation of Go
 | 
			
		||||
shall terminate as of the date such litigation is filed.
 | 
			
		||||
							
								
								
									
										168
									
								
								vendor/golang.org/x/net/internal/socks/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								vendor/golang.org/x/net/internal/socks/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
			
		||||
// Copyright 2018 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package socks
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	noDeadline   = time.Time{}
 | 
			
		||||
	aLongTimeAgo = time.Unix(1, 0)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) {
 | 
			
		||||
	host, port, err := splitHostPort(address)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
 | 
			
		||||
		c.SetDeadline(deadline)
 | 
			
		||||
		defer c.SetDeadline(noDeadline)
 | 
			
		||||
	}
 | 
			
		||||
	if ctx != context.Background() {
 | 
			
		||||
		errCh := make(chan error, 1)
 | 
			
		||||
		done := make(chan struct{})
 | 
			
		||||
		defer func() {
 | 
			
		||||
			close(done)
 | 
			
		||||
			if ctxErr == nil {
 | 
			
		||||
				ctxErr = <-errCh
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
		go func() {
 | 
			
		||||
			select {
 | 
			
		||||
			case <-ctx.Done():
 | 
			
		||||
				c.SetDeadline(aLongTimeAgo)
 | 
			
		||||
				errCh <- ctx.Err()
 | 
			
		||||
			case <-done:
 | 
			
		||||
				errCh <- nil
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b := make([]byte, 0, 6+len(host)) // the size here is just an estimate
 | 
			
		||||
	b = append(b, Version5)
 | 
			
		||||
	if len(d.AuthMethods) == 0 || d.Authenticate == nil {
 | 
			
		||||
		b = append(b, 1, byte(AuthMethodNotRequired))
 | 
			
		||||
	} else {
 | 
			
		||||
		ams := d.AuthMethods
 | 
			
		||||
		if len(ams) > 255 {
 | 
			
		||||
			return nil, errors.New("too many authentication methods")
 | 
			
		||||
		}
 | 
			
		||||
		b = append(b, byte(len(ams)))
 | 
			
		||||
		for _, am := range ams {
 | 
			
		||||
			b = append(b, byte(am))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if _, ctxErr = c.Write(b); ctxErr != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if b[0] != Version5 {
 | 
			
		||||
		return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
 | 
			
		||||
	}
 | 
			
		||||
	am := AuthMethod(b[1])
 | 
			
		||||
	if am == AuthMethodNoAcceptableMethods {
 | 
			
		||||
		return nil, errors.New("no acceptable authentication methods")
 | 
			
		||||
	}
 | 
			
		||||
	if d.Authenticate != nil {
 | 
			
		||||
		if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b = b[:0]
 | 
			
		||||
	b = append(b, Version5, byte(d.cmd), 0)
 | 
			
		||||
	if ip := net.ParseIP(host); ip != nil {
 | 
			
		||||
		if ip4 := ip.To4(); ip4 != nil {
 | 
			
		||||
			b = append(b, AddrTypeIPv4)
 | 
			
		||||
			b = append(b, ip4...)
 | 
			
		||||
		} else if ip6 := ip.To16(); ip6 != nil {
 | 
			
		||||
			b = append(b, AddrTypeIPv6)
 | 
			
		||||
			b = append(b, ip6...)
 | 
			
		||||
		} else {
 | 
			
		||||
			return nil, errors.New("unknown address type")
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if len(host) > 255 {
 | 
			
		||||
			return nil, errors.New("FQDN too long")
 | 
			
		||||
		}
 | 
			
		||||
		b = append(b, AddrTypeFQDN)
 | 
			
		||||
		b = append(b, byte(len(host)))
 | 
			
		||||
		b = append(b, host...)
 | 
			
		||||
	}
 | 
			
		||||
	b = append(b, byte(port>>8), byte(port))
 | 
			
		||||
	if _, ctxErr = c.Write(b); ctxErr != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if b[0] != Version5 {
 | 
			
		||||
		return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
 | 
			
		||||
	}
 | 
			
		||||
	if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded {
 | 
			
		||||
		return nil, errors.New("unknown error " + cmdErr.String())
 | 
			
		||||
	}
 | 
			
		||||
	if b[2] != 0 {
 | 
			
		||||
		return nil, errors.New("non-zero reserved field")
 | 
			
		||||
	}
 | 
			
		||||
	l := 2
 | 
			
		||||
	var a Addr
 | 
			
		||||
	switch b[3] {
 | 
			
		||||
	case AddrTypeIPv4:
 | 
			
		||||
		l += net.IPv4len
 | 
			
		||||
		a.IP = make(net.IP, net.IPv4len)
 | 
			
		||||
	case AddrTypeIPv6:
 | 
			
		||||
		l += net.IPv6len
 | 
			
		||||
		a.IP = make(net.IP, net.IPv6len)
 | 
			
		||||
	case AddrTypeFQDN:
 | 
			
		||||
		if _, err := io.ReadFull(c, b[:1]); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		l += int(b[0])
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3])))
 | 
			
		||||
	}
 | 
			
		||||
	if cap(b) < l {
 | 
			
		||||
		b = make([]byte, l)
 | 
			
		||||
	} else {
 | 
			
		||||
		b = b[:l]
 | 
			
		||||
	}
 | 
			
		||||
	if _, ctxErr = io.ReadFull(c, b); ctxErr != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if a.IP != nil {
 | 
			
		||||
		copy(a.IP, b)
 | 
			
		||||
	} else {
 | 
			
		||||
		a.Name = string(b[:len(b)-2])
 | 
			
		||||
	}
 | 
			
		||||
	a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1])
 | 
			
		||||
	return &a, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func splitHostPort(address string) (string, int, error) {
 | 
			
		||||
	host, port, err := net.SplitHostPort(address)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", 0, err
 | 
			
		||||
	}
 | 
			
		||||
	portnum, err := strconv.Atoi(port)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", 0, err
 | 
			
		||||
	}
 | 
			
		||||
	if 1 > portnum || portnum > 0xffff {
 | 
			
		||||
		return "", 0, errors.New("port number out of range " + port)
 | 
			
		||||
	}
 | 
			
		||||
	return host, portnum, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										317
									
								
								vendor/golang.org/x/net/internal/socks/socks.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										317
									
								
								vendor/golang.org/x/net/internal/socks/socks.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,317 @@
 | 
			
		||||
// Copyright 2018 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package socks provides a SOCKS version 5 client implementation.
 | 
			
		||||
//
 | 
			
		||||
// SOCKS protocol version 5 is defined in RFC 1928.
 | 
			
		||||
// Username/Password authentication for SOCKS version 5 is defined in
 | 
			
		||||
// RFC 1929.
 | 
			
		||||
package socks
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Command represents a SOCKS command.
 | 
			
		||||
type Command int
 | 
			
		||||
 | 
			
		||||
func (cmd Command) String() string {
 | 
			
		||||
	switch cmd {
 | 
			
		||||
	case CmdConnect:
 | 
			
		||||
		return "socks connect"
 | 
			
		||||
	case cmdBind:
 | 
			
		||||
		return "socks bind"
 | 
			
		||||
	default:
 | 
			
		||||
		return "socks " + strconv.Itoa(int(cmd))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An AuthMethod represents a SOCKS authentication method.
 | 
			
		||||
type AuthMethod int
 | 
			
		||||
 | 
			
		||||
// A Reply represents a SOCKS command reply code.
 | 
			
		||||
type Reply int
 | 
			
		||||
 | 
			
		||||
func (code Reply) String() string {
 | 
			
		||||
	switch code {
 | 
			
		||||
	case StatusSucceeded:
 | 
			
		||||
		return "succeeded"
 | 
			
		||||
	case 0x01:
 | 
			
		||||
		return "general SOCKS server failure"
 | 
			
		||||
	case 0x02:
 | 
			
		||||
		return "connection not allowed by ruleset"
 | 
			
		||||
	case 0x03:
 | 
			
		||||
		return "network unreachable"
 | 
			
		||||
	case 0x04:
 | 
			
		||||
		return "host unreachable"
 | 
			
		||||
	case 0x05:
 | 
			
		||||
		return "connection refused"
 | 
			
		||||
	case 0x06:
 | 
			
		||||
		return "TTL expired"
 | 
			
		||||
	case 0x07:
 | 
			
		||||
		return "command not supported"
 | 
			
		||||
	case 0x08:
 | 
			
		||||
		return "address type not supported"
 | 
			
		||||
	default:
 | 
			
		||||
		return "unknown code: " + strconv.Itoa(int(code))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Wire protocol constants.
 | 
			
		||||
const (
 | 
			
		||||
	Version5 = 0x05
 | 
			
		||||
 | 
			
		||||
	AddrTypeIPv4 = 0x01
 | 
			
		||||
	AddrTypeFQDN = 0x03
 | 
			
		||||
	AddrTypeIPv6 = 0x04
 | 
			
		||||
 | 
			
		||||
	CmdConnect Command = 0x01 // establishes an active-open forward proxy connection
 | 
			
		||||
	cmdBind    Command = 0x02 // establishes a passive-open forward proxy connection
 | 
			
		||||
 | 
			
		||||
	AuthMethodNotRequired         AuthMethod = 0x00 // no authentication required
 | 
			
		||||
	AuthMethodUsernamePassword    AuthMethod = 0x02 // use username/password
 | 
			
		||||
	AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods
 | 
			
		||||
 | 
			
		||||
	StatusSucceeded Reply = 0x00
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// An Addr represents a SOCKS-specific address.
 | 
			
		||||
// Either Name or IP is used exclusively.
 | 
			
		||||
type Addr struct {
 | 
			
		||||
	Name string // fully-qualified domain name
 | 
			
		||||
	IP   net.IP
 | 
			
		||||
	Port int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *Addr) Network() string { return "socks" }
 | 
			
		||||
 | 
			
		||||
func (a *Addr) String() string {
 | 
			
		||||
	if a == nil {
 | 
			
		||||
		return "<nil>"
 | 
			
		||||
	}
 | 
			
		||||
	port := strconv.Itoa(a.Port)
 | 
			
		||||
	if a.IP == nil {
 | 
			
		||||
		return net.JoinHostPort(a.Name, port)
 | 
			
		||||
	}
 | 
			
		||||
	return net.JoinHostPort(a.IP.String(), port)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Conn represents a forward proxy connection.
 | 
			
		||||
type Conn struct {
 | 
			
		||||
	net.Conn
 | 
			
		||||
 | 
			
		||||
	boundAddr net.Addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BoundAddr returns the address assigned by the proxy server for
 | 
			
		||||
// connecting to the command target address from the proxy server.
 | 
			
		||||
func (c *Conn) BoundAddr() net.Addr {
 | 
			
		||||
	if c == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return c.boundAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Dialer holds SOCKS-specific options.
 | 
			
		||||
type Dialer struct {
 | 
			
		||||
	cmd          Command // either CmdConnect or cmdBind
 | 
			
		||||
	proxyNetwork string  // network between a proxy server and a client
 | 
			
		||||
	proxyAddress string  // proxy server address
 | 
			
		||||
 | 
			
		||||
	// ProxyDial specifies the optional dial function for
 | 
			
		||||
	// establishing the transport connection.
 | 
			
		||||
	ProxyDial func(context.Context, string, string) (net.Conn, error)
 | 
			
		||||
 | 
			
		||||
	// AuthMethods specifies the list of request authentication
 | 
			
		||||
	// methods.
 | 
			
		||||
	// If empty, SOCKS client requests only AuthMethodNotRequired.
 | 
			
		||||
	AuthMethods []AuthMethod
 | 
			
		||||
 | 
			
		||||
	// Authenticate specifies the optional authentication
 | 
			
		||||
	// function. It must be non-nil when AuthMethods is not empty.
 | 
			
		||||
	// It must return an error when the authentication is failed.
 | 
			
		||||
	Authenticate func(context.Context, io.ReadWriter, AuthMethod) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialContext connects to the provided address on the provided
 | 
			
		||||
// network.
 | 
			
		||||
//
 | 
			
		||||
// The returned error value may be a net.OpError. When the Op field of
 | 
			
		||||
// net.OpError contains "socks", the Source field contains a proxy
 | 
			
		||||
// server address and the Addr field contains a command target
 | 
			
		||||
// address.
 | 
			
		||||
//
 | 
			
		||||
// See func Dial of the net package of standard library for a
 | 
			
		||||
// description of the network and address parameters.
 | 
			
		||||
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
 | 
			
		||||
	if err := d.validateTarget(network, address); err != nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	if ctx == nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
 | 
			
		||||
	}
 | 
			
		||||
	var err error
 | 
			
		||||
	var c net.Conn
 | 
			
		||||
	if d.ProxyDial != nil {
 | 
			
		||||
		c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress)
 | 
			
		||||
	} else {
 | 
			
		||||
		var dd net.Dialer
 | 
			
		||||
		c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	a, err := d.connect(ctx, c, address)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		c.Close()
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	return &Conn{Conn: c, boundAddr: a}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialWithConn initiates a connection from SOCKS server to the target
 | 
			
		||||
// network and address using the connection c that is already
 | 
			
		||||
// connected to the SOCKS server.
 | 
			
		||||
//
 | 
			
		||||
// It returns the connection's local address assigned by the SOCKS
 | 
			
		||||
// server.
 | 
			
		||||
func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) {
 | 
			
		||||
	if err := d.validateTarget(network, address); err != nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	if ctx == nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
 | 
			
		||||
	}
 | 
			
		||||
	a, err := d.connect(ctx, c, address)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	return a, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dial connects to the provided address on the provided network.
 | 
			
		||||
//
 | 
			
		||||
// Unlike DialContext, it returns a raw transport connection instead
 | 
			
		||||
// of a forward proxy connection.
 | 
			
		||||
//
 | 
			
		||||
// Deprecated: Use DialContext or DialWithConn instead.
 | 
			
		||||
func (d *Dialer) Dial(network, address string) (net.Conn, error) {
 | 
			
		||||
	if err := d.validateTarget(network, address); err != nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	var err error
 | 
			
		||||
	var c net.Conn
 | 
			
		||||
	if d.ProxyDial != nil {
 | 
			
		||||
		c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress)
 | 
			
		||||
	} else {
 | 
			
		||||
		c, err = net.Dial(d.proxyNetwork, d.proxyAddress)
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		proxy, dst, _ := d.pathAddrs(address)
 | 
			
		||||
		return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil {
 | 
			
		||||
		c.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return c, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Dialer) validateTarget(network, address string) error {
 | 
			
		||||
	switch network {
 | 
			
		||||
	case "tcp", "tcp6", "tcp4":
 | 
			
		||||
	default:
 | 
			
		||||
		return errors.New("network not implemented")
 | 
			
		||||
	}
 | 
			
		||||
	switch d.cmd {
 | 
			
		||||
	case CmdConnect, cmdBind:
 | 
			
		||||
	default:
 | 
			
		||||
		return errors.New("command not implemented")
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {
 | 
			
		||||
	for i, s := range []string{d.proxyAddress, address} {
 | 
			
		||||
		host, port, err := splitHostPort(s)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, nil, err
 | 
			
		||||
		}
 | 
			
		||||
		a := &Addr{Port: port}
 | 
			
		||||
		a.IP = net.ParseIP(host)
 | 
			
		||||
		if a.IP == nil {
 | 
			
		||||
			a.Name = host
 | 
			
		||||
		}
 | 
			
		||||
		if i == 0 {
 | 
			
		||||
			proxy = a
 | 
			
		||||
		} else {
 | 
			
		||||
			dst = a
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewDialer returns a new Dialer that dials through the provided
 | 
			
		||||
// proxy server's network and address.
 | 
			
		||||
func NewDialer(network, address string) *Dialer {
 | 
			
		||||
	return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	authUsernamePasswordVersion = 0x01
 | 
			
		||||
	authStatusSucceeded         = 0x00
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// UsernamePassword are the credentials for the username/password
 | 
			
		||||
// authentication method.
 | 
			
		||||
type UsernamePassword struct {
 | 
			
		||||
	Username string
 | 
			
		||||
	Password string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Authenticate authenticates a pair of username and password with the
 | 
			
		||||
// proxy server.
 | 
			
		||||
func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error {
 | 
			
		||||
	switch auth {
 | 
			
		||||
	case AuthMethodNotRequired:
 | 
			
		||||
		return nil
 | 
			
		||||
	case AuthMethodUsernamePassword:
 | 
			
		||||
		if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 {
 | 
			
		||||
			return errors.New("invalid username/password")
 | 
			
		||||
		}
 | 
			
		||||
		b := []byte{authUsernamePasswordVersion}
 | 
			
		||||
		b = append(b, byte(len(up.Username)))
 | 
			
		||||
		b = append(b, up.Username...)
 | 
			
		||||
		b = append(b, byte(len(up.Password)))
 | 
			
		||||
		b = append(b, up.Password...)
 | 
			
		||||
		// TODO(mikio): handle IO deadlines and cancelation if
 | 
			
		||||
		// necessary
 | 
			
		||||
		if _, err := rw.Write(b); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if _, err := io.ReadFull(rw, b[:2]); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if b[0] != authUsernamePasswordVersion {
 | 
			
		||||
			return errors.New("invalid username/password version")
 | 
			
		||||
		}
 | 
			
		||||
		if b[1] != authStatusSucceeded {
 | 
			
		||||
			return errors.New("username/password authentication failed")
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								vendor/golang.org/x/net/proxy/dial.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								vendor/golang.org/x/net/proxy/dial.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
// Copyright 2019 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package proxy
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"net"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A ContextDialer dials using a context.
 | 
			
		||||
type ContextDialer interface {
 | 
			
		||||
	DialContext(ctx context.Context, network, address string) (net.Conn, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dial works like DialContext on net.Dialer but using a dialer returned by FromEnvironment.
 | 
			
		||||
//
 | 
			
		||||
// The passed ctx is only used for returning the Conn, not the lifetime of the Conn.
 | 
			
		||||
//
 | 
			
		||||
// Custom dialers (registered via RegisterDialerType) that do not implement ContextDialer
 | 
			
		||||
// can leak a goroutine for as long as it takes the underlying Dialer implementation to timeout.
 | 
			
		||||
//
 | 
			
		||||
// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed.
 | 
			
		||||
func Dial(ctx context.Context, network, address string) (net.Conn, error) {
 | 
			
		||||
	d := FromEnvironment()
 | 
			
		||||
	if xd, ok := d.(ContextDialer); ok {
 | 
			
		||||
		return xd.DialContext(ctx, network, address)
 | 
			
		||||
	}
 | 
			
		||||
	return dialContext(ctx, d, network, address)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WARNING: this can leak a goroutine for as long as the underlying Dialer implementation takes to timeout
 | 
			
		||||
// A Conn returned from a successful Dial after the context has been cancelled will be immediately closed.
 | 
			
		||||
func dialContext(ctx context.Context, d Dialer, network, address string) (net.Conn, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		conn net.Conn
 | 
			
		||||
		done = make(chan struct{}, 1)
 | 
			
		||||
		err  error
 | 
			
		||||
	)
 | 
			
		||||
	go func() {
 | 
			
		||||
		conn, err = d.Dial(network, address)
 | 
			
		||||
		close(done)
 | 
			
		||||
		if conn != nil && ctx.Err() != nil {
 | 
			
		||||
			conn.Close()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	select {
 | 
			
		||||
	case <-ctx.Done():
 | 
			
		||||
		err = ctx.Err()
 | 
			
		||||
	case <-done:
 | 
			
		||||
	}
 | 
			
		||||
	return conn, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								vendor/golang.org/x/net/proxy/direct.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								vendor/golang.org/x/net/proxy/direct.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package proxy
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"net"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type direct struct{}
 | 
			
		||||
 | 
			
		||||
// Direct implements Dialer by making network connections directly using net.Dial or net.DialContext.
 | 
			
		||||
var Direct = direct{}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	_ Dialer        = Direct
 | 
			
		||||
	_ ContextDialer = Direct
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Dial directly invokes net.Dial with the supplied parameters.
 | 
			
		||||
func (direct) Dial(network, addr string) (net.Conn, error) {
 | 
			
		||||
	return net.Dial(network, addr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialContext instantiates a net.Dialer and invokes its DialContext receiver with the supplied parameters.
 | 
			
		||||
func (direct) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
 | 
			
		||||
	var d net.Dialer
 | 
			
		||||
	return d.DialContext(ctx, network, addr)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										155
									
								
								vendor/golang.org/x/net/proxy/per_host.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								vendor/golang.org/x/net/proxy/per_host.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package proxy
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"net"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A PerHost directs connections to a default Dialer unless the host name
 | 
			
		||||
// requested matches one of a number of exceptions.
 | 
			
		||||
type PerHost struct {
 | 
			
		||||
	def, bypass 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 NewPerHost(defaultDialer, bypass Dialer) *PerHost {
 | 
			
		||||
	return &PerHost{
 | 
			
		||||
		def:    defaultDialer,
 | 
			
		||||
		bypass: bypass,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dial connects to the address addr on the given network through either
 | 
			
		||||
// defaultDialer or bypass.
 | 
			
		||||
func (p *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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialContext connects to the address addr on the given network through either
 | 
			
		||||
// defaultDialer or bypass.
 | 
			
		||||
func (p *PerHost) DialContext(ctx context.Context, network, addr string) (c net.Conn, err error) {
 | 
			
		||||
	host, _, err := net.SplitHostPort(addr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	d := p.dialerForRequest(host)
 | 
			
		||||
	if x, ok := d.(ContextDialer); ok {
 | 
			
		||||
		return x.DialContext(ctx, network, addr)
 | 
			
		||||
	}
 | 
			
		||||
	return dialContext(ctx, d, network, addr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *PerHost) dialerForRequest(host string) 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 *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 *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 *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 *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 *PerHost) AddHost(host string) {
 | 
			
		||||
	if strings.HasSuffix(host, ".") {
 | 
			
		||||
		host = host[:len(host)-1]
 | 
			
		||||
	}
 | 
			
		||||
	p.bypassHosts = append(p.bypassHosts, host)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										149
									
								
								vendor/golang.org/x/net/proxy/proxy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								vendor/golang.org/x/net/proxy/proxy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,149 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package proxy provides support for a variety of protocols to proxy network
 | 
			
		||||
// data.
 | 
			
		||||
package proxy // import "golang.org/x/net/proxy"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A Dialer is a means to establish a connection.
 | 
			
		||||
// Custom dialers should also implement ContextDialer.
 | 
			
		||||
type 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 Auth struct {
 | 
			
		||||
	User, Password string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromEnvironment returns the dialer specified by the proxy-related
 | 
			
		||||
// variables in the environment and makes underlying connections
 | 
			
		||||
// directly.
 | 
			
		||||
func FromEnvironment() Dialer {
 | 
			
		||||
	return FromEnvironmentUsing(Direct)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromEnvironmentUsing returns the dialer specify by the proxy-related
 | 
			
		||||
// variables in the environment and makes underlying connections
 | 
			
		||||
// using the provided forwarding Dialer (for instance, a *net.Dialer
 | 
			
		||||
// with desired configuration).
 | 
			
		||||
func FromEnvironmentUsing(forward Dialer) Dialer {
 | 
			
		||||
	allProxy := allProxyEnv.Get()
 | 
			
		||||
	if len(allProxy) == 0 {
 | 
			
		||||
		return forward
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	proxyURL, err := url.Parse(allProxy)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return forward
 | 
			
		||||
	}
 | 
			
		||||
	proxy, err := FromURL(proxyURL, forward)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return forward
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	noProxy := noProxyEnv.Get()
 | 
			
		||||
	if len(noProxy) == 0 {
 | 
			
		||||
		return proxy
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	perHost := NewPerHost(proxy, forward)
 | 
			
		||||
	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 proxySchemes map[string]func(*url.URL, Dialer) (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 RegisterDialerType(scheme string, f func(*url.URL, Dialer) (Dialer, error)) {
 | 
			
		||||
	if proxySchemes == nil {
 | 
			
		||||
		proxySchemes = make(map[string]func(*url.URL, Dialer) (Dialer, error))
 | 
			
		||||
	}
 | 
			
		||||
	proxySchemes[scheme] = f
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromURL returns a Dialer given a URL specification and an underlying
 | 
			
		||||
// Dialer for it to make network requests.
 | 
			
		||||
func FromURL(u *url.URL, forward Dialer) (Dialer, error) {
 | 
			
		||||
	var auth *Auth
 | 
			
		||||
	if u.User != nil {
 | 
			
		||||
		auth = new(Auth)
 | 
			
		||||
		auth.User = u.User.Username()
 | 
			
		||||
		if p, ok := u.User.Password(); ok {
 | 
			
		||||
			auth.Password = p
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch u.Scheme {
 | 
			
		||||
	case "socks5", "socks5h":
 | 
			
		||||
		addr := u.Hostname()
 | 
			
		||||
		port := u.Port()
 | 
			
		||||
		if port == "" {
 | 
			
		||||
			port = "1080"
 | 
			
		||||
		}
 | 
			
		||||
		return SOCKS5("tcp", net.JoinHostPort(addr, port), auth, forward)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the scheme doesn't match any of the built-in schemes, see if it
 | 
			
		||||
	// was registered by another package.
 | 
			
		||||
	if proxySchemes != nil {
 | 
			
		||||
		if f, ok := proxySchemes[u.Scheme]; ok {
 | 
			
		||||
			return f(u, forward)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, errors.New("proxy: unknown scheme: " + u.Scheme)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	allProxyEnv = &envOnce{
 | 
			
		||||
		names: []string{"ALL_PROXY", "all_proxy"},
 | 
			
		||||
	}
 | 
			
		||||
	noProxyEnv = &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 envOnce struct {
 | 
			
		||||
	names []string
 | 
			
		||||
	once  sync.Once
 | 
			
		||||
	val   string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *envOnce) Get() string {
 | 
			
		||||
	e.once.Do(e.init)
 | 
			
		||||
	return e.val
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *envOnce) init() {
 | 
			
		||||
	for _, n := range e.names {
 | 
			
		||||
		e.val = os.Getenv(n)
 | 
			
		||||
		if e.val != "" {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// reset is used by tests
 | 
			
		||||
func (e *envOnce) reset() {
 | 
			
		||||
	e.once = sync.Once{}
 | 
			
		||||
	e.val = ""
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								vendor/golang.org/x/net/proxy/socks5.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								vendor/golang.org/x/net/proxy/socks5.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package proxy
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"net"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/internal/socks"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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 SOCKS5(network, address string, auth *Auth, forward Dialer) (Dialer, error) {
 | 
			
		||||
	d := socks.NewDialer(network, address)
 | 
			
		||||
	if forward != nil {
 | 
			
		||||
		if f, ok := forward.(ContextDialer); ok {
 | 
			
		||||
			d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) {
 | 
			
		||||
				return f.DialContext(ctx, network, address)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			d.ProxyDial = func(ctx context.Context, network string, address string) (net.Conn, error) {
 | 
			
		||||
				return dialContext(ctx, forward, network, address)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if auth != nil {
 | 
			
		||||
		up := socks.UsernamePassword{
 | 
			
		||||
			Username: auth.User,
 | 
			
		||||
			Password: auth.Password,
 | 
			
		||||
		}
 | 
			
		||||
		d.AuthMethods = []socks.AuthMethod{
 | 
			
		||||
			socks.AuthMethodNotRequired,
 | 
			
		||||
			socks.AuthMethodUsernamePassword,
 | 
			
		||||
		}
 | 
			
		||||
		d.Authenticate = up.Authenticate
 | 
			
		||||
	}
 | 
			
		||||
	return d, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										106
									
								
								vendor/golang.org/x/net/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								vendor/golang.org/x/net/websocket/client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,106 @@
 | 
			
		||||
// Copyright 2009 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package websocket
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// DialError is an error that occurs while dialling a websocket server.
 | 
			
		||||
type DialError struct {
 | 
			
		||||
	*Config
 | 
			
		||||
	Err error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *DialError) Error() string {
 | 
			
		||||
	return "websocket.Dial " + e.Config.Location.String() + ": " + e.Err.Error()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewConfig creates a new WebSocket config for client connection.
 | 
			
		||||
func NewConfig(server, origin string) (config *Config, err error) {
 | 
			
		||||
	config = new(Config)
 | 
			
		||||
	config.Version = ProtocolVersionHybi13
 | 
			
		||||
	config.Location, err = url.ParseRequestURI(server)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	config.Origin, err = url.ParseRequestURI(origin)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	config.Header = http.Header(make(map[string][]string))
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewClient creates a new WebSocket client connection over rwc.
 | 
			
		||||
func NewClient(config *Config, rwc io.ReadWriteCloser) (ws *Conn, err error) {
 | 
			
		||||
	br := bufio.NewReader(rwc)
 | 
			
		||||
	bw := bufio.NewWriter(rwc)
 | 
			
		||||
	err = hybiClientHandshake(config, br, bw)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	buf := bufio.NewReadWriter(br, bw)
 | 
			
		||||
	ws = newHybiClientConn(config, buf, rwc)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dial opens a new client connection to a WebSocket.
 | 
			
		||||
func Dial(url_, protocol, origin string) (ws *Conn, err error) {
 | 
			
		||||
	config, err := NewConfig(url_, origin)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if protocol != "" {
 | 
			
		||||
		config.Protocol = []string{protocol}
 | 
			
		||||
	}
 | 
			
		||||
	return DialConfig(config)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var portMap = map[string]string{
 | 
			
		||||
	"ws":  "80",
 | 
			
		||||
	"wss": "443",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseAuthority(location *url.URL) string {
 | 
			
		||||
	if _, ok := portMap[location.Scheme]; ok {
 | 
			
		||||
		if _, _, err := net.SplitHostPort(location.Host); err != nil {
 | 
			
		||||
			return net.JoinHostPort(location.Host, portMap[location.Scheme])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return location.Host
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialConfig opens a new client connection to a WebSocket with a config.
 | 
			
		||||
func DialConfig(config *Config) (ws *Conn, err error) {
 | 
			
		||||
	var client net.Conn
 | 
			
		||||
	if config.Location == nil {
 | 
			
		||||
		return nil, &DialError{config, ErrBadWebSocketLocation}
 | 
			
		||||
	}
 | 
			
		||||
	if config.Origin == nil {
 | 
			
		||||
		return nil, &DialError{config, ErrBadWebSocketOrigin}
 | 
			
		||||
	}
 | 
			
		||||
	dialer := config.Dialer
 | 
			
		||||
	if dialer == nil {
 | 
			
		||||
		dialer = &net.Dialer{}
 | 
			
		||||
	}
 | 
			
		||||
	client, err = dialWithDialer(dialer, config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		goto Error
 | 
			
		||||
	}
 | 
			
		||||
	ws, err = NewClient(config, client)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		client.Close()
 | 
			
		||||
		goto Error
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
 | 
			
		||||
Error:
 | 
			
		||||
	return nil, &DialError{config, err}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								vendor/golang.org/x/net/websocket/dial.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								vendor/golang.org/x/net/websocket/dial.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
// Copyright 2015 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package websocket
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"net"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func dialWithDialer(dialer *net.Dialer, config *Config) (conn net.Conn, err error) {
 | 
			
		||||
	switch config.Location.Scheme {
 | 
			
		||||
	case "ws":
 | 
			
		||||
		conn, err = dialer.Dial("tcp", parseAuthority(config.Location))
 | 
			
		||||
 | 
			
		||||
	case "wss":
 | 
			
		||||
		conn, err = tls.DialWithDialer(dialer, "tcp", parseAuthority(config.Location), config.TlsConfig)
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		err = ErrBadScheme
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										583
									
								
								vendor/golang.org/x/net/websocket/hybi.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										583
									
								
								vendor/golang.org/x/net/websocket/hybi.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,583 @@
 | 
			
		||||
// Copyright 2011 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package websocket
 | 
			
		||||
 | 
			
		||||
// This file implements a protocol of hybi draft.
 | 
			
		||||
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	websocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
 | 
			
		||||
 | 
			
		||||
	closeStatusNormal            = 1000
 | 
			
		||||
	closeStatusGoingAway         = 1001
 | 
			
		||||
	closeStatusProtocolError     = 1002
 | 
			
		||||
	closeStatusUnsupportedData   = 1003
 | 
			
		||||
	closeStatusFrameTooLarge     = 1004
 | 
			
		||||
	closeStatusNoStatusRcvd      = 1005
 | 
			
		||||
	closeStatusAbnormalClosure   = 1006
 | 
			
		||||
	closeStatusBadMessageData    = 1007
 | 
			
		||||
	closeStatusPolicyViolation   = 1008
 | 
			
		||||
	closeStatusTooBigData        = 1009
 | 
			
		||||
	closeStatusExtensionMismatch = 1010
 | 
			
		||||
 | 
			
		||||
	maxControlFramePayloadLength = 125
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrBadMaskingKey         = &ProtocolError{"bad masking key"}
 | 
			
		||||
	ErrBadPongMessage        = &ProtocolError{"bad pong message"}
 | 
			
		||||
	ErrBadClosingStatus      = &ProtocolError{"bad closing status"}
 | 
			
		||||
	ErrUnsupportedExtensions = &ProtocolError{"unsupported extensions"}
 | 
			
		||||
	ErrNotImplemented        = &ProtocolError{"not implemented"}
 | 
			
		||||
 | 
			
		||||
	handshakeHeader = map[string]bool{
 | 
			
		||||
		"Host":                   true,
 | 
			
		||||
		"Upgrade":                true,
 | 
			
		||||
		"Connection":             true,
 | 
			
		||||
		"Sec-Websocket-Key":      true,
 | 
			
		||||
		"Sec-Websocket-Origin":   true,
 | 
			
		||||
		"Sec-Websocket-Version":  true,
 | 
			
		||||
		"Sec-Websocket-Protocol": true,
 | 
			
		||||
		"Sec-Websocket-Accept":   true,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A hybiFrameHeader is a frame header as defined in hybi draft.
 | 
			
		||||
type hybiFrameHeader struct {
 | 
			
		||||
	Fin        bool
 | 
			
		||||
	Rsv        [3]bool
 | 
			
		||||
	OpCode     byte
 | 
			
		||||
	Length     int64
 | 
			
		||||
	MaskingKey []byte
 | 
			
		||||
 | 
			
		||||
	data *bytes.Buffer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A hybiFrameReader is a reader for hybi frame.
 | 
			
		||||
type hybiFrameReader struct {
 | 
			
		||||
	reader io.Reader
 | 
			
		||||
 | 
			
		||||
	header hybiFrameHeader
 | 
			
		||||
	pos    int64
 | 
			
		||||
	length int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameReader) Read(msg []byte) (n int, err error) {
 | 
			
		||||
	n, err = frame.reader.Read(msg)
 | 
			
		||||
	if frame.header.MaskingKey != nil {
 | 
			
		||||
		for i := 0; i < n; i++ {
 | 
			
		||||
			msg[i] = msg[i] ^ frame.header.MaskingKey[frame.pos%4]
 | 
			
		||||
			frame.pos++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameReader) PayloadType() byte { return frame.header.OpCode }
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameReader) HeaderReader() io.Reader {
 | 
			
		||||
	if frame.header.data == nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if frame.header.data.Len() == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return frame.header.data
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameReader) TrailerReader() io.Reader { return nil }
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameReader) Len() (n int) { return frame.length }
 | 
			
		||||
 | 
			
		||||
// A hybiFrameReaderFactory creates new frame reader based on its frame type.
 | 
			
		||||
type hybiFrameReaderFactory struct {
 | 
			
		||||
	*bufio.Reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewFrameReader reads a frame header from the connection, and creates new reader for the frame.
 | 
			
		||||
// See Section 5.2 Base Framing protocol for detail.
 | 
			
		||||
// http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5.2
 | 
			
		||||
func (buf hybiFrameReaderFactory) NewFrameReader() (frame frameReader, err error) {
 | 
			
		||||
	hybiFrame := new(hybiFrameReader)
 | 
			
		||||
	frame = hybiFrame
 | 
			
		||||
	var header []byte
 | 
			
		||||
	var b byte
 | 
			
		||||
	// First byte. FIN/RSV1/RSV2/RSV3/OpCode(4bits)
 | 
			
		||||
	b, err = buf.ReadByte()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	header = append(header, b)
 | 
			
		||||
	hybiFrame.header.Fin = ((header[0] >> 7) & 1) != 0
 | 
			
		||||
	for i := 0; i < 3; i++ {
 | 
			
		||||
		j := uint(6 - i)
 | 
			
		||||
		hybiFrame.header.Rsv[i] = ((header[0] >> j) & 1) != 0
 | 
			
		||||
	}
 | 
			
		||||
	hybiFrame.header.OpCode = header[0] & 0x0f
 | 
			
		||||
 | 
			
		||||
	// Second byte. Mask/Payload len(7bits)
 | 
			
		||||
	b, err = buf.ReadByte()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	header = append(header, b)
 | 
			
		||||
	mask := (b & 0x80) != 0
 | 
			
		||||
	b &= 0x7f
 | 
			
		||||
	lengthFields := 0
 | 
			
		||||
	switch {
 | 
			
		||||
	case b <= 125: // Payload length 7bits.
 | 
			
		||||
		hybiFrame.header.Length = int64(b)
 | 
			
		||||
	case b == 126: // Payload length 7+16bits
 | 
			
		||||
		lengthFields = 2
 | 
			
		||||
	case b == 127: // Payload length 7+64bits
 | 
			
		||||
		lengthFields = 8
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < lengthFields; i++ {
 | 
			
		||||
		b, err = buf.ReadByte()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if lengthFields == 8 && i == 0 { // MSB must be zero when 7+64 bits
 | 
			
		||||
			b &= 0x7f
 | 
			
		||||
		}
 | 
			
		||||
		header = append(header, b)
 | 
			
		||||
		hybiFrame.header.Length = hybiFrame.header.Length*256 + int64(b)
 | 
			
		||||
	}
 | 
			
		||||
	if mask {
 | 
			
		||||
		// Masking key. 4 bytes.
 | 
			
		||||
		for i := 0; i < 4; i++ {
 | 
			
		||||
			b, err = buf.ReadByte()
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			header = append(header, b)
 | 
			
		||||
			hybiFrame.header.MaskingKey = append(hybiFrame.header.MaskingKey, b)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	hybiFrame.reader = io.LimitReader(buf.Reader, hybiFrame.header.Length)
 | 
			
		||||
	hybiFrame.header.data = bytes.NewBuffer(header)
 | 
			
		||||
	hybiFrame.length = len(header) + int(hybiFrame.header.Length)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A HybiFrameWriter is a writer for hybi frame.
 | 
			
		||||
type hybiFrameWriter struct {
 | 
			
		||||
	writer *bufio.Writer
 | 
			
		||||
 | 
			
		||||
	header *hybiFrameHeader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameWriter) Write(msg []byte) (n int, err error) {
 | 
			
		||||
	var header []byte
 | 
			
		||||
	var b byte
 | 
			
		||||
	if frame.header.Fin {
 | 
			
		||||
		b |= 0x80
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < 3; i++ {
 | 
			
		||||
		if frame.header.Rsv[i] {
 | 
			
		||||
			j := uint(6 - i)
 | 
			
		||||
			b |= 1 << j
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	b |= frame.header.OpCode
 | 
			
		||||
	header = append(header, b)
 | 
			
		||||
	if frame.header.MaskingKey != nil {
 | 
			
		||||
		b = 0x80
 | 
			
		||||
	} else {
 | 
			
		||||
		b = 0
 | 
			
		||||
	}
 | 
			
		||||
	lengthFields := 0
 | 
			
		||||
	length := len(msg)
 | 
			
		||||
	switch {
 | 
			
		||||
	case length <= 125:
 | 
			
		||||
		b |= byte(length)
 | 
			
		||||
	case length < 65536:
 | 
			
		||||
		b |= 126
 | 
			
		||||
		lengthFields = 2
 | 
			
		||||
	default:
 | 
			
		||||
		b |= 127
 | 
			
		||||
		lengthFields = 8
 | 
			
		||||
	}
 | 
			
		||||
	header = append(header, b)
 | 
			
		||||
	for i := 0; i < lengthFields; i++ {
 | 
			
		||||
		j := uint((lengthFields - i - 1) * 8)
 | 
			
		||||
		b = byte((length >> j) & 0xff)
 | 
			
		||||
		header = append(header, b)
 | 
			
		||||
	}
 | 
			
		||||
	if frame.header.MaskingKey != nil {
 | 
			
		||||
		if len(frame.header.MaskingKey) != 4 {
 | 
			
		||||
			return 0, ErrBadMaskingKey
 | 
			
		||||
		}
 | 
			
		||||
		header = append(header, frame.header.MaskingKey...)
 | 
			
		||||
		frame.writer.Write(header)
 | 
			
		||||
		data := make([]byte, length)
 | 
			
		||||
		for i := range data {
 | 
			
		||||
			data[i] = msg[i] ^ frame.header.MaskingKey[i%4]
 | 
			
		||||
		}
 | 
			
		||||
		frame.writer.Write(data)
 | 
			
		||||
		err = frame.writer.Flush()
 | 
			
		||||
		return length, err
 | 
			
		||||
	}
 | 
			
		||||
	frame.writer.Write(header)
 | 
			
		||||
	frame.writer.Write(msg)
 | 
			
		||||
	err = frame.writer.Flush()
 | 
			
		||||
	return length, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (frame *hybiFrameWriter) Close() error { return nil }
 | 
			
		||||
 | 
			
		||||
type hybiFrameWriterFactory struct {
 | 
			
		||||
	*bufio.Writer
 | 
			
		||||
	needMaskingKey bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (buf hybiFrameWriterFactory) NewFrameWriter(payloadType byte) (frame frameWriter, err error) {
 | 
			
		||||
	frameHeader := &hybiFrameHeader{Fin: true, OpCode: payloadType}
 | 
			
		||||
	if buf.needMaskingKey {
 | 
			
		||||
		frameHeader.MaskingKey, err = generateMaskingKey()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return &hybiFrameWriter{writer: buf.Writer, header: frameHeader}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type hybiFrameHandler struct {
 | 
			
		||||
	conn        *Conn
 | 
			
		||||
	payloadType byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (handler *hybiFrameHandler) HandleFrame(frame frameReader) (frameReader, error) {
 | 
			
		||||
	if handler.conn.IsServerConn() {
 | 
			
		||||
		// The client MUST mask all frames sent to the server.
 | 
			
		||||
		if frame.(*hybiFrameReader).header.MaskingKey == nil {
 | 
			
		||||
			handler.WriteClose(closeStatusProtocolError)
 | 
			
		||||
			return nil, io.EOF
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		// The server MUST NOT mask all frames.
 | 
			
		||||
		if frame.(*hybiFrameReader).header.MaskingKey != nil {
 | 
			
		||||
			handler.WriteClose(closeStatusProtocolError)
 | 
			
		||||
			return nil, io.EOF
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if header := frame.HeaderReader(); header != nil {
 | 
			
		||||
		io.Copy(ioutil.Discard, header)
 | 
			
		||||
	}
 | 
			
		||||
	switch frame.PayloadType() {
 | 
			
		||||
	case ContinuationFrame:
 | 
			
		||||
		frame.(*hybiFrameReader).header.OpCode = handler.payloadType
 | 
			
		||||
	case TextFrame, BinaryFrame:
 | 
			
		||||
		handler.payloadType = frame.PayloadType()
 | 
			
		||||
	case CloseFrame:
 | 
			
		||||
		return nil, io.EOF
 | 
			
		||||
	case PingFrame, PongFrame:
 | 
			
		||||
		b := make([]byte, maxControlFramePayloadLength)
 | 
			
		||||
		n, err := io.ReadFull(frame, b)
 | 
			
		||||
		if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		io.Copy(ioutil.Discard, frame)
 | 
			
		||||
		if frame.PayloadType() == PingFrame {
 | 
			
		||||
			if _, err := handler.WritePong(b[:n]); err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
	return frame, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (handler *hybiFrameHandler) WriteClose(status int) (err error) {
 | 
			
		||||
	handler.conn.wio.Lock()
 | 
			
		||||
	defer handler.conn.wio.Unlock()
 | 
			
		||||
	w, err := handler.conn.frameWriterFactory.NewFrameWriter(CloseFrame)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	msg := make([]byte, 2)
 | 
			
		||||
	binary.BigEndian.PutUint16(msg, uint16(status))
 | 
			
		||||
	_, err = w.Write(msg)
 | 
			
		||||
	w.Close()
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (handler *hybiFrameHandler) WritePong(msg []byte) (n int, err error) {
 | 
			
		||||
	handler.conn.wio.Lock()
 | 
			
		||||
	defer handler.conn.wio.Unlock()
 | 
			
		||||
	w, err := handler.conn.frameWriterFactory.NewFrameWriter(PongFrame)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	n, err = w.Write(msg)
 | 
			
		||||
	w.Close()
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newHybiConn creates a new WebSocket connection speaking hybi draft protocol.
 | 
			
		||||
func newHybiConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
 | 
			
		||||
	if buf == nil {
 | 
			
		||||
		br := bufio.NewReader(rwc)
 | 
			
		||||
		bw := bufio.NewWriter(rwc)
 | 
			
		||||
		buf = bufio.NewReadWriter(br, bw)
 | 
			
		||||
	}
 | 
			
		||||
	ws := &Conn{config: config, request: request, buf: buf, rwc: rwc,
 | 
			
		||||
		frameReaderFactory: hybiFrameReaderFactory{buf.Reader},
 | 
			
		||||
		frameWriterFactory: hybiFrameWriterFactory{
 | 
			
		||||
			buf.Writer, request == nil},
 | 
			
		||||
		PayloadType:        TextFrame,
 | 
			
		||||
		defaultCloseStatus: closeStatusNormal}
 | 
			
		||||
	ws.frameHandler = &hybiFrameHandler{conn: ws}
 | 
			
		||||
	return ws
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generateMaskingKey generates a masking key for a frame.
 | 
			
		||||
func generateMaskingKey() (maskingKey []byte, err error) {
 | 
			
		||||
	maskingKey = make([]byte, 4)
 | 
			
		||||
	if _, err = io.ReadFull(rand.Reader, maskingKey); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generateNonce generates a nonce consisting of a randomly selected 16-byte
 | 
			
		||||
// value that has been base64-encoded.
 | 
			
		||||
func generateNonce() (nonce []byte) {
 | 
			
		||||
	key := make([]byte, 16)
 | 
			
		||||
	if _, err := io.ReadFull(rand.Reader, key); err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	nonce = make([]byte, 24)
 | 
			
		||||
	base64.StdEncoding.Encode(nonce, key)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// removeZone removes IPv6 zone identifer from host.
 | 
			
		||||
// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
 | 
			
		||||
func removeZone(host string) string {
 | 
			
		||||
	if !strings.HasPrefix(host, "[") {
 | 
			
		||||
		return host
 | 
			
		||||
	}
 | 
			
		||||
	i := strings.LastIndex(host, "]")
 | 
			
		||||
	if i < 0 {
 | 
			
		||||
		return host
 | 
			
		||||
	}
 | 
			
		||||
	j := strings.LastIndex(host[:i], "%")
 | 
			
		||||
	if j < 0 {
 | 
			
		||||
		return host
 | 
			
		||||
	}
 | 
			
		||||
	return host[:j] + host[i:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getNonceAccept computes the base64-encoded SHA-1 of the concatenation of
 | 
			
		||||
// the nonce ("Sec-WebSocket-Key" value) with the websocket GUID string.
 | 
			
		||||
func getNonceAccept(nonce []byte) (expected []byte, err error) {
 | 
			
		||||
	h := sha1.New()
 | 
			
		||||
	if _, err = h.Write(nonce); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if _, err = h.Write([]byte(websocketGUID)); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	expected = make([]byte, 28)
 | 
			
		||||
	base64.StdEncoding.Encode(expected, h.Sum(nil))
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Client handshake described in draft-ietf-hybi-thewebsocket-protocol-17
 | 
			
		||||
func hybiClientHandshake(config *Config, br *bufio.Reader, bw *bufio.Writer) (err error) {
 | 
			
		||||
	bw.WriteString("GET " + config.Location.RequestURI() + " HTTP/1.1\r\n")
 | 
			
		||||
 | 
			
		||||
	// According to RFC 6874, an HTTP client, proxy, or other
 | 
			
		||||
	// intermediary must remove any IPv6 zone identifier attached
 | 
			
		||||
	// to an outgoing URI.
 | 
			
		||||
	bw.WriteString("Host: " + removeZone(config.Location.Host) + "\r\n")
 | 
			
		||||
	bw.WriteString("Upgrade: websocket\r\n")
 | 
			
		||||
	bw.WriteString("Connection: Upgrade\r\n")
 | 
			
		||||
	nonce := generateNonce()
 | 
			
		||||
	if config.handshakeData != nil {
 | 
			
		||||
		nonce = []byte(config.handshakeData["key"])
 | 
			
		||||
	}
 | 
			
		||||
	bw.WriteString("Sec-WebSocket-Key: " + string(nonce) + "\r\n")
 | 
			
		||||
	bw.WriteString("Origin: " + strings.ToLower(config.Origin.String()) + "\r\n")
 | 
			
		||||
 | 
			
		||||
	if config.Version != ProtocolVersionHybi13 {
 | 
			
		||||
		return ErrBadProtocolVersion
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bw.WriteString("Sec-WebSocket-Version: " + fmt.Sprintf("%d", config.Version) + "\r\n")
 | 
			
		||||
	if len(config.Protocol) > 0 {
 | 
			
		||||
		bw.WriteString("Sec-WebSocket-Protocol: " + strings.Join(config.Protocol, ", ") + "\r\n")
 | 
			
		||||
	}
 | 
			
		||||
	// TODO(ukai): send Sec-WebSocket-Extensions.
 | 
			
		||||
	err = config.Header.WriteSubset(bw, handshakeHeader)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bw.WriteString("\r\n")
 | 
			
		||||
	if err = bw.Flush(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resp, err := http.ReadResponse(br, &http.Request{Method: "GET"})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if resp.StatusCode != 101 {
 | 
			
		||||
		return ErrBadStatus
 | 
			
		||||
	}
 | 
			
		||||
	if strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" ||
 | 
			
		||||
		strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
 | 
			
		||||
		return ErrBadUpgrade
 | 
			
		||||
	}
 | 
			
		||||
	expectedAccept, err := getNonceAccept(nonce)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if resp.Header.Get("Sec-WebSocket-Accept") != string(expectedAccept) {
 | 
			
		||||
		return ErrChallengeResponse
 | 
			
		||||
	}
 | 
			
		||||
	if resp.Header.Get("Sec-WebSocket-Extensions") != "" {
 | 
			
		||||
		return ErrUnsupportedExtensions
 | 
			
		||||
	}
 | 
			
		||||
	offeredProtocol := resp.Header.Get("Sec-WebSocket-Protocol")
 | 
			
		||||
	if offeredProtocol != "" {
 | 
			
		||||
		protocolMatched := false
 | 
			
		||||
		for i := 0; i < len(config.Protocol); i++ {
 | 
			
		||||
			if config.Protocol[i] == offeredProtocol {
 | 
			
		||||
				protocolMatched = true
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if !protocolMatched {
 | 
			
		||||
			return ErrBadWebSocketProtocol
 | 
			
		||||
		}
 | 
			
		||||
		config.Protocol = []string{offeredProtocol}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newHybiClientConn creates a client WebSocket connection after handshake.
 | 
			
		||||
func newHybiClientConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser) *Conn {
 | 
			
		||||
	return newHybiConn(config, buf, rwc, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A HybiServerHandshaker performs a server handshake using hybi draft protocol.
 | 
			
		||||
type hybiServerHandshaker struct {
 | 
			
		||||
	*Config
 | 
			
		||||
	accept []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *hybiServerHandshaker) ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error) {
 | 
			
		||||
	c.Version = ProtocolVersionHybi13
 | 
			
		||||
	if req.Method != "GET" {
 | 
			
		||||
		return http.StatusMethodNotAllowed, ErrBadRequestMethod
 | 
			
		||||
	}
 | 
			
		||||
	// HTTP version can be safely ignored.
 | 
			
		||||
 | 
			
		||||
	if strings.ToLower(req.Header.Get("Upgrade")) != "websocket" ||
 | 
			
		||||
		!strings.Contains(strings.ToLower(req.Header.Get("Connection")), "upgrade") {
 | 
			
		||||
		return http.StatusBadRequest, ErrNotWebSocket
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	key := req.Header.Get("Sec-Websocket-Key")
 | 
			
		||||
	if key == "" {
 | 
			
		||||
		return http.StatusBadRequest, ErrChallengeResponse
 | 
			
		||||
	}
 | 
			
		||||
	version := req.Header.Get("Sec-Websocket-Version")
 | 
			
		||||
	switch version {
 | 
			
		||||
	case "13":
 | 
			
		||||
		c.Version = ProtocolVersionHybi13
 | 
			
		||||
	default:
 | 
			
		||||
		return http.StatusBadRequest, ErrBadWebSocketVersion
 | 
			
		||||
	}
 | 
			
		||||
	var scheme string
 | 
			
		||||
	if req.TLS != nil {
 | 
			
		||||
		scheme = "wss"
 | 
			
		||||
	} else {
 | 
			
		||||
		scheme = "ws"
 | 
			
		||||
	}
 | 
			
		||||
	c.Location, err = url.ParseRequestURI(scheme + "://" + req.Host + req.URL.RequestURI())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusBadRequest, err
 | 
			
		||||
	}
 | 
			
		||||
	protocol := strings.TrimSpace(req.Header.Get("Sec-Websocket-Protocol"))
 | 
			
		||||
	if protocol != "" {
 | 
			
		||||
		protocols := strings.Split(protocol, ",")
 | 
			
		||||
		for i := 0; i < len(protocols); i++ {
 | 
			
		||||
			c.Protocol = append(c.Protocol, strings.TrimSpace(protocols[i]))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	c.accept, err = getNonceAccept([]byte(key))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return http.StatusInternalServerError, err
 | 
			
		||||
	}
 | 
			
		||||
	return http.StatusSwitchingProtocols, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Origin parses the Origin header in req.
 | 
			
		||||
// If the Origin header is not set, it returns nil and nil.
 | 
			
		||||
func Origin(config *Config, req *http.Request) (*url.URL, error) {
 | 
			
		||||
	var origin string
 | 
			
		||||
	switch config.Version {
 | 
			
		||||
	case ProtocolVersionHybi13:
 | 
			
		||||
		origin = req.Header.Get("Origin")
 | 
			
		||||
	}
 | 
			
		||||
	if origin == "" {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
	return url.ParseRequestURI(origin)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *hybiServerHandshaker) AcceptHandshake(buf *bufio.Writer) (err error) {
 | 
			
		||||
	if len(c.Protocol) > 0 {
 | 
			
		||||
		if len(c.Protocol) != 1 {
 | 
			
		||||
			// You need choose a Protocol in Handshake func in Server.
 | 
			
		||||
			return ErrBadWebSocketProtocol
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	buf.WriteString("HTTP/1.1 101 Switching Protocols\r\n")
 | 
			
		||||
	buf.WriteString("Upgrade: websocket\r\n")
 | 
			
		||||
	buf.WriteString("Connection: Upgrade\r\n")
 | 
			
		||||
	buf.WriteString("Sec-WebSocket-Accept: " + string(c.accept) + "\r\n")
 | 
			
		||||
	if len(c.Protocol) > 0 {
 | 
			
		||||
		buf.WriteString("Sec-WebSocket-Protocol: " + c.Protocol[0] + "\r\n")
 | 
			
		||||
	}
 | 
			
		||||
	// TODO(ukai): send Sec-WebSocket-Extensions.
 | 
			
		||||
	if c.Header != nil {
 | 
			
		||||
		err := c.Header.WriteSubset(buf, handshakeHeader)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	buf.WriteString("\r\n")
 | 
			
		||||
	return buf.Flush()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *hybiServerHandshaker) NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
 | 
			
		||||
	return newHybiServerConn(c.Config, buf, rwc, request)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// newHybiServerConn returns a new WebSocket connection speaking hybi draft protocol.
 | 
			
		||||
func newHybiServerConn(config *Config, buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) *Conn {
 | 
			
		||||
	return newHybiConn(config, buf, rwc, request)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										113
									
								
								vendor/golang.org/x/net/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								vendor/golang.org/x/net/websocket/server.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
			
		||||
// Copyright 2009 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package websocket
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func newServerConn(rwc io.ReadWriteCloser, buf *bufio.ReadWriter, req *http.Request, config *Config, handshake func(*Config, *http.Request) error) (conn *Conn, err error) {
 | 
			
		||||
	var hs serverHandshaker = &hybiServerHandshaker{Config: config}
 | 
			
		||||
	code, err := hs.ReadHandshake(buf.Reader, req)
 | 
			
		||||
	if err == ErrBadWebSocketVersion {
 | 
			
		||||
		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
 | 
			
		||||
		fmt.Fprintf(buf, "Sec-WebSocket-Version: %s\r\n", SupportedProtocolVersion)
 | 
			
		||||
		buf.WriteString("\r\n")
 | 
			
		||||
		buf.WriteString(err.Error())
 | 
			
		||||
		buf.Flush()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
 | 
			
		||||
		buf.WriteString("\r\n")
 | 
			
		||||
		buf.WriteString(err.Error())
 | 
			
		||||
		buf.Flush()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if handshake != nil {
 | 
			
		||||
		err = handshake(config, req)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			code = http.StatusForbidden
 | 
			
		||||
			fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
 | 
			
		||||
			buf.WriteString("\r\n")
 | 
			
		||||
			buf.Flush()
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	err = hs.AcceptHandshake(buf.Writer)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		code = http.StatusBadRequest
 | 
			
		||||
		fmt.Fprintf(buf, "HTTP/1.1 %03d %s\r\n", code, http.StatusText(code))
 | 
			
		||||
		buf.WriteString("\r\n")
 | 
			
		||||
		buf.Flush()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	conn = hs.NewServerConn(buf, rwc, req)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Server represents a server of a WebSocket.
 | 
			
		||||
type Server struct {
 | 
			
		||||
	// Config is a WebSocket configuration for new WebSocket connection.
 | 
			
		||||
	Config
 | 
			
		||||
 | 
			
		||||
	// Handshake is an optional function in WebSocket handshake.
 | 
			
		||||
	// For example, you can check, or don't check Origin header.
 | 
			
		||||
	// Another example, you can select config.Protocol.
 | 
			
		||||
	Handshake func(*Config, *http.Request) error
 | 
			
		||||
 | 
			
		||||
	// Handler handles a WebSocket connection.
 | 
			
		||||
	Handler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServeHTTP implements the http.Handler interface for a WebSocket
 | 
			
		||||
func (s Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 | 
			
		||||
	s.serveWebSocket(w, req)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) {
 | 
			
		||||
	rwc, buf, err := w.(http.Hijacker).Hijack()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic("Hijack failed: " + err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	// The server should abort the WebSocket connection if it finds
 | 
			
		||||
	// the client did not send a handshake that matches with protocol
 | 
			
		||||
	// specification.
 | 
			
		||||
	defer rwc.Close()
 | 
			
		||||
	conn, err := newServerConn(rwc, buf, req, &s.Config, s.Handshake)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if conn == nil {
 | 
			
		||||
		panic("unexpected nil conn")
 | 
			
		||||
	}
 | 
			
		||||
	s.Handler(conn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Handler is a simple interface to a WebSocket browser client.
 | 
			
		||||
// It checks if Origin header is valid URL by default.
 | 
			
		||||
// You might want to verify websocket.Conn.Config().Origin in the func.
 | 
			
		||||
// If you use Server instead of Handler, you could call websocket.Origin and
 | 
			
		||||
// check the origin in your Handshake func. So, if you want to accept
 | 
			
		||||
// non-browser clients, which do not send an Origin header, set a
 | 
			
		||||
// Server.Handshake that does not check the origin.
 | 
			
		||||
type Handler func(*Conn)
 | 
			
		||||
 | 
			
		||||
func checkOrigin(config *Config, req *http.Request) (err error) {
 | 
			
		||||
	config.Origin, err = Origin(config, req)
 | 
			
		||||
	if err == nil && config.Origin == nil {
 | 
			
		||||
		return fmt.Errorf("null origin")
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServeHTTP implements the http.Handler interface for a WebSocket
 | 
			
		||||
func (h Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 | 
			
		||||
	s := Server{Handler: h, Handshake: checkOrigin}
 | 
			
		||||
	s.serveWebSocket(w, req)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										451
									
								
								vendor/golang.org/x/net/websocket/websocket.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										451
									
								
								vendor/golang.org/x/net/websocket/websocket.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,451 @@
 | 
			
		||||
// Copyright 2009 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Package websocket implements a client and server for the WebSocket protocol
 | 
			
		||||
// as specified in RFC 6455.
 | 
			
		||||
//
 | 
			
		||||
// This package currently lacks some features found in alternative
 | 
			
		||||
// and more actively maintained WebSocket packages:
 | 
			
		||||
//
 | 
			
		||||
//     https://godoc.org/github.com/gorilla/websocket
 | 
			
		||||
//     https://godoc.org/nhooyr.io/websocket
 | 
			
		||||
package websocket // import "golang.org/x/net/websocket"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ProtocolVersionHybi13    = 13
 | 
			
		||||
	ProtocolVersionHybi      = ProtocolVersionHybi13
 | 
			
		||||
	SupportedProtocolVersion = "13"
 | 
			
		||||
 | 
			
		||||
	ContinuationFrame = 0
 | 
			
		||||
	TextFrame         = 1
 | 
			
		||||
	BinaryFrame       = 2
 | 
			
		||||
	CloseFrame        = 8
 | 
			
		||||
	PingFrame         = 9
 | 
			
		||||
	PongFrame         = 10
 | 
			
		||||
	UnknownFrame      = 255
 | 
			
		||||
 | 
			
		||||
	DefaultMaxPayloadBytes = 32 << 20 // 32MB
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ProtocolError represents WebSocket protocol errors.
 | 
			
		||||
type ProtocolError struct {
 | 
			
		||||
	ErrorString string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err *ProtocolError) Error() string { return err.ErrorString }
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrBadProtocolVersion   = &ProtocolError{"bad protocol version"}
 | 
			
		||||
	ErrBadScheme            = &ProtocolError{"bad scheme"}
 | 
			
		||||
	ErrBadStatus            = &ProtocolError{"bad status"}
 | 
			
		||||
	ErrBadUpgrade           = &ProtocolError{"missing or bad upgrade"}
 | 
			
		||||
	ErrBadWebSocketOrigin   = &ProtocolError{"missing or bad WebSocket-Origin"}
 | 
			
		||||
	ErrBadWebSocketLocation = &ProtocolError{"missing or bad WebSocket-Location"}
 | 
			
		||||
	ErrBadWebSocketProtocol = &ProtocolError{"missing or bad WebSocket-Protocol"}
 | 
			
		||||
	ErrBadWebSocketVersion  = &ProtocolError{"missing or bad WebSocket Version"}
 | 
			
		||||
	ErrChallengeResponse    = &ProtocolError{"mismatch challenge/response"}
 | 
			
		||||
	ErrBadFrame             = &ProtocolError{"bad frame"}
 | 
			
		||||
	ErrBadFrameBoundary     = &ProtocolError{"not on frame boundary"}
 | 
			
		||||
	ErrNotWebSocket         = &ProtocolError{"not websocket protocol"}
 | 
			
		||||
	ErrBadRequestMethod     = &ProtocolError{"bad method"}
 | 
			
		||||
	ErrNotSupported         = &ProtocolError{"not supported"}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrFrameTooLarge is returned by Codec's Receive method if payload size
 | 
			
		||||
// exceeds limit set by Conn.MaxPayloadBytes
 | 
			
		||||
var ErrFrameTooLarge = errors.New("websocket: frame payload size exceeds limit")
 | 
			
		||||
 | 
			
		||||
// Addr is an implementation of net.Addr for WebSocket.
 | 
			
		||||
type Addr struct {
 | 
			
		||||
	*url.URL
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Network returns the network type for a WebSocket, "websocket".
 | 
			
		||||
func (addr *Addr) Network() string { return "websocket" }
 | 
			
		||||
 | 
			
		||||
// Config is a WebSocket configuration
 | 
			
		||||
type Config struct {
 | 
			
		||||
	// A WebSocket server address.
 | 
			
		||||
	Location *url.URL
 | 
			
		||||
 | 
			
		||||
	// A Websocket client origin.
 | 
			
		||||
	Origin *url.URL
 | 
			
		||||
 | 
			
		||||
	// WebSocket subprotocols.
 | 
			
		||||
	Protocol []string
 | 
			
		||||
 | 
			
		||||
	// WebSocket protocol version.
 | 
			
		||||
	Version int
 | 
			
		||||
 | 
			
		||||
	// TLS config for secure WebSocket (wss).
 | 
			
		||||
	TlsConfig *tls.Config
 | 
			
		||||
 | 
			
		||||
	// Additional header fields to be sent in WebSocket opening handshake.
 | 
			
		||||
	Header http.Header
 | 
			
		||||
 | 
			
		||||
	// Dialer used when opening websocket connections.
 | 
			
		||||
	Dialer *net.Dialer
 | 
			
		||||
 | 
			
		||||
	handshakeData map[string]string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// serverHandshaker is an interface to handle WebSocket server side handshake.
 | 
			
		||||
type serverHandshaker interface {
 | 
			
		||||
	// ReadHandshake reads handshake request message from client.
 | 
			
		||||
	// Returns http response code and error if any.
 | 
			
		||||
	ReadHandshake(buf *bufio.Reader, req *http.Request) (code int, err error)
 | 
			
		||||
 | 
			
		||||
	// AcceptHandshake accepts the client handshake request and sends
 | 
			
		||||
	// handshake response back to client.
 | 
			
		||||
	AcceptHandshake(buf *bufio.Writer) (err error)
 | 
			
		||||
 | 
			
		||||
	// NewServerConn creates a new WebSocket connection.
 | 
			
		||||
	NewServerConn(buf *bufio.ReadWriter, rwc io.ReadWriteCloser, request *http.Request) (conn *Conn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// frameReader is an interface to read a WebSocket frame.
 | 
			
		||||
type frameReader interface {
 | 
			
		||||
	// Reader is to read payload of the frame.
 | 
			
		||||
	io.Reader
 | 
			
		||||
 | 
			
		||||
	// PayloadType returns payload type.
 | 
			
		||||
	PayloadType() byte
 | 
			
		||||
 | 
			
		||||
	// HeaderReader returns a reader to read header of the frame.
 | 
			
		||||
	HeaderReader() io.Reader
 | 
			
		||||
 | 
			
		||||
	// TrailerReader returns a reader to read trailer of the frame.
 | 
			
		||||
	// If it returns nil, there is no trailer in the frame.
 | 
			
		||||
	TrailerReader() io.Reader
 | 
			
		||||
 | 
			
		||||
	// Len returns total length of the frame, including header and trailer.
 | 
			
		||||
	Len() int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// frameReaderFactory is an interface to creates new frame reader.
 | 
			
		||||
type frameReaderFactory interface {
 | 
			
		||||
	NewFrameReader() (r frameReader, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// frameWriter is an interface to write a WebSocket frame.
 | 
			
		||||
type frameWriter interface {
 | 
			
		||||
	// Writer is to write payload of the frame.
 | 
			
		||||
	io.WriteCloser
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// frameWriterFactory is an interface to create new frame writer.
 | 
			
		||||
type frameWriterFactory interface {
 | 
			
		||||
	NewFrameWriter(payloadType byte) (w frameWriter, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type frameHandler interface {
 | 
			
		||||
	HandleFrame(frame frameReader) (r frameReader, err error)
 | 
			
		||||
	WriteClose(status int) (err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Conn represents a WebSocket connection.
 | 
			
		||||
//
 | 
			
		||||
// Multiple goroutines may invoke methods on a Conn simultaneously.
 | 
			
		||||
type Conn struct {
 | 
			
		||||
	config  *Config
 | 
			
		||||
	request *http.Request
 | 
			
		||||
 | 
			
		||||
	buf *bufio.ReadWriter
 | 
			
		||||
	rwc io.ReadWriteCloser
 | 
			
		||||
 | 
			
		||||
	rio sync.Mutex
 | 
			
		||||
	frameReaderFactory
 | 
			
		||||
	frameReader
 | 
			
		||||
 | 
			
		||||
	wio sync.Mutex
 | 
			
		||||
	frameWriterFactory
 | 
			
		||||
 | 
			
		||||
	frameHandler
 | 
			
		||||
	PayloadType        byte
 | 
			
		||||
	defaultCloseStatus int
 | 
			
		||||
 | 
			
		||||
	// MaxPayloadBytes limits the size of frame payload received over Conn
 | 
			
		||||
	// by Codec's Receive method. If zero, DefaultMaxPayloadBytes is used.
 | 
			
		||||
	MaxPayloadBytes int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read implements the io.Reader interface:
 | 
			
		||||
// it reads data of a frame from the WebSocket connection.
 | 
			
		||||
// if msg is not large enough for the frame data, it fills the msg and next Read
 | 
			
		||||
// will read the rest of the frame data.
 | 
			
		||||
// it reads Text frame or Binary frame.
 | 
			
		||||
func (ws *Conn) Read(msg []byte) (n int, err error) {
 | 
			
		||||
	ws.rio.Lock()
 | 
			
		||||
	defer ws.rio.Unlock()
 | 
			
		||||
again:
 | 
			
		||||
	if ws.frameReader == nil {
 | 
			
		||||
		frame, err := ws.frameReaderFactory.NewFrameReader()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		ws.frameReader, err = ws.frameHandler.HandleFrame(frame)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		if ws.frameReader == nil {
 | 
			
		||||
			goto again
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	n, err = ws.frameReader.Read(msg)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		if trailer := ws.frameReader.TrailerReader(); trailer != nil {
 | 
			
		||||
			io.Copy(ioutil.Discard, trailer)
 | 
			
		||||
		}
 | 
			
		||||
		ws.frameReader = nil
 | 
			
		||||
		goto again
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write implements the io.Writer interface:
 | 
			
		||||
// it writes data as a frame to the WebSocket connection.
 | 
			
		||||
func (ws *Conn) Write(msg []byte) (n int, err error) {
 | 
			
		||||
	ws.wio.Lock()
 | 
			
		||||
	defer ws.wio.Unlock()
 | 
			
		||||
	w, err := ws.frameWriterFactory.NewFrameWriter(ws.PayloadType)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	n, err = w.Write(msg)
 | 
			
		||||
	w.Close()
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close implements the io.Closer interface.
 | 
			
		||||
func (ws *Conn) Close() error {
 | 
			
		||||
	err := ws.frameHandler.WriteClose(ws.defaultCloseStatus)
 | 
			
		||||
	err1 := ws.rwc.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return err1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsClientConn reports whether ws is a client-side connection.
 | 
			
		||||
func (ws *Conn) IsClientConn() bool { return ws.request == nil }
 | 
			
		||||
 | 
			
		||||
// IsServerConn reports whether ws is a server-side connection.
 | 
			
		||||
func (ws *Conn) IsServerConn() bool { return ws.request != nil }
 | 
			
		||||
 | 
			
		||||
// LocalAddr returns the WebSocket Origin for the connection for client, or
 | 
			
		||||
// the WebSocket location for server.
 | 
			
		||||
func (ws *Conn) LocalAddr() net.Addr {
 | 
			
		||||
	if ws.IsClientConn() {
 | 
			
		||||
		return &Addr{ws.config.Origin}
 | 
			
		||||
	}
 | 
			
		||||
	return &Addr{ws.config.Location}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoteAddr returns the WebSocket location for the connection for client, or
 | 
			
		||||
// the Websocket Origin for server.
 | 
			
		||||
func (ws *Conn) RemoteAddr() net.Addr {
 | 
			
		||||
	if ws.IsClientConn() {
 | 
			
		||||
		return &Addr{ws.config.Location}
 | 
			
		||||
	}
 | 
			
		||||
	return &Addr{ws.config.Origin}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var errSetDeadline = errors.New("websocket: cannot set deadline: not using a net.Conn")
 | 
			
		||||
 | 
			
		||||
// SetDeadline sets the connection's network read & write deadlines.
 | 
			
		||||
func (ws *Conn) SetDeadline(t time.Time) error {
 | 
			
		||||
	if conn, ok := ws.rwc.(net.Conn); ok {
 | 
			
		||||
		return conn.SetDeadline(t)
 | 
			
		||||
	}
 | 
			
		||||
	return errSetDeadline
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetReadDeadline sets the connection's network read deadline.
 | 
			
		||||
func (ws *Conn) SetReadDeadline(t time.Time) error {
 | 
			
		||||
	if conn, ok := ws.rwc.(net.Conn); ok {
 | 
			
		||||
		return conn.SetReadDeadline(t)
 | 
			
		||||
	}
 | 
			
		||||
	return errSetDeadline
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetWriteDeadline sets the connection's network write deadline.
 | 
			
		||||
func (ws *Conn) SetWriteDeadline(t time.Time) error {
 | 
			
		||||
	if conn, ok := ws.rwc.(net.Conn); ok {
 | 
			
		||||
		return conn.SetWriteDeadline(t)
 | 
			
		||||
	}
 | 
			
		||||
	return errSetDeadline
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Config returns the WebSocket config.
 | 
			
		||||
func (ws *Conn) Config() *Config { return ws.config }
 | 
			
		||||
 | 
			
		||||
// Request returns the http request upgraded to the WebSocket.
 | 
			
		||||
// It is nil for client side.
 | 
			
		||||
func (ws *Conn) Request() *http.Request { return ws.request }
 | 
			
		||||
 | 
			
		||||
// Codec represents a symmetric pair of functions that implement a codec.
 | 
			
		||||
type Codec struct {
 | 
			
		||||
	Marshal   func(v interface{}) (data []byte, payloadType byte, err error)
 | 
			
		||||
	Unmarshal func(data []byte, payloadType byte, v interface{}) (err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send sends v marshaled by cd.Marshal as single frame to ws.
 | 
			
		||||
func (cd Codec) Send(ws *Conn, v interface{}) (err error) {
 | 
			
		||||
	data, payloadType, err := cd.Marshal(v)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	ws.wio.Lock()
 | 
			
		||||
	defer ws.wio.Unlock()
 | 
			
		||||
	w, err := ws.frameWriterFactory.NewFrameWriter(payloadType)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = w.Write(data)
 | 
			
		||||
	w.Close()
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Receive receives single frame from ws, unmarshaled by cd.Unmarshal and stores
 | 
			
		||||
// in v. The whole frame payload is read to an in-memory buffer; max size of
 | 
			
		||||
// payload is defined by ws.MaxPayloadBytes. If frame payload size exceeds
 | 
			
		||||
// limit, ErrFrameTooLarge is returned; in this case frame is not read off wire
 | 
			
		||||
// completely. The next call to Receive would read and discard leftover data of
 | 
			
		||||
// previous oversized frame before processing next frame.
 | 
			
		||||
func (cd Codec) Receive(ws *Conn, v interface{}) (err error) {
 | 
			
		||||
	ws.rio.Lock()
 | 
			
		||||
	defer ws.rio.Unlock()
 | 
			
		||||
	if ws.frameReader != nil {
 | 
			
		||||
		_, err = io.Copy(ioutil.Discard, ws.frameReader)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		ws.frameReader = nil
 | 
			
		||||
	}
 | 
			
		||||
again:
 | 
			
		||||
	frame, err := ws.frameReaderFactory.NewFrameReader()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	frame, err = ws.frameHandler.HandleFrame(frame)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if frame == nil {
 | 
			
		||||
		goto again
 | 
			
		||||
	}
 | 
			
		||||
	maxPayloadBytes := ws.MaxPayloadBytes
 | 
			
		||||
	if maxPayloadBytes == 0 {
 | 
			
		||||
		maxPayloadBytes = DefaultMaxPayloadBytes
 | 
			
		||||
	}
 | 
			
		||||
	if hf, ok := frame.(*hybiFrameReader); ok && hf.header.Length > int64(maxPayloadBytes) {
 | 
			
		||||
		// payload size exceeds limit, no need to call Unmarshal
 | 
			
		||||
		//
 | 
			
		||||
		// set frameReader to current oversized frame so that
 | 
			
		||||
		// the next call to this function can drain leftover
 | 
			
		||||
		// data before processing the next frame
 | 
			
		||||
		ws.frameReader = frame
 | 
			
		||||
		return ErrFrameTooLarge
 | 
			
		||||
	}
 | 
			
		||||
	payloadType := frame.PayloadType()
 | 
			
		||||
	data, err := ioutil.ReadAll(frame)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return cd.Unmarshal(data, payloadType, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func marshal(v interface{}) (msg []byte, payloadType byte, err error) {
 | 
			
		||||
	switch data := v.(type) {
 | 
			
		||||
	case string:
 | 
			
		||||
		return []byte(data), TextFrame, nil
 | 
			
		||||
	case []byte:
 | 
			
		||||
		return data, BinaryFrame, nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, UnknownFrame, ErrNotSupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func unmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
 | 
			
		||||
	switch data := v.(type) {
 | 
			
		||||
	case *string:
 | 
			
		||||
		*data = string(msg)
 | 
			
		||||
		return nil
 | 
			
		||||
	case *[]byte:
 | 
			
		||||
		*data = msg
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return ErrNotSupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Message is a codec to send/receive text/binary data in a frame on WebSocket connection.
 | 
			
		||||
To send/receive text frame, use string type.
 | 
			
		||||
To send/receive binary frame, use []byte type.
 | 
			
		||||
 | 
			
		||||
Trivial usage:
 | 
			
		||||
 | 
			
		||||
	import "websocket"
 | 
			
		||||
 | 
			
		||||
	// receive text frame
 | 
			
		||||
	var message string
 | 
			
		||||
	websocket.Message.Receive(ws, &message)
 | 
			
		||||
 | 
			
		||||
	// send text frame
 | 
			
		||||
	message = "hello"
 | 
			
		||||
	websocket.Message.Send(ws, message)
 | 
			
		||||
 | 
			
		||||
	// receive binary frame
 | 
			
		||||
	var data []byte
 | 
			
		||||
	websocket.Message.Receive(ws, &data)
 | 
			
		||||
 | 
			
		||||
	// send binary frame
 | 
			
		||||
	data = []byte{0, 1, 2}
 | 
			
		||||
	websocket.Message.Send(ws, data)
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
var Message = Codec{marshal, unmarshal}
 | 
			
		||||
 | 
			
		||||
func jsonMarshal(v interface{}) (msg []byte, payloadType byte, err error) {
 | 
			
		||||
	msg, err = json.Marshal(v)
 | 
			
		||||
	return msg, TextFrame, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func jsonUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
 | 
			
		||||
	return json.Unmarshal(msg, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
JSON is a codec to send/receive JSON data in a frame from a WebSocket connection.
 | 
			
		||||
 | 
			
		||||
Trivial usage:
 | 
			
		||||
 | 
			
		||||
	import "websocket"
 | 
			
		||||
 | 
			
		||||
	type T struct {
 | 
			
		||||
		Msg string
 | 
			
		||||
		Count int
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// receive JSON type T
 | 
			
		||||
	var data T
 | 
			
		||||
	websocket.JSON.Receive(ws, &data)
 | 
			
		||||
 | 
			
		||||
	// send JSON type T
 | 
			
		||||
	websocket.JSON.Send(ws, data)
 | 
			
		||||
*/
 | 
			
		||||
var JSON = Codec{jsonMarshal, jsonUnmarshal}
 | 
			
		||||
		Reference in New Issue
	
	Block a user