github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/net/http2/transport_go117_test.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build go1.17 6 // +build go1.17 7 8 package http2 9 10 import ( 11 "context" 12 "errors" 13 14 "github.com/hxx258456/ccgo/gmhttp/httptest" 15 16 http "github.com/hxx258456/ccgo/gmhttp" 17 18 tls "github.com/hxx258456/ccgo/gmtls" 19 20 "testing" 21 ) 22 23 func TestTransportDialTLSContext(t *testing.T) { 24 blockCh := make(chan struct{}) 25 serverTLSConfigFunc := func(ts *httptest.Server) { 26 ts.Config.TLSConfig = &tls.Config{ 27 // Triggers the server to request the clients certificate 28 // during TLS handshake. 29 ClientAuth: tls.RequestClientCert, 30 } 31 } 32 ts := newServerTester(t, 33 func(w http.ResponseWriter, r *http.Request) {}, 34 optOnlyServer, 35 serverTLSConfigFunc, 36 ) 37 defer ts.Close() 38 tr := &Transport{ 39 TLSClientConfig: &tls.Config{ 40 GetClientCertificate: func(cri *tls.CertificateRequestInfo) (*tls.Certificate, error) { 41 // Tests that the context provided to `req` is 42 // passed into this function. 43 close(blockCh) 44 <-cri.Context().Done() 45 return nil, cri.Context().Err() 46 }, 47 InsecureSkipVerify: true, 48 }, 49 } 50 defer tr.CloseIdleConnections() 51 req, err := http.NewRequest(http.MethodGet, ts.ts.URL, nil) 52 if err != nil { 53 t.Fatal(err) 54 } 55 ctx, cancel := context.WithCancel(context.Background()) 56 defer cancel() 57 req = req.WithContext(ctx) 58 errCh := make(chan error) 59 go func() { 60 defer close(errCh) 61 res, err := tr.RoundTrip(req) 62 if err != nil { 63 errCh <- err 64 return 65 } 66 res.Body.Close() 67 }() 68 // Wait for GetClientCertificate handler to be called 69 <-blockCh 70 // Cancel the context 71 cancel() 72 // Expect the cancellation error here 73 err = <-errCh 74 if err == nil { 75 t.Fatal("cancelling context during client certificate fetch did not error as expected") 76 return 77 } 78 if !errors.Is(err, context.Canceled) { 79 t.Fatalf("unexpected error returned after cancellation: %v", err) 80 } 81 } 82 83 // TestDialRaceResumesDial tests that, given two concurrent requests 84 // to the same address, when the first Dial is interrupted because 85 // the first request's context is cancelled, the second request 86 // resumes the dial automatically. 87 func TestDialRaceResumesDial(t *testing.T) { 88 blockCh := make(chan struct{}) 89 serverTLSConfigFunc := func(ts *httptest.Server) { 90 ts.Config.TLSConfig = &tls.Config{ 91 // Triggers the server to request the clients certificate 92 // during TLS handshake. 93 ClientAuth: tls.RequestClientCert, 94 } 95 } 96 ts := newServerTester(t, 97 func(w http.ResponseWriter, r *http.Request) {}, 98 optOnlyServer, 99 serverTLSConfigFunc, 100 ) 101 defer ts.Close() 102 tr := &Transport{ 103 TLSClientConfig: &tls.Config{ 104 GetClientCertificate: func(cri *tls.CertificateRequestInfo) (*tls.Certificate, error) { 105 select { 106 case <-blockCh: 107 // If we already errored, return without error. 108 return &tls.Certificate{}, nil 109 default: 110 } 111 close(blockCh) 112 <-cri.Context().Done() 113 return nil, cri.Context().Err() 114 }, 115 InsecureSkipVerify: true, 116 }, 117 } 118 defer tr.CloseIdleConnections() 119 req, err := http.NewRequest(http.MethodGet, ts.ts.URL, nil) 120 if err != nil { 121 t.Fatal(err) 122 } 123 // Create two requests with independent cancellation. 124 ctx1, cancel1 := context.WithCancel(context.Background()) 125 defer cancel1() 126 req1 := req.WithContext(ctx1) 127 ctx2, cancel2 := context.WithCancel(context.Background()) 128 defer cancel2() 129 req2 := req.WithContext(ctx2) 130 errCh := make(chan error) 131 go func() { 132 res, err := tr.RoundTrip(req1) 133 if err != nil { 134 errCh <- err 135 return 136 } 137 res.Body.Close() 138 }() 139 successCh := make(chan struct{}) 140 go func() { 141 // Don't start request until first request 142 // has initiated the handshake. 143 <-blockCh 144 res, err := tr.RoundTrip(req2) 145 if err != nil { 146 errCh <- err 147 return 148 } 149 res.Body.Close() 150 // Close successCh to indicate that the second request 151 // made it to the server successfully. 152 close(successCh) 153 }() 154 // Wait for GetClientCertificate handler to be called 155 <-blockCh 156 // Cancel the context first 157 cancel1() 158 // Expect the cancellation error here 159 err = <-errCh 160 if err == nil { 161 t.Fatal("cancelling context during client certificate fetch did not error as expected") 162 return 163 } 164 if !errors.Is(err, context.Canceled) { 165 t.Fatalf("unexpected error returned after cancellation: %v", err) 166 } 167 select { 168 case err := <-errCh: 169 t.Fatalf("unexpected second error: %v", err) 170 case <-successCh: 171 } 172 }