@@ -153,6 +153,8 @@ type ClientConn struct {
153
153
bw * bufio.Writer
154
154
br * bufio.Reader
155
155
fr * Framer
156
+ lastActive time.Time
157
+
156
158
// Settings from peer:
157
159
maxFrameSize uint32
158
160
maxConcurrentStreams uint32
@@ -170,6 +172,7 @@ type ClientConn struct {
170
172
type clientStream struct {
171
173
cc * ClientConn
172
174
req * http.Request
175
+ trace * clientTrace // or nil
173
176
ID uint32
174
177
resc chan resAndError
175
178
bufPipe pipe // buffered pipe with the flow-controlled response payload
@@ -288,6 +291,7 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
288
291
t .vlogf ("http2: Transport failed to get client conn for %s: %v" , addr , err )
289
292
return nil , err
290
293
}
294
+ traceGotConn (req , cc )
291
295
res , err := cc .RoundTrip (req )
292
296
if shouldRetryRequest (req , err ) {
293
297
continue
@@ -622,13 +626,15 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
622
626
}
623
627
624
628
cc .mu .Lock ()
629
+ cc .lastActive = time .Now ()
625
630
if cc .closed || ! cc .canTakeNewRequestLocked () {
626
631
cc .mu .Unlock ()
627
632
return nil , errClientConnUnusable
628
633
}
629
634
630
635
cs := cc .newStream ()
631
636
cs .req = req
637
+ cs .trace = requestTrace (req )
632
638
hasBody := body != nil
633
639
634
640
// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
@@ -659,6 +665,7 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
659
665
endStream := ! hasBody && ! hasTrailers
660
666
werr := cc .writeHeaders (cs .ID , endStream , hdrs )
661
667
cc .wmu .Unlock ()
668
+ traceWroteHeaders (cs .trace )
662
669
cc .mu .Unlock ()
663
670
664
671
if werr != nil {
@@ -668,6 +675,7 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
668
675
cc .forgetStreamID (cs .ID )
669
676
// Don't bother sending a RST_STREAM (our write already failed;
670
677
// no need to keep writing)
678
+ traceWroteRequest (cs .trace , werr )
671
679
return nil , werr
672
680
}
673
681
@@ -679,6 +687,7 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
679
687
bodyCopyErrc <- cs .writeRequestBody (body , req .Body )
680
688
}()
681
689
} else {
690
+ traceWroteRequest (cs .trace , nil )
682
691
if d := cc .responseHeaderTimeout (); d != 0 {
683
692
timer := time .NewTimer (d )
684
693
defer timer .Stop ()
@@ -743,6 +752,7 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
743
752
// forgetStreamID.
744
753
return nil , cs .resetErr
745
754
case err := <- bodyCopyErrc :
755
+ traceWroteRequest (cs .trace , err )
746
756
if err != nil {
747
757
return nil , err
748
758
}
@@ -1068,6 +1078,7 @@ func (cc *ClientConn) streamByID(id uint32, andRemove bool) *clientStream {
1068
1078
defer cc .mu .Unlock ()
1069
1079
cs := cc .streams [id ]
1070
1080
if andRemove && cs != nil && ! cc .closed {
1081
+ cc .lastActive = time .Now ()
1071
1082
delete (cc .streams , id )
1072
1083
close (cs .done )
1073
1084
}
@@ -1196,6 +1207,13 @@ func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error {
1196
1207
} else {
1197
1208
return rl .processTrailers (cs , f )
1198
1209
}
1210
+ if cs .trace != nil {
1211
+ // TODO(bradfitz): move first response byte earlier,
1212
+ // when we first read the 9 byte header, not waiting
1213
+ // until all the HEADERS+CONTINUATION frames have been
1214
+ // merged. This works for now.
1215
+ traceFirstResponseByte (cs .trace )
1216
+ }
1199
1217
1200
1218
res , err := rl .handleResponse (cs , f )
1201
1219
if err != nil {
@@ -1243,6 +1261,7 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
1243
1261
if statusCode == 100 {
1244
1262
// Just skip 100-continue response headers for now.
1245
1263
// TODO: golang.org/issue/13851 for doing it properly.
1264
+ // TODO: also call the httptrace.ClientTrace hooks
1246
1265
cs .pastHeaders = false // do it all again
1247
1266
return nil , nil
1248
1267
}
0 commit comments