mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-13 11:11:30 -04:00
Factor out httpRendezvous separate from BrokerChannel.
Makes BrokerChannel abstract over a rendezvousMethod. BrokerChannel itself is responsible for keepLocalAddresses and the NAT type state, as well as encoding and decoding client poll messages. rendezvousMethod is only responsible for delivery of encoded messages.
This commit is contained in:
parent
55f4814dfb
commit
0f34a7778f
4 changed files with 258 additions and 156 deletions
145
client/lib/rendezvous_test.go
Normal file
145
client/lib/rendezvous_test.go
Normal file
|
@ -0,0 +1,145 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"git.torproject.org/pluggable-transports/snowflake.git/common/messages"
|
||||
"git.torproject.org/pluggable-transports/snowflake.git/common/nat"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
// mockTransport's RoundTrip method returns a response with a fake status and
|
||||
// body.
|
||||
type mockTransport struct {
|
||||
statusCode int
|
||||
body []byte
|
||||
}
|
||||
|
||||
func (t *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return &http.Response{
|
||||
Status: fmt.Sprintf("%d %s", t.statusCode, http.StatusText(t.statusCode)),
|
||||
StatusCode: t.statusCode,
|
||||
Body: ioutil.NopCloser(bytes.NewReader(t.body)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// errorTransport's RoundTrip method returns an error.
|
||||
type errorTransport struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (t errorTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return nil, t.err
|
||||
}
|
||||
|
||||
// makeEncPollReq returns an encoded client poll request containing a given
|
||||
// offer.
|
||||
func makeEncPollReq(offer string) []byte {
|
||||
encPollReq, err := (&messages.ClientPollRequest{
|
||||
Offer: offer,
|
||||
NAT: nat.NATUnknown,
|
||||
}).EncodePollRequest()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return encPollReq
|
||||
}
|
||||
|
||||
// makeEncPollResp returns an encoded client poll response with given answer and
|
||||
// error strings.
|
||||
func makeEncPollResp(answer, errorStr string) []byte {
|
||||
encPollResp, err := (&messages.ClientPollResponse{
|
||||
Answer: answer,
|
||||
Error: errorStr,
|
||||
}).EncodePollResponse()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return encPollResp
|
||||
}
|
||||
|
||||
func TestHTTPRendezvous(t *testing.T) {
|
||||
Convey("HTTP rendezvous", t, func() {
|
||||
Convey("Construct httpRendezvous with no front domain", func() {
|
||||
transport := &mockTransport{http.StatusOK, []byte{}}
|
||||
rend, err := newHTTPRendezvous("http://test.broker", "", transport)
|
||||
So(err, ShouldBeNil)
|
||||
So(rend.brokerURL, ShouldNotBeNil)
|
||||
So(rend.brokerURL.Host, ShouldResemble, "test.broker")
|
||||
So(rend.front, ShouldResemble, "")
|
||||
So(rend.transport, ShouldEqual, transport)
|
||||
})
|
||||
|
||||
Convey("Construct httpRendezvous *with* front domain", func() {
|
||||
transport := &mockTransport{http.StatusOK, []byte{}}
|
||||
rend, err := newHTTPRendezvous("http://test.broker", "front", transport)
|
||||
So(err, ShouldBeNil)
|
||||
So(rend.brokerURL, ShouldNotBeNil)
|
||||
So(rend.brokerURL.Host, ShouldResemble, "test.broker")
|
||||
So(rend.front, ShouldResemble, "front")
|
||||
So(rend.transport, ShouldEqual, transport)
|
||||
})
|
||||
|
||||
fakeEncPollReq := makeEncPollReq(`{"type":"offer","sdp":"test"}`)
|
||||
|
||||
Convey("httpRendezvous.Exchange responds with answer", func() {
|
||||
fakeEncPollResp := makeEncPollResp(
|
||||
`{"answer": "{\"type\":\"answer\",\"sdp\":\"fake\"}" }`,
|
||||
"",
|
||||
)
|
||||
rend, err := newHTTPRendezvous("http://test.broker", "",
|
||||
&mockTransport{http.StatusOK, fakeEncPollResp})
|
||||
So(err, ShouldBeNil)
|
||||
answer, err := rend.Exchange(fakeEncPollReq)
|
||||
So(err, ShouldBeNil)
|
||||
So(answer, ShouldResemble, fakeEncPollResp)
|
||||
})
|
||||
|
||||
Convey("httpRendezvous.Exchange responds with no answer", func() {
|
||||
fakeEncPollResp := makeEncPollResp(
|
||||
"",
|
||||
`{"error": "no snowflake proxies currently available"}`,
|
||||
)
|
||||
rend, err := newHTTPRendezvous("http://test.broker", "",
|
||||
&mockTransport{http.StatusOK, fakeEncPollResp})
|
||||
So(err, ShouldBeNil)
|
||||
answer, err := rend.Exchange(fakeEncPollReq)
|
||||
So(err, ShouldBeNil)
|
||||
So(answer, ShouldResemble, fakeEncPollResp)
|
||||
})
|
||||
|
||||
Convey("httpRendezvous.Exchange fails with unexpected HTTP status code", func() {
|
||||
rend, err := newHTTPRendezvous("http://test.broker", "",
|
||||
&mockTransport{http.StatusInternalServerError, []byte{}})
|
||||
So(err, ShouldBeNil)
|
||||
answer, err := rend.Exchange(fakeEncPollReq)
|
||||
So(err, ShouldNotBeNil)
|
||||
So(answer, ShouldBeNil)
|
||||
So(err.Error(), ShouldResemble, BrokerErrorUnexpected)
|
||||
})
|
||||
|
||||
Convey("httpRendezvous.Exchange fails with error", func() {
|
||||
transportErr := errors.New("error")
|
||||
rend, err := newHTTPRendezvous("http://test.broker", "",
|
||||
&errorTransport{err: transportErr})
|
||||
So(err, ShouldBeNil)
|
||||
answer, err := rend.Exchange(fakeEncPollReq)
|
||||
So(err, ShouldEqual, transportErr)
|
||||
So(answer, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("httpRendezvous.Exchange fails with large read", func() {
|
||||
rend, err := newHTTPRendezvous("http://test.broker", "",
|
||||
&mockTransport{http.StatusOK, make([]byte, readLimit+1)})
|
||||
So(err, ShouldBeNil)
|
||||
_, err = rend.Exchange(fakeEncPollReq)
|
||||
So(err, ShouldEqual, io.ErrUnexpectedEOF)
|
||||
})
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue