Example #1
0
// New creates a new instance of Proxy. "direct" is a special case URL that simply passes data through.
func New(proxyURLString string) *Proxy {
	proxy := &Proxy{
		Tr: &http.Transport{
			TLSHandshakeTimeout:   10 * time.Second,
			ExpectContinueTimeout: 1 * time.Second,
			DialContext: (&net.Dialer{
				Timeout:   30 * time.Second,
				KeepAlive: 30 * time.Second,
			}).DialContext,
			IdleConnTimeout: 90 * time.Second,
			Dial:            net.Dial,
		},
	}

	if proxyURLString == "direct" {
		proxy.Tr.Proxy = func(req *http.Request) (*url.URL, error) { return nil, nil }
		proxy.Available = func() bool { return true }
		proxy.ConnectDial = nil
	} else {
		proxyURL := earl.ParseWithDefaults(proxyURLString, &earl.URL{Scheme: "auto"})
		proxy.Tr.Proxy = func(req *http.Request) (*url.URL, error) { return proxyURL.ToNetURL(), nil }
		proxy.Available = func() bool { return exec.Command("ping", "-w", "1", proxyURL.Host).Run() == nil }
		proxy.ConnectDial = proxy.connectDialer(proxyURL.ToNetURL().String())
	}

	return proxy
}
Example #2
0
// connectDialer establishes a connection for use with a CONNECT request
// This code is largely derived from github.com/elazarl/go-proxy
func (proxy *Proxy) connectDialer(https_proxy string) func(network, addr string) (net.Conn, error) {
	u := earl.ParseWithDefaults(https_proxy, &earl.URL{Scheme: "auto", Port: "80"})

	return func(network, addr string) (net.Conn, error) {
		client, err := proxy.Tr.Dial(network, u.HostAndPort())
		if err != nil {
			return nil, fmt.Errorf("Proxy refused connection: %s", err)
		}

		if u.Scheme == "https" {
			client = tls.Client(client, proxy.Tr.TLSClientConfig)
		}

		request := &http.Request{
			Method: "CONNECT",
			URL:    &url.URL{Opaque: addr},
			Host:   addr,
			Header: make(http.Header),
		}

		request.Write(client)

		reader := bufio.NewReader(client)
		response, err := http.ReadResponse(reader, request)
		if err != nil {
			client.Close()
			return nil, fmt.Errorf("Error reading response from proxy: %s", err)
		}

		if response.StatusCode != 200 {
			responseText, _ := ioutil.ReadAll(response.Body)
			response.Body.Close()
			client.Close()
			return nil, fmt.Errorf("Proxy error: %s", string(responseText))
		}

		return client, nil
	}
}