|
|
|
@ -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
|
|
|
|
|
}
|
|
|
|
|