/* * * Copyright 2017 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */package transportimport ()const proxyAuthHeaderKey = "Proxy-Authorization"// To read a response from a net.Conn, http.ReadResponse() takes a bufio.Reader.// It's possible that this reader reads more than what's need for the response// and stores those bytes in the buffer. bufConn wraps the original net.Conn// and the bufio.Reader to make sure we don't lose the bytes in the buffer.type bufConn struct {net.Conn r io.Reader}func ( *bufConn) ( []byte) (int, error) {return .r.Read()}func basicAuth(, string) string { := + ":" + returnbase64.StdEncoding.EncodeToString([]byte())}func doHTTPConnectHandshake( context.Context, net.Conn, string, proxyattributes.Options) ( net.Conn, error) {deferfunc() {if != nil { .Close() } }() := &http.Request{Method: http.MethodConnect,URL: &url.URL{Host: .ConnectAddr},Header: map[string][]string{"User-Agent": {}}, }if := .User; != nil { := .Username() , := .Password() .Header.Add(proxyAuthHeaderKey, "Basic "+basicAuth(, )) }if := sendHTTPRequest(, , ); != nil {returnnil, fmt.Errorf("failed to write the HTTP request: %v", ) } := bufio.NewReader() , := http.ReadResponse(, )if != nil {returnnil, fmt.Errorf("reading server HTTP response: %v", ) }defer .Body.Close()if .StatusCode != http.StatusOK { , := httputil.DumpResponse(, true)if != nil {returnnil, fmt.Errorf("failed to do connect handshake, status code: %s", .Status) }returnnil, fmt.Errorf("failed to do connect handshake, response: %q", ) }// The buffer could contain extra bytes from the target server, so we can't // discard it. However, in many cases where the server waits for the client // to send the first message (e.g. when TLS is being used), the buffer will // be empty, so we can avoid the overhead of reading through this buffer.if .Buffered() != 0 {return &bufConn{Conn: , r: }, nil }return , nil}// proxyDial establishes a TCP connection to the specified address and performs an HTTP CONNECT handshake.func proxyDial( context.Context, resolver.Address, string, proxyattributes.Options) (net.Conn, error) { , := internal.NetDialerWithTCPKeepalive().DialContext(, "tcp", .Addr)if != nil {returnnil, }returndoHTTPConnectHandshake(, , , )}func sendHTTPRequest( context.Context, *http.Request, net.Conn) error { = .WithContext()if := .Write(); != nil {returnfmt.Errorf("failed to write the HTTP request: %v", ) }returnnil}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.