commit 1d76d3ca2e581bbb345b09444dd1d25dd985673c Author: Cecylia Bocovich cohosh@torproject.org Date: Fri May 10 17:16:35 2019 -0400
Implement limitedRead function for client side
MaxBytesReader is only documented for server side reads, so we're using a local limitedRead function instead that uses an io.LimitedReader.
Declared limits in a commented constant --- broker/broker.go | 7 ++++--- client/lib/rendezvous.go | 21 ++++++++++++++++++++- proxy-go/snowflake.go | 21 ++++++++++++++++++++- 3 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/broker/broker.go b/broker/broker.go index a0ef38a..274d87c 100644 --- a/broker/broker.go +++ b/broker/broker.go @@ -28,6 +28,7 @@ import ( const ( ClientTimeout = 10 ProxyTimeout = 10 + readLimit = 100000 //Maximum number of bytes to be read from an HTTP request )
type BrokerContext struct { @@ -136,7 +137,7 @@ For snowflake proxies to request a client from the Broker. */ func proxyPolls(ctx *BrokerContext, w http.ResponseWriter, r *http.Request) { id := r.Header.Get("X-Session-ID") - body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, 100000)) + body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, readLimit)) if nil != err { log.Println("Invalid data.") w.WriteHeader(http.StatusBadRequest) @@ -166,7 +167,7 @@ the HTTP response back to the client. */ func clientOffers(ctx *BrokerContext, w http.ResponseWriter, r *http.Request) { startTime := time.Now() - offer, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, 100000)) + offer, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, readLimit)) if nil != err { log.Println("Invalid data.") w.WriteHeader(http.StatusBadRequest) @@ -213,7 +214,7 @@ func proxyAnswers(ctx *BrokerContext, w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusGone) return } - body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, 100000)) + body, err := ioutil.ReadAll(http.MaxBytesReader(w, r.Body, readLimit)) if nil != err || nil == body || len(body) <= 0 { log.Println("Invalid data.") w.WriteHeader(http.StatusBadRequest) diff --git a/client/lib/rendezvous.go b/client/lib/rendezvous.go index e53c51e..7f03d13 100644 --- a/client/lib/rendezvous.go +++ b/client/lib/rendezvous.go @@ -11,6 +11,7 @@ package lib import ( "bytes" "errors" + "io" "io/ioutil" "log" "net/http" @@ -23,6 +24,7 @@ const ( BrokerError503 string = "No snowflake proxies currently available." BrokerError400 string = "You sent an invalid offer in the request." BrokerErrorUnexpected string = "Unexpected error, no answer." + readLimit = 100000 //Maximum number of bytes to be read from an HTTP response )
// Signalling Channel to the Broker. @@ -64,6 +66,23 @@ func NewBrokerChannel(broker string, front string, transport http.RoundTripper) return bc }
+func limitedRead(r io.Reader, limit int64) ([]byte, error) { + p, err := ioutil.ReadAll(&io.LimitedReader{r, limit}) + if err != nil { + return p, err + } + + //Check to see if limit was exceeded + var tmp [1]byte + _, err = io.ReadFull(r, tmp[:]) + if err == io.EOF { + err = nil + } else if err == nil { + err = io.ErrUnexpectedEOF + } + return p, err +} + // Roundtrip HTTP POST using WebRTC SessionDescriptions. // // Send an SDP offer to the broker, which assigns a proxy and responds @@ -91,7 +110,7 @@ func (bc *BrokerChannel) Negotiate(offer *webrtc.SessionDescription) (
switch resp.StatusCode { case http.StatusOK: - body, err := ioutil.ReadAll(http.MaxBytesReader(nil, resp.Body, 100000)) + body, err := limitedRead(resp.Body, readLimit) if nil != err { return nil, err } diff --git a/proxy-go/snowflake.go b/proxy-go/snowflake.go index ebab790..ececda3 100644 --- a/proxy-go/snowflake.go +++ b/proxy-go/snowflake.go @@ -32,6 +32,8 @@ const pollInterval = 5 * time.Second //client is not going to connect const dataChannelTimeout = 20 * time.Second
+const readLimit = 100000 //Maximum number of bytes to be read from an HTTP request + var brokerURL *url.URL var relayURL string
@@ -137,6 +139,23 @@ func genSessionID() string { return strings.TrimRight(base64.StdEncoding.EncodeToString(buf), "=") }
+func limitedRead(r io.Reader, limit int64) ([]byte, error) { + p, err := ioutil.ReadAll(&io.LimitedReader{r, limit}) + if err != nil { + return p, err + } + + //Check to see if limit was exceeded + var tmp [1]byte + _, err = io.ReadFull(r, tmp[:]) + if err == io.EOF { + err = nil + } else if err == nil { + err = io.ErrUnexpectedEOF + } + return p, err +} + func pollOffer(sid string) *webrtc.SessionDescription { broker := brokerURL.ResolveReference(&url.URL{Path: "proxy"}) timeOfNextPoll := time.Now() @@ -162,7 +181,7 @@ func pollOffer(sid string) *webrtc.SessionDescription { if resp.StatusCode != http.StatusOK { log.Printf("broker returns: %d", resp.StatusCode) } else { - body, err := ioutil.ReadAll(http.MaxBytesReader(nil, resp.Body, 100000)) + body, err := limitedRead(resp.Body, readLimit) if err != nil { log.Printf("error reading broker response: %s", err) } else {
tor-commits@lists.torproject.org