-
-
Save benjivesterby/c472aed15968f91707ed76d3930e31c7 to your computer and use it in GitHub Desktop.
Register Dialer Type for HTTP&HTTPS Proxy in golang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"fmt" | |
"net" | |
"net/http" | |
"net/url" | |
"crypto/tls" | |
"golang.org/x/net/proxy" | |
) | |
type direct struct{} | |
// Direct is a direct proxy: one that makes network connections directly. | |
var Direct = direct{} | |
func (direct) Dial(network, addr string) (net.Conn, error) { | |
return net.Dial(network, addr) | |
} | |
// httpsDialer | |
type httpsDialer struct {} | |
// HTTPSDialer is a https proxy: one that makes network connections on tls. | |
var HttpsDialer = httpsDialer{} | |
var TlsConfig = &tls.Config{} | |
func (d httpsDialer) Dial(network, addr string) (c net.Conn, err error) { | |
c, err = tls.Dial("tcp", addr, TlsConfig) | |
if err != nil { | |
fmt.Println(err) | |
} | |
return | |
} | |
// httpProxy is a HTTP/HTTPS connect proxy. | |
type httpProxy struct { | |
host string | |
haveAuth bool | |
username string | |
password string | |
forward proxy.Dialer | |
} | |
func newHTTPProxy(uri *url.URL, forward proxy.Dialer) (proxy.Dialer, error) { | |
s := new(httpProxy) | |
s.host = uri.Host | |
s.forward = forward | |
if uri.User != nil { | |
s.haveAuth = true | |
s.username = uri.User.Username() | |
s.password, _ = uri.User.Password() | |
} | |
return s, nil | |
} | |
func (s *httpProxy) Dial(network, addr string) (net.Conn, error) { | |
// Dial and create the https client connection. | |
c, err := s.forward.Dial("tcp", s.host) | |
if err != nil { | |
return nil, err | |
} | |
// HACK. http.ReadRequest also does this. | |
reqURL, err := url.Parse("http://" + addr) | |
if err != nil { | |
c.Close() | |
return nil, err | |
} | |
reqURL.Scheme = "" | |
req, err := http.NewRequest("CONNECT", reqURL.String(), nil) | |
if err != nil { | |
c.Close() | |
return nil, err | |
} | |
req.Close = false | |
if s.haveAuth { | |
req.SetBasicAuth(s.username, s.password) | |
} | |
req.Header.Set("User-Agent", "Powerby Gota") | |
err = req.Write(c) | |
if err != nil { | |
c.Close() | |
return nil, err | |
} | |
resp, err := http.ReadResponse(bufio.NewReader(c), req) | |
if err != nil { | |
// TODO close resp body ? | |
resp.Body.Close() | |
c.Close() | |
return nil, err | |
} | |
resp.Body.Close() | |
if resp.StatusCode != 200 { | |
c.Close() | |
err = fmt.Errorf("Connect server using proxy error, StatusCode [%d]", resp.StatusCode) | |
return nil, err | |
} | |
return c, nil | |
} | |
func FromURL(u *url.URL, forward proxy.Dialer) (proxy.Dialer, error){ | |
return proxy.FromURL(u, forward) | |
} | |
func FromEnvironment() proxy.Dialer { | |
return proxy.FromEnvironment() | |
} | |
func init() { | |
proxy.RegisterDialerType("http", newHTTPProxy) | |
proxy.RegisterDialerType("https", newHTTPProxy) | |
} | |
func main() { | |
// http proxy | |
httpProxyURI, _ := url.Parse("http://your http proxy:3128") | |
httpDialer, err := proxy.FromURL(httpProxyURI, Direct) | |
conn, err := httpDialer.Dial("tcp", "google.com:80") | |
if err != nil { | |
panic(err) | |
} | |
fmt.Printf("Create http tunnel OK: %+v\n", conn) | |
httpsProxyURI, _ := url.Parse("https://your https proxy:443") | |
httpsDialer, err := proxy.FromURL(httpsProxyURI, HttpsDialer) | |
conn, err = httpsDialer.Dial("tcp", "google.com:443") | |
if err != nil { | |
panic(err) | |
} | |
fmt.Printf("Create https tunnel OK: %+v\n", conn) | |
// TODO use conn | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment