File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -33,11 +33,19 @@ func (l *Limiter) Stop() {
3333// alreadyLimits returns true if cd is already limited by this Limiter.
3434// This lets us help the user avoiding double-accounting bandwidth.
3535func (l * Limiter ) alreadyLimits (cd ContextDialer ) bool {
36+ seen := make (map [* Dialer ]struct {})
3637 for {
3738 if d , ok := cd .(* Dialer ); ok {
39+ if d == nil {
40+ return false
41+ }
3842 if d .Limiter == l {
3943 return true
4044 }
45+ if _ , ok := seen [d ]; ok {
46+ return false
47+ }
48+ seen [d ] = struct {}{}
4149 cd = d .ContextDialer
4250 } else {
4351 return false
Original file line number Diff line number Diff line change 44 "bytes"
55 "io"
66 "testing"
7+ "time"
78)
89
910func TestLimiter_Stop (t * testing.T ) {
@@ -62,3 +63,38 @@ func TestLimiter_Stop_flushesCount(t *testing.T) {
6263 t .Fatalf ("got %d want %d" , got , n )
6364 }
6465}
66+
67+ func TestLimiter_Wrap_cyclicDialerChain_doesNotHang (t * testing.T ) {
68+ l1 := NewLimiter ()
69+ defer l1 .Stop ()
70+ l2 := NewLimiter ()
71+ defer l2 .Stop ()
72+
73+ d := & Dialer {Limiter : l1 }
74+ d .ContextDialer = d
75+
76+ done := make (chan ContextDialer , 1 )
77+ go func () {
78+ done <- l2 .Wrap (d )
79+ }()
80+
81+ select {
82+ case wrapped := <- done :
83+ if wrapped == nil {
84+ t .Fatal ("expected wrapped dialer" )
85+ }
86+ case <- time .After (500 * time .Millisecond ):
87+ t .Fatal ("Wrap hung on cyclic dialer chain" )
88+ }
89+ }
90+
91+ func TestLimiter_alreadyLimits_typedNilDialer (t * testing.T ) {
92+ l := NewLimiter ()
93+ defer l .Stop ()
94+
95+ var d * Dialer
96+ var cd ContextDialer = d
97+ if l .alreadyLimits (cd ) {
98+ t .Fatal ("typed nil dialer should not be detected as already limited" )
99+ }
100+ }
You can’t perform that action at this time.
0 commit comments