11package proxy
22
33import (
4+ "bufio"
45 "crypto/tls"
6+ "encoding/base64"
7+ "fmt"
58 "github.com/pkg/errors"
69 "golang.org/x/net/proxy"
710 "net"
11+ "net/http"
12+ "net/url"
813 "strings"
914 "time"
1015)
@@ -23,7 +28,16 @@ func (d directDialer) Dial(network, addr string) (net.Conn, error) {
2328 Timeout : d .dialTimeout ,
2429 KeepAlive : d .keepAlive ,
2530 }
26- return dialer .Dial (network , addr )
31+ conn , err := dialer .Dial (network , addr )
32+ if err != nil {
33+ return nil , err
34+ }
35+ err = conn .SetDeadline (time .Now ().Add (d .dialTimeout ))
36+ if err != nil {
37+ conn .Close ()
38+ return nil , err
39+ }
40+ return conn , err
2741}
2842
2943type socks5Dialer struct {
@@ -122,3 +136,61 @@ func (d tlsDialer) Dial(network, addr string) (net.Conn, error) {
122136
123137 return conn , nil
124138}
139+
140+ type httpProxy struct {
141+ forwardDialer Dialer
142+ hostPort string
143+ username , password string
144+ }
145+
146+ func (s * httpProxy ) Dial (network , addr string ) (net.Conn , error ) {
147+ reqURL , err := url .Parse ("http://" + addr )
148+ if err != nil {
149+ return nil , err
150+ }
151+ req , err := http .NewRequest ("CONNECT" , reqURL .String (), nil )
152+ if err != nil {
153+ return nil , err
154+ }
155+ req .Close = false
156+ if s .username != "" && s .password != "" {
157+ req .Header .Set ("Proxy-Authorization" , base64 .StdEncoding .EncodeToString ([]byte (s .username + ":" + s .password )))
158+ }
159+
160+ c , err := s .forwardDialer .Dial ("tcp" , s .hostPort )
161+ if err != nil {
162+ return nil , err
163+ }
164+ err = req .Write (c )
165+ if err != nil {
166+ c .Close ()
167+ return nil , err
168+ }
169+
170+ resp , err := http .ReadResponse (bufio .NewReader (c ), req )
171+ if err != nil {
172+ c .Close ()
173+ return nil , err
174+ }
175+ resp .Body .Close ()
176+ if resp .StatusCode != 200 {
177+ c .Close ()
178+ return nil , fmt .Errorf ("connect server using proxy error, statuscode [%d]" , resp .StatusCode )
179+ }
180+
181+ return c , nil
182+ }
183+
184+ func newHTTPProxy (uri * url.URL , forward Dialer ) (Dialer , error ) {
185+ s := new (httpProxy )
186+ s .hostPort = uri .Host
187+ if uri .Port () == "" {
188+ return nil , fmt .Errorf ("http proxy url doesn't contain a port [%v]" , uri )
189+ }
190+ s .forwardDialer = forward
191+ if uri .User != nil {
192+ s .username = uri .User .Username ()
193+ s .password , _ = uri .User .Password ()
194+ }
195+ return s , nil
196+ }
0 commit comments