diff --git a/proxy/connection.go b/proxy/connection.go index 0561ac4..34e9c40 100644 --- a/proxy/connection.go +++ b/proxy/connection.go @@ -198,61 +198,6 @@ func (connCtx *ConnContext) initServerTcpConn(req *http.Request) error { return nil } -// connect proxy when set https_proxy env -// ref: http/transport.go dialConn func -func getProxyConn(proxyUrl *url.URL, address string) (net.Conn, error) { - conn, err := (&net.Dialer{}).DialContext(context.Background(), "tcp", proxyUrl.Host) - if err != nil { - return nil, err - } - connectReq := &http.Request{ - Method: "CONNECT", - URL: &url.URL{Opaque: address}, - Host: address, - Header: http.Header{}, - } - if proxyUrl.User != nil { - connectReq.Header.Set("Proxy-Authorization", "Basic"+base64.StdEncoding.EncodeToString([]byte(proxyUrl.User.String()))) - } - connectCtx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) - defer cancel() - didReadResponse := make(chan struct{}) // closed after CONNECT write+read is done or fails - var resp *http.Response - // Write the CONNECT request & read the response. - go func() { - defer close(didReadResponse) - err = connectReq.Write(conn) - if err != nil { - return - } - // Okay to use and discard buffered reader here, because - // TLS server will not speak until spoken to. - br := bufio.NewReader(conn) - resp, err = http.ReadResponse(br, connectReq) - }() - select { - case <-connectCtx.Done(): - conn.Close() - <-didReadResponse - return nil, connectCtx.Err() - case <-didReadResponse: - // resp or err now set - } - if err != nil { - conn.Close() - return nil, err - } - if resp.StatusCode != 200 { - _, text, ok := strings.Cut(resp.Status, " ") - conn.Close() - if !ok { - return nil, errors.New("unknown status code") - } - return nil, errors.New(text) - } - return conn, nil -} - func (connCtx *ConnContext) initHttpsServerConn() { if !connCtx.ClientConn.Tls { return @@ -393,3 +338,58 @@ func (c *wrapServerConn) Close() error { return c.closeErr } + +// connect proxy when set https_proxy env +// ref: http/transport.go dialConn func +func getProxyConn(proxyUrl *url.URL, address string) (net.Conn, error) { + conn, err := (&net.Dialer{}).DialContext(context.Background(), "tcp", proxyUrl.Host) + if err != nil { + return nil, err + } + connectReq := &http.Request{ + Method: "CONNECT", + URL: &url.URL{Opaque: address}, + Host: address, + Header: http.Header{}, + } + if proxyUrl.User != nil { + connectReq.Header.Set("Proxy-Authorization", "Basic"+base64.StdEncoding.EncodeToString([]byte(proxyUrl.User.String()))) + } + connectCtx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) + defer cancel() + didReadResponse := make(chan struct{}) // closed after CONNECT write+read is done or fails + var resp *http.Response + // Write the CONNECT request & read the response. + go func() { + defer close(didReadResponse) + err = connectReq.Write(conn) + if err != nil { + return + } + // Okay to use and discard buffered reader here, because + // TLS server will not speak until spoken to. + br := bufio.NewReader(conn) + resp, err = http.ReadResponse(br, connectReq) + }() + select { + case <-connectCtx.Done(): + conn.Close() + <-didReadResponse + return nil, connectCtx.Err() + case <-didReadResponse: + // resp or err now set + } + if err != nil { + conn.Close() + return nil, err + } + if resp.StatusCode != 200 { + _, text, ok := strings.Cut(resp.Status, " ") + conn.Close() + if !ok { + return nil, errors.New("unknown status code") + } + return nil, errors.New(text) + } + return conn, nil +}