...
1
2
3
4
5 package websocket
6
7 import (
8 "bufio"
9 "encoding/base64"
10 "errors"
11 "net"
12 "net/http"
13 "net/url"
14 "strings"
15 )
16
17 type netDialerFunc func(network, addr string) (net.Conn, error)
18
19 func (fn netDialerFunc) Dial(network, addr string) (net.Conn, error) {
20 return fn(network, addr)
21 }
22
23 func init() {
24 proxy_RegisterDialerType("http", func(proxyURL *url.URL, forwardDialer proxy_Dialer) (proxy_Dialer, error) {
25 return &httpProxyDialer{proxyURL: proxyURL, forwardDial: forwardDialer.Dial}, nil
26 })
27 }
28
29 type httpProxyDialer struct {
30 proxyURL *url.URL
31 forwardDial func(network, addr string) (net.Conn, error)
32 }
33
34 func (hpd *httpProxyDialer) Dial(network string, addr string) (net.Conn, error) {
35 hostPort, _ := hostPortNoPort(hpd.proxyURL)
36 conn, err := hpd.forwardDial(network, hostPort)
37 if err != nil {
38 return nil, err
39 }
40
41 connectHeader := make(http.Header)
42 if user := hpd.proxyURL.User; user != nil {
43 proxyUser := user.Username()
44 if proxyPassword, passwordSet := user.Password(); passwordSet {
45 credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword))
46 connectHeader.Set("Proxy-Authorization", "Basic "+credential)
47 }
48 }
49
50 connectReq := &http.Request{
51 Method: http.MethodConnect,
52 URL: &url.URL{Opaque: addr},
53 Host: addr,
54 Header: connectHeader,
55 }
56
57 if err := connectReq.Write(conn); err != nil {
58 conn.Close()
59 return nil, err
60 }
61
62
63
64 br := bufio.NewReader(conn)
65 resp, err := http.ReadResponse(br, connectReq)
66 if err != nil {
67 conn.Close()
68 return nil, err
69 }
70
71 if resp.StatusCode != 200 {
72 conn.Close()
73 f := strings.SplitN(resp.Status, " ", 2)
74 return nil, errors.New(f[1])
75 }
76 return conn, nil
77 }
78
View as plain text