github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/internal/transport/proxy_test.go (about) 1 //go:build !race 2 // +build !race 3 4 /* 5 * 6 * Copyright 2017 gRPC authors. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 */ 21 22 package transport 23 24 import ( 25 "bufio" 26 "context" 27 "encoding/base64" 28 "fmt" 29 "io" 30 "net" 31 "net/url" 32 "testing" 33 "time" 34 35 http "github.com/hxx258456/ccgo/gmhttp" 36 ) 37 38 const ( 39 envTestAddr = "1.2.3.4:8080" 40 envProxyAddr = "2.3.4.5:7687" 41 ) 42 43 // overwriteAndRestore overwrite function httpProxyFromEnvironment and 44 // returns a function to restore the default values. 45 func overwrite(hpfe func(req *http.Request) (*url.URL, error)) func() { 46 backHPFE := httpProxyFromEnvironment 47 httpProxyFromEnvironment = hpfe 48 return func() { 49 httpProxyFromEnvironment = backHPFE 50 } 51 } 52 53 type proxyServer struct { 54 t *testing.T 55 lis net.Listener 56 in net.Conn 57 out net.Conn 58 59 requestCheck func(*http.Request) error 60 } 61 62 func (p *proxyServer) run() { 63 in, err := p.lis.Accept() 64 if err != nil { 65 return 66 } 67 p.in = in 68 69 req, err := http.ReadRequest(bufio.NewReader(in)) 70 if err != nil { 71 p.t.Errorf("failed to read CONNECT req: %v", err) 72 return 73 } 74 if err := p.requestCheck(req); err != nil { 75 resp := http.Response{StatusCode: http.StatusMethodNotAllowed} 76 resp.Write(p.in) 77 p.in.Close() 78 p.t.Errorf("get wrong CONNECT req: %+v, error: %v", req, err) 79 return 80 } 81 82 out, err := net.Dial("tcp", req.URL.Host) 83 if err != nil { 84 p.t.Errorf("failed to dial to server: %v", err) 85 return 86 } 87 resp := http.Response{StatusCode: http.StatusOK, Proto: "HTTP/1.0"} 88 resp.Write(p.in) 89 p.out = out 90 go io.Copy(p.in, p.out) 91 go io.Copy(p.out, p.in) 92 } 93 94 func (p *proxyServer) stop() { 95 p.lis.Close() 96 if p.in != nil { 97 p.in.Close() 98 } 99 if p.out != nil { 100 p.out.Close() 101 } 102 } 103 104 func testHTTPConnect(t *testing.T, proxyURLModify func(*url.URL) *url.URL, proxyReqCheck func(*http.Request) error) { 105 plis, err := net.Listen("tcp", "localhost:0") 106 if err != nil { 107 t.Fatalf("failed to listen: %v", err) 108 } 109 p := &proxyServer{ 110 t: t, 111 lis: plis, 112 requestCheck: proxyReqCheck, 113 } 114 go p.run() 115 defer p.stop() 116 117 blis, err := net.Listen("tcp", "localhost:0") 118 if err != nil { 119 t.Fatalf("failed to listen: %v", err) 120 } 121 122 msg := []byte{4, 3, 5, 2} 123 recvBuf := make([]byte, len(msg)) 124 done := make(chan error, 1) 125 go func() { 126 in, err := blis.Accept() 127 if err != nil { 128 done <- err 129 return 130 } 131 defer in.Close() 132 in.Read(recvBuf) 133 done <- nil 134 }() 135 136 // Overwrite the function in the test and restore them in defer. 137 hpfe := func(req *http.Request) (*url.URL, error) { 138 return proxyURLModify(&url.URL{Host: plis.Addr().String()}), nil 139 } 140 defer overwrite(hpfe)() 141 142 // Dial to proxy server. 143 ctx, cancel := context.WithTimeout(context.Background(), time.Second) 144 defer cancel() 145 c, err := proxyDial(ctx, blis.Addr().String(), "test") 146 if err != nil { 147 t.Fatalf("http connect Dial failed: %v", err) 148 } 149 defer c.Close() 150 151 // Send msg on the connection. 152 c.Write(msg) 153 if err := <-done; err != nil { 154 t.Fatalf("failed to accept: %v", err) 155 } 156 157 // Check received msg. 158 if string(recvBuf) != string(msg) { 159 t.Fatalf("received msg: %v, want %v", recvBuf, msg) 160 } 161 } 162 163 func (s) TestHTTPConnect(t *testing.T) { 164 testHTTPConnect(t, 165 func(in *url.URL) *url.URL { 166 return in 167 }, 168 func(req *http.Request) error { 169 if req.Method != http.MethodConnect { 170 return fmt.Errorf("unexpected Method %q, want %q", req.Method, http.MethodConnect) 171 } 172 return nil 173 }, 174 ) 175 } 176 177 func (s) TestHTTPConnectBasicAuth(t *testing.T) { 178 const ( 179 user = "notAUser" 180 password = "notAPassword" 181 ) 182 testHTTPConnect(t, 183 func(in *url.URL) *url.URL { 184 in.User = url.UserPassword(user, password) 185 return in 186 }, 187 func(req *http.Request) error { 188 if req.Method != http.MethodConnect { 189 return fmt.Errorf("unexpected Method %q, want %q", req.Method, http.MethodConnect) 190 } 191 wantProxyAuthStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(user+":"+password)) 192 if got := req.Header.Get(proxyAuthHeaderKey); got != wantProxyAuthStr { 193 gotDecoded, _ := base64.StdEncoding.DecodeString(got) 194 wantDecoded, _ := base64.StdEncoding.DecodeString(wantProxyAuthStr) 195 return fmt.Errorf("unexpected auth %q (%q), want %q (%q)", got, gotDecoded, wantProxyAuthStr, wantDecoded) 196 } 197 return nil 198 }, 199 ) 200 } 201 202 func (s) TestMapAddressEnv(t *testing.T) { 203 // Overwrite the function in the test and restore them in defer. 204 hpfe := func(req *http.Request) (*url.URL, error) { 205 if req.URL.Host == envTestAddr { 206 return &url.URL{ 207 Scheme: "https", 208 Host: envProxyAddr, 209 }, nil 210 } 211 return nil, nil 212 } 213 defer overwrite(hpfe)() 214 215 // envTestAddr should be handled by ProxyFromEnvironment. 216 got, err := mapAddress(envTestAddr) 217 if err != nil { 218 t.Error(err) 219 } 220 if got.Host != envProxyAddr { 221 t.Errorf("want %v, got %v", envProxyAddr, got) 222 } 223 }