Skip to content

Commit e71042d

Browse files
committed
http2: add Transport.AddIdleConn
This adds the http2 Transport method needed by https://golang.org/cl/16090 to glue the HTTP/1 Transport (net/http.Transport) to the http2.Transport without throwing away fresh TCP connections after the TLS handshake determines which NPN/ALPN protocol was selected. Updates golang/go#6891 Change-Id: Iba004c8b1a149a5ee6c755d9a3fc1b19856a4e47 Reviewed-on: https://go-review.googlesource.com/16180 Reviewed-by: Andrew Gerrand <[email protected]>
1 parent 9946ad7 commit e71042d

File tree

1 file changed

+44
-8
lines changed

1 file changed

+44
-8
lines changed

http2/transport.go

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -157,29 +157,61 @@ func filterOutClientConn(in []*clientConn, exclude *clientConn) []*clientConn {
157157
return out
158158
}
159159

160-
func (t *Transport) getClientConn(host, port string) (*clientConn, error) {
160+
// AddIdleConn adds c as an idle conn for Transport.
161+
// It assumes that c has not yet exchanged SETTINGS frames.
162+
// The addr maybe be either "host" or "host:port".
163+
func (t *Transport) AddIdleConn(addr string, c *tls.Conn) error {
164+
var key string
165+
host, _, err := net.SplitHostPort(addr)
166+
if err == nil {
167+
key = addr
168+
} else {
169+
host = addr
170+
key = addr + ":443"
171+
}
172+
cc, err := t.newClientConn(host, key, c)
173+
if err != nil {
174+
return err
175+
}
176+
177+
t.addConn(key, cc)
178+
return nil
179+
}
180+
181+
func (t *Transport) addConn(key string, cc *clientConn) {
161182
t.connMu.Lock()
162183
defer t.connMu.Unlock()
184+
if t.conns == nil {
185+
t.conns = make(map[string][]*clientConn)
186+
}
187+
t.conns[key] = append(t.conns[key], cc)
188+
}
163189

190+
func (t *Transport) getClientConn(host, port string) (*clientConn, error) {
164191
key := net.JoinHostPort(host, port)
165192

193+
t.connMu.Lock()
166194
for _, cc := range t.conns[key] {
167195
if cc.canTakeNewRequest() {
196+
t.connMu.Unlock()
168197
return cc, nil
169198
}
170199
}
171-
if t.conns == nil {
172-
t.conns = make(map[string][]*clientConn)
173-
}
174-
cc, err := t.newClientConn(host, port, key)
200+
t.connMu.Unlock()
201+
202+
// TODO(bradfitz): use a singleflight.Group to only lock once per 'key'.
203+
// Probably need to vendor it in as github.com/golang/sync/singleflight
204+
// though, since the net package already uses it? Also lines up with
205+
// sameer, bcmills, et al wanting to open source some sync stuff.
206+
cc, err := t.dialClientConn(host, port, key)
175207
if err != nil {
176208
return nil, err
177209
}
178-
t.conns[key] = append(t.conns[key], cc)
210+
t.addConn(key, cc)
179211
return cc, nil
180212
}
181213

182-
func (t *Transport) newClientConn(host, port, key string) (*clientConn, error) {
214+
func (t *Transport) dialClientConn(host, port, key string) (*clientConn, error) {
183215
cfg := &tls.Config{
184216
ServerName: host,
185217
NextProtos: []string{NextProtoTLS},
@@ -189,11 +221,15 @@ func (t *Transport) newClientConn(host, port, key string) (*clientConn, error) {
189221
if err != nil {
190222
return nil, err
191223
}
224+
return t.newClientConn(host, key, tconn)
225+
}
226+
227+
func (t *Transport) newClientConn(host, key string, tconn *tls.Conn) (*clientConn, error) {
192228
if err := tconn.Handshake(); err != nil {
193229
return nil, err
194230
}
195231
if !t.InsecureTLSDial {
196-
if err := tconn.VerifyHostname(cfg.ServerName); err != nil {
232+
if err := tconn.VerifyHostname(host); err != nil {
197233
return nil, err
198234
}
199235
}

0 commit comments

Comments
 (0)