privatize the client, only expose Dial functions

This commit is contained in:
Marten Seemann
2017-02-22 12:21:33 +07:00
parent 48dee2708e
commit 96edca5219
7 changed files with 214 additions and 188 deletions

View File

@@ -20,23 +20,19 @@ import (
"github.com/lucas-clemente/quic-go/utils"
)
type quicClient interface {
OpenStream() (quic.Stream, error)
Close(error) error
Listen() error
}
// Client is a HTTP2 client doing QUIC requests
type Client struct {
mutex sync.RWMutex
cryptoChangedCond sync.Cond
config *quic.Config
t *QuicRoundTripper
hostname string
encryptionLevel protocol.EncryptionLevel
client quicClient
session quic.Session
headerStream quic.Stream
headerErr *qerr.QuicError
requestWriter *requestWriter
@@ -47,42 +43,50 @@ type Client struct {
var _ h2quicClient = &Client{}
// NewClient creates a new client
func NewClient(t *QuicRoundTripper, tlsConfig *tls.Config, hostname string) (*Client, error) {
func NewClient(t *QuicRoundTripper, tlsConfig *tls.Config, hostname string) *Client {
c := &Client{
t: t,
hostname: authorityAddr("https", hostname),
responses: make(map[protocol.StreamID]chan *http.Response),
}
c.cryptoChangedCond = sync.Cond{L: &c.mutex}
var err error
c.client, err = quic.NewClient(c.hostname, tlsConfig, c.cryptoChangeCallback, c.versionNegotiateCallback)
if err != nil {
return nil, err
c.config = &quic.Config{
ConnState: c.connStateCallback,
}
go c.client.Listen()
return c, nil
return c
}
func (c *Client) cryptoChangeCallback(isForwardSecure bool) {
c.cryptoChangedCond.L.Lock()
defer c.cryptoChangedCond.L.Unlock()
// Dial dials the connection
func (c *Client) Dial() error {
_, err := quic.DialAddr(c.hostname, c.config)
return err
}
if isForwardSecure {
c.encryptionLevel = protocol.EncryptionForwardSecure
utils.Debugf("is forward secure")
} else {
func (c *Client) connStateCallback(sess quic.Session, state quic.ConnState) {
c.mutex.Lock()
if c.session == nil {
c.session = sess
}
switch state {
case quic.ConnStateVersionNegotiated:
// TODO: handle errors
c.versionNegotiateCallback()
case quic.ConnStateSecure:
c.encryptionLevel = protocol.EncryptionSecure
utils.Debugf("is secure")
c.cryptoChangedCond.Broadcast()
case quic.ConnStateForwardSecure:
c.encryptionLevel = protocol.EncryptionForwardSecure
utils.Debugf("is forward secure")
c.cryptoChangedCond.Broadcast()
}
c.cryptoChangedCond.Broadcast()
c.mutex.Unlock()
}
func (c *Client) versionNegotiateCallback() error {
var err error
// once the version has been negotiated, open the header stream
c.headerStream, err = c.client.OpenStream()
c.headerStream, err = c.session.OpenStream()
if err != nil {
return err
}
@@ -162,7 +166,7 @@ func (c *Client) Do(req *http.Request) (*http.Response, error) {
}
hdrChan := make(chan *http.Response)
// TODO: think about what to do with a TooManyOpenStreams error. Wait and retry?
dataStream, err := c.client.OpenStream()
dataStream, err := c.session.OpenStream()
if err != nil {
c.Close(err)
return nil, err
@@ -260,7 +264,7 @@ func (c *Client) writeRequestBody(dataStream quic.Stream, body io.ReadCloser) (e
// Close closes the client
func (c *Client) Close(e error) {
_ = c.client.Close(e)
_ = c.session.Close(e)
}
// copied from net/transport.go