[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [meek/master] Refactor the helper into an http.RoundTripper.
commit 15108412e6d608ebaaadbf8df84f62a4da96afe7
Author: David Fifield <david@xxxxxxxxxxxxxxx>
Date: Mon Jan 14 22:52:14 2019 -0700
Refactor the helper into an http.RoundTripper.
---
meek-client/helper.go | 82 ++++++++++++++++++++++++++++++++++++++--------
meek-client/meek-client.go | 23 ++++++++-----
2 files changed, 83 insertions(+), 22 deletions(-)
diff --git a/meek-client/helper.go b/meek-client/helper.go
index 6b89f5a..f412aaa 100644
--- a/meek-client/helper.go
+++ b/meek-client/helper.go
@@ -9,6 +9,7 @@ import (
"io/ioutil"
"net"
"net/http"
+ "net/textproto"
"net/url"
"strconv"
"time"
@@ -40,6 +41,11 @@ type ProxySpec struct {
Port int `json:"port"`
}
+type HelperRoundTripper struct {
+ ReadTimeout time.Duration
+ WriteTimeout time.Duration
+}
+
// Return a ProxySpec suitable for the proxy URL in u.
func makeProxySpec(u *url.URL) (*ProxySpec, error) {
spec := new(ProxySpec)
@@ -80,9 +86,7 @@ func makeProxySpec(u *url.URL) (*ProxySpec, error) {
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) {
+func (rt *HelperRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
s, err := net.DialTCP("tcp", nil, options.HelperAddr)
if err != nil {
return nil, err
@@ -90,28 +94,51 @@ func roundTripWithHelper(buf []byte, info *RequestInfo) (*http.Response, error)
defer s.Close()
// Encode our JSON.
- req := JSONRequest{
- Method: "POST",
- URL: info.URL.String(),
+ jsonReq := JSONRequest{
+ Method: req.Method,
+ URL: req.URL.String(),
Header: make(map[string]string),
- Body: buf,
+ Body: make([]byte, 0),
}
- req.Header["X-Session-Id"] = info.SessionID
- if info.Host != "" {
- req.Header["Host"] = info.Host
+
+ // We take only the first value for each header key, due to limitations
+ // in the helper JSON protocol.
+ for key, values := range req.Header {
+ if len(values) == 0 {
+ continue
+ }
+ value := values[0]
+ key = textproto.CanonicalMIMEHeaderKey(key)
+ jsonReq.Header[key] = value
+ }
+ // req.Host overrides req.Header.
+ if req.Host != "" {
+ jsonReq.Header["Host"] = req.Host
}
- req.Proxy, err = makeProxySpec(options.ProxyURL)
+
+ if req.Body != nil {
+ jsonReq.Body, err = ioutil.ReadAll(req.Body)
+ if err != nil {
+ return nil, err
+ }
+ err = req.Body.Close()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ jsonReq.Proxy, err = makeProxySpec(options.ProxyURL)
if err != nil {
return nil, err
}
- encReq, err := json.Marshal(&req)
+ encReq, err := json.Marshal(&jsonReq)
if err != nil {
return nil, err
}
// log.Printf("encoded %s", encReq)
// Send the request.
- s.SetWriteDeadline(time.Now().Add(helperWriteTimeout))
+ s.SetWriteDeadline(time.Now().Add(rt.WriteTimeout))
err = binary.Write(s, binary.BigEndian, uint32(len(encReq)))
if err != nil {
return nil, err
@@ -123,7 +150,7 @@ func roundTripWithHelper(buf []byte, info *RequestInfo) (*http.Response, error)
// Read the response.
var length uint32
- s.SetReadDeadline(time.Now().Add(helperReadTimeout))
+ s.SetReadDeadline(time.Now().Add(rt.ReadTimeout))
err = binary.Read(s, binary.BigEndian, &length)
if err != nil {
return nil, err
@@ -159,3 +186,30 @@ func roundTripWithHelper(buf []byte, info *RequestInfo) (*http.Response, error)
}
return &resp, 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) {
+ var body io.Reader
+ if len(buf) > 0 {
+ // Leave body == nil when buf is empty. A nil body is an
+ // explicit signal that the body is empty. An empty
+ // *bytes.Reader or the magic value http.NoBody are supposed to
+ // be equivalent ways to signal an empty body, but in Go 1.8 the
+ // HTTP/2 code only understands nil. Not leaving body == nil
+ // causes the Content-Length header to be omitted from HTTP/2
+ // requests, which in some cases can cause the server to return
+ // a 411 "Length Required" error. See
+ // https://bugs.torproject.org/22865.
+ body = bytes.NewReader(buf)
+ }
+ req, err := http.NewRequest("POST", info.URL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+ if info.Host != "" {
+ req.Host = info.Host
+ }
+ req.Header.Set("X-Session-Id", info.SessionID)
+ return helperRoundTripper.RoundTrip(req)
+}
diff --git a/meek-client/meek-client.go b/meek-client/meek-client.go
index bbacbb4..3923b9a 100644
--- a/meek-client/meek-client.go
+++ b/meek-client/meek-client.go
@@ -83,10 +83,16 @@ const (
var ptInfo pt.ClientInfo
-// We use this RoundTripper to make all our requests (when --helper is not
-// used). We use the defaults, except we take control of the Proxy setting
+// We use this RoundTripper to make all our requests when --helper is not
+// in effect. We use the defaults, except we take control of the Proxy setting
// (notably, disabling the default ProxyFromEnvironment).
-var httpTransport *http.Transport = http.DefaultTransport.(*http.Transport)
+var httpRoundTripper *http.Transport = http.DefaultTransport.(*http.Transport)
+
+// We use this RoundTripper when --helper is in effect.
+var helperRoundTripper = &HelperRoundTripper{
+ ReadTimeout: helperReadTimeout,
+ WriteTimeout: helperWriteTimeout,
+}
// Store for command line options.
var options struct {
@@ -137,7 +143,7 @@ func roundTripWithHTTP(buf []byte, info *RequestInfo) (*http.Response, error) {
req.Host = info.Host
}
req.Header.Set("X-Session-Id", info.SessionID)
- return httpTransport.RoundTrip(req)
+ return httpRoundTripper.RoundTrip(req)
}
// Do a roundtrip, trying at most limit times if there is an HTTP status other
@@ -411,9 +417,10 @@ func main() {
}
}
- // Disable the default ProxyFromEnvironment setting. httpTransport.Proxy
- // is overridden below if options.ProxyURL is set.
- httpTransport.Proxy = nil
+ // Disable the default ProxyFromEnvironment setting.
+ // httpRoundTripper.Proxy is overridden below if options.ProxyURL is
+ // set.
+ httpRoundTripper.Proxy = nil
// Command-line proxy overrides managed configuration.
if options.ProxyURL == nil {
@@ -427,7 +434,7 @@ func main() {
log.Fatal(fmt.Sprintf("proxy error: %s", err))
}
log.Printf("using proxy %s", options.ProxyURL.String())
- httpTransport.Proxy = http.ProxyURL(options.ProxyURL)
+ httpRoundTripper.Proxy = http.ProxyURL(options.ProxyURL)
if ptInfo.ProxyURL != nil {
pt.ProxyDone()
}
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits