mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-14 05:11:19 -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
77
client/lib/rendezvous_http.go
Normal file
77
client/lib/rendezvous_http.go
Normal file
|
@ -0,0 +1,77 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// httpRendezvous is a rendezvousMethod that communicates with the .../client
|
||||
// route of the broker over HTTP or HTTPS, with optional domain fronting.
|
||||
type httpRendezvous struct {
|
||||
brokerURL *url.URL
|
||||
front string // Optional front domain to replace url.Host in requests.
|
||||
transport http.RoundTripper // Used to make all requests.
|
||||
}
|
||||
|
||||
// newHTTPRendezvous creates a new httpRendezvous that contacts the broker at
|
||||
// the given URL, with an optional front domain. transport is the
|
||||
// http.RoundTripper used to make all requests.
|
||||
func newHTTPRendezvous(broker, front string, transport http.RoundTripper) (*httpRendezvous, error) {
|
||||
brokerURL, err := url.Parse(broker)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &httpRendezvous{
|
||||
brokerURL: brokerURL,
|
||||
front: front,
|
||||
transport: transport,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *httpRendezvous) Exchange(encPollReq []byte) ([]byte, error) {
|
||||
log.Println("Negotiating via HTTP rendezvous...")
|
||||
log.Println("Target URL: ", r.brokerURL.Host)
|
||||
log.Println("Front URL: ", r.front)
|
||||
|
||||
// Suffix the path with the broker's client registration handler.
|
||||
reqURL := r.brokerURL.ResolveReference(&url.URL{Path: "client"})
|
||||
req, err := http.NewRequest("POST", reqURL.String(), bytes.NewReader(encPollReq))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r.front != "" {
|
||||
// Do domain fronting. Replace the domain in the URL's with the
|
||||
// front, and store the original domain the HTTP Host header.
|
||||
req.Host = req.URL.Host
|
||||
req.URL.Host = r.front
|
||||
}
|
||||
|
||||
resp, err := r.transport.RoundTrip(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
log.Printf("HTTP rendezvous response: %s", resp.Status)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(BrokerErrorUnexpected)
|
||||
}
|
||||
|
||||
return limitedRead(resp.Body, readLimit)
|
||||
}
|
||||
|
||||
func limitedRead(r io.Reader, limit int64) ([]byte, error) {
|
||||
p, err := ioutil.ReadAll(&io.LimitedReader{R: r, N: limit + 1})
|
||||
if err != nil {
|
||||
return p, err
|
||||
} else if int64(len(p)) == limit+1 {
|
||||
return p[0:limit], io.ErrUnexpectedEOF
|
||||
}
|
||||
return p, err
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue