commit bb22b14120357f084d7e63d26c3ee493bc270236
Author: David Fifield <da...@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
 }



_______________________________________________
tor-commits mailing list
tor-commits@lists.torproject.org
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits

Reply via email to