[tor-commits] [meek/master] Honor an http proxy when roundtripping through the helper.

dcf at torproject.org dcf at torproject.org
Wed May 28 07:03:21 UTC 2014


commit bb22b14120357f084d7e63d26c3ee493bc270236
Author: David Fifield <david at bamsoftware.com>
Date:   Sat May 24 22:37:17 2014 -0700

    Honor an http proxy when roundtripping through the helper.
---
 meek-client/helper.go      |   55 ++++++++++++++++++++++++++++++++++++++++++++
 meek-client/helper_test.go |   50 ++++++++++++++++++++++++++++++++++++++++
 meek-client/meek-client.go |    4 +++-
 3 files changed, 108 insertions(+), 1 deletion(-)

diff --git a/meek-client/helper.go b/meek-client/helper.go
index 49423fb..d85ac8d 100644
--- a/meek-client/helper.go
+++ b/meek-client/helper.go
@@ -10,6 +10,8 @@ import (
 	"io/ioutil"
 	"net"
 	"net/http"
+	"net/url"
+	"strconv"
 	"time"
 )
 
@@ -21,6 +23,7 @@ type JSONRequest struct {
 	URL    string            `json:"url,omitempty"`
 	Header map[string]string `json:"header,omitempty"`
 	Body   []byte            `json:"body,omitempty"`
+	Proxy  *ProxySpec        `json:"proxy,omitempty"`
 }
 
 type JSONResponse struct {
@@ -29,6 +32,54 @@ type JSONResponse struct {
 	Body   []byte `json:"body"`
 }
 
+// ProxySpec encodes information we need to connect through a proxy.
+type ProxySpec struct {
+	// Acceptable values for Type are as in proposal 232: "http", "socks5",
+	// or "socks4a".
+	Type string `json:"type"`
+	Host string `json:"host"`
+	Port int    `json:"port"`
+}
+
+// Return a ProxySpec suitable for the proxy URL in u.
+func makeProxySpec(u *url.URL) (*ProxySpec, error) {
+	spec := new(ProxySpec)
+	var err error
+	var portStr string
+	var port uint64
+
+	if u == nil {
+		// No proxy.
+		return nil, nil
+	}
+
+	// Firefox's nsIProxyInfo doesn't allow credentials.
+	if u.User != nil {
+		return nil, errors.New("proxy URLs with a username or password can't be used with the helper")
+	}
+
+	if u.Scheme == "http" {
+		spec.Type = "http"
+	} else {
+		return nil, errors.New("unknown scheme")
+	}
+
+	spec.Host, portStr, err = net.SplitHostPort(u.Host)
+	if err != nil {
+		return nil, err
+	}
+	if spec.Host == "" {
+		return nil, errors.New("missing host")
+	}
+	port, err = strconv.ParseUint(portStr, 10, 16)
+	if err != nil {
+		return nil, err
+	}
+	spec.Port = int(port)
+
+	return spec, nil
+}
+
 // Do an HTTP roundtrip through the configured browser extension, using the
 // payload data in buf and the request metadata in info.
 func roundTripWithHelper(buf []byte, info *RequestInfo) (*http.Response, error) {
@@ -49,6 +100,10 @@ func roundTripWithHelper(buf []byte, info *RequestInfo) (*http.Response, error)
 	if info.Host != "" {
 		req.Header["Host"] = info.Host
 	}
+	req.Proxy, err = makeProxySpec(options.ProxyURL)
+	if err != nil {
+		return nil, err
+	}
 	encReq, err := json.Marshal(&req)
 	if err != nil {
 		return nil, err
diff --git a/meek-client/helper_test.go b/meek-client/helper_test.go
new file mode 100644
index 0000000..4a34e35
--- /dev/null
+++ b/meek-client/helper_test.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+	"net/url"
+	"testing"
+)
+
+func TestMakeProxySpec(t *testing.T) {
+	badTests := [...]url.URL{
+		url.URL{Scheme: "http"},
+		url.URL{Scheme: "http", Host: ":"},
+		url.URL{Scheme: "http", Host: "localhost"},
+		url.URL{Scheme: "http", Host: "localhost:"},
+		url.URL{Scheme: "http", Host: ":8080"},
+		url.URL{Scheme: "http", Host: "localhost:https"},
+		url.URL{Scheme: "http", Host: "localhost:8080", User: url.User("username")},
+		url.URL{Scheme: "http", Host: "localhost:8080", User: url.UserPassword("username", "password")},
+		url.URL{Scheme: "http", User: url.User("username"), Host: "localhost:8080"},
+		url.URL{Scheme: "http", User: url.UserPassword("username", "password"), Host: "localhost:8080"},
+		url.URL{Scheme: "http", Host: "localhost:-1"},
+		url.URL{Scheme: "http", Host: "localhost:65536"},
+		url.URL{Scheme: "unknown", Host: "localhost:9999"},
+	}
+	goodTests := [...]struct {
+		input    url.URL
+		expected ProxySpec
+	}{
+		{
+			url.URL{Scheme: "http", Host: "localhost:8080"},
+			ProxySpec{"http", "localhost", 8080},
+		},
+	}
+
+	for _, input := range badTests {
+		_, err := makeProxySpec(&input)
+		if err == nil {
+			t.Errorf("%q unexpectedly succeeded", input)
+		}
+	}
+
+	for _, test := range goodTests {
+		spec, err := makeProxySpec(&test.input)
+		if err != nil {
+			t.Fatalf("%q unexpectedly returned an error: %s", test.input, err)
+		}
+		if *spec != test.expected {
+			t.Errorf("%q → %q (expected %q)", test.input, spec, test.expected)
+		}
+	}
+}
diff --git a/meek-client/meek-client.go b/meek-client/meek-client.go
index 5f7228e..72e379f 100644
--- a/meek-client/meek-client.go
+++ b/meek-client/meek-client.go
@@ -320,7 +320,9 @@ func checkProxyURL(u *url.URL) error {
 		return errors.New(fmt.Sprintf("don't understand proxy URL scheme %q", options.ProxyURL.Scheme))
 	}
 	if options.HelperAddr != nil {
-		return errors.New("--helper can't be used with an upstream proxy")
+		if options.ProxyURL.User != nil {
+			return errors.New("a proxy URL with a username or password can't be used with --helper")
+		}
 	}
 	return nil
 }





More information about the tor-commits mailing list