glider/proxy/ws/client.go

121 lines
2.8 KiB
Go
Raw Normal View History

2018-07-21 22:56:37 +08:00
package ws
import (
"errors"
"io"
"net"
"net/textproto"
2020-04-19 23:20:15 +08:00
"github.com/nadoo/glider/pool"
2020-10-19 20:45:57 +08:00
"github.com/nadoo/glider/proxy"
2018-07-21 22:56:37 +08:00
)
2020-10-19 20:45:57 +08:00
func init() {
proxy.RegisterDialer("ws", NewWSDialer)
}
2018-07-24 00:45:41 +08:00
2020-10-19 20:45:57 +08:00
// NewWSDialer returns a ws proxy dialer.
func NewWSDialer(s string, d proxy.Dialer) (proxy.Dialer, error) {
return NewWS(s, d, nil)
2018-07-21 22:56:37 +08:00
}
2020-10-19 20:45:57 +08:00
// Addr returns forwarder's address.
func (s *WS) Addr() string {
if s.addr == "" {
return s.dialer.Addr()
}
return s.addr
2018-07-21 22:56:37 +08:00
}
2020-10-19 20:45:57 +08:00
// Dial connects to the address addr on the network net via the proxy.
func (s *WS) Dial(network, addr string) (net.Conn, error) {
rc, err := s.dialer.Dial("tcp", s.addr)
if err != nil {
return nil, err
}
2020-10-19 20:45:57 +08:00
return s.NewClientConn(rc)
2018-07-21 22:56:37 +08:00
}
2020-10-19 20:45:57 +08:00
// DialUDP connects to the given address via the proxy.
func (s *WS) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
return nil, nil, errors.New("[ws] ws client does not support udp now")
}
// ClientConn is a connection to ws server.
type ClientConn struct {
net.Conn
reader io.Reader
writer io.Writer
}
// NewClientConn creates a new ws client connection.
func (s *WS) NewClientConn(rc net.Conn) (*ClientConn, error) {
conn := &ClientConn{Conn: rc}
return conn, conn.Handshake(s.host, s.path, s.origin)
2018-07-21 22:56:37 +08:00
}
2019-09-07 17:17:38 +08:00
// Handshake handshakes with the server using HTTP to request a protocol upgrade.
func (c *ClientConn) Handshake(host, path, origin string) error {
2018-07-24 00:45:41 +08:00
clientKey := generateClientKey()
2020-11-03 22:52:50 +08:00
buf := pool.GetBytesBuffer()
defer pool.PutBytesBuffer(buf)
2020-04-19 23:20:15 +08:00
2019-09-07 17:17:38 +08:00
buf.WriteString("GET " + path + " HTTP/1.1\r\n")
buf.WriteString("Host: " + host + "\r\n")
buf.WriteString("Upgrade: websocket\r\n")
buf.WriteString("Connection: Upgrade\r\n")
if origin != "" {
buf.WriteString("Origin: http://" + origin + "\r\n")
}
2019-09-07 17:17:38 +08:00
buf.WriteString("Sec-WebSocket-Key: " + clientKey + "\r\n")
buf.WriteString("Sec-WebSocket-Protocol: binary\r\n")
buf.WriteString("Sec-WebSocket-Version: 13\r\n")
buf.WriteString(("\r\n"))
2018-07-24 00:45:41 +08:00
if _, err := c.Conn.Write(buf.Bytes()); err != nil {
return err
}
2018-07-21 22:56:37 +08:00
2020-11-03 22:52:50 +08:00
br := pool.GetBufReader(c.Conn)
defer pool.PutBufReader(br)
tpr := textproto.NewReader(br)
2019-09-07 17:17:38 +08:00
line, err := tpr.ReadLine()
if err != nil {
return err
}
_, code, _, ok := parseFirstLine(line)
2018-07-21 22:56:37 +08:00
if !ok || code != "101" {
return errors.New("[ws] error in ws handshake, got wrong response: " + line)
2018-07-21 22:56:37 +08:00
}
2018-07-24 00:45:41 +08:00
respHeader, err := tpr.ReadMIMEHeader()
if err != nil {
return err
}
2018-07-21 22:56:37 +08:00
2018-07-24 00:45:41 +08:00
serverKey := respHeader.Get("Sec-WebSocket-Accept")
if serverKey != computeServerKey(clientKey) {
return errors.New("[ws] error in ws handshake, got wrong Sec-Websocket-Key")
}
2018-07-21 22:56:37 +08:00
return nil
}
2020-10-19 20:45:57 +08:00
func (c *ClientConn) Write(b []byte) (n int, err error) {
2018-07-21 22:56:37 +08:00
if c.writer == nil {
2020-10-20 20:28:35 +08:00
c.writer = FrameWriter(c.Conn, false)
2018-07-21 22:56:37 +08:00
}
return c.writer.Write(b)
}
2020-10-19 20:45:57 +08:00
func (c *ClientConn) Read(b []byte) (n int, err error) {
2018-07-21 22:56:37 +08:00
if c.reader == nil {
2020-10-20 20:28:35 +08:00
c.reader = FrameReader(c.Conn, false)
2018-07-21 22:56:37 +08:00
}
return c.reader.Read(b)
}