@@ -157,29 +157,61 @@ func filterOutClientConn(in []*clientConn, exclude *clientConn) []*clientConn {
157
157
return out
158
158
}
159
159
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 ) {
161
182
t .connMu .Lock ()
162
183
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
+ }
163
189
190
+ func (t * Transport ) getClientConn (host , port string ) (* clientConn , error ) {
164
191
key := net .JoinHostPort (host , port )
165
192
193
+ t .connMu .Lock ()
166
194
for _ , cc := range t .conns [key ] {
167
195
if cc .canTakeNewRequest () {
196
+ t .connMu .Unlock ()
168
197
return cc , nil
169
198
}
170
199
}
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 )
175
207
if err != nil {
176
208
return nil , err
177
209
}
178
- t .conns [ key ] = append ( t . conns [ key ] , cc )
210
+ t .addConn ( key , cc )
179
211
return cc , nil
180
212
}
181
213
182
- func (t * Transport ) newClientConn (host , port , key string ) (* clientConn , error ) {
214
+ func (t * Transport ) dialClientConn (host , port , key string ) (* clientConn , error ) {
183
215
cfg := & tls.Config {
184
216
ServerName : host ,
185
217
NextProtos : []string {NextProtoTLS },
@@ -189,11 +221,15 @@ func (t *Transport) newClientConn(host, port, key string) (*clientConn, error) {
189
221
if err != nil {
190
222
return nil , err
191
223
}
224
+ return t .newClientConn (host , key , tconn )
225
+ }
226
+
227
+ func (t * Transport ) newClientConn (host , key string , tconn * tls.Conn ) (* clientConn , error ) {
192
228
if err := tconn .Handshake (); err != nil {
193
229
return nil , err
194
230
}
195
231
if ! t .InsecureTLSDial {
196
- if err := tconn .VerifyHostname (cfg . ServerName ); err != nil {
232
+ if err := tconn .VerifyHostname (host ); err != nil {
197
233
return nil , err
198
234
}
199
235
}
0 commit comments