github.com/yaling888/clash@v1.53.0/listener/http/upgrade.go (about) 1 package http 2 3 import ( 4 "net" 5 "net/http" 6 "strings" 7 "time" 8 9 "github.com/yaling888/clash/adapter/inbound" 10 N "github.com/yaling888/clash/common/net" 11 C "github.com/yaling888/clash/constant" 12 "github.com/yaling888/clash/transport/socks5" 13 ) 14 15 func isUpgradeRequest(req *http.Request) bool { 16 for _, header := range req.Header["Connection"] { 17 for _, elm := range strings.Split(header, ",") { 18 if strings.EqualFold(strings.TrimSpace(elm), "Upgrade") { 19 return true 20 } 21 } 22 } 23 24 return false 25 } 26 27 func HandleUpgrade(localConn net.Conn, serverConn *N.BufferedConn, request *http.Request, in chan<- C.ConnContext) (resp *http.Response) { 28 removeProxyHeaders(request.Header) 29 RemoveExtraHTTPHostPort(request) 30 31 if serverConn == nil { 32 address := request.Host 33 if _, _, err := net.SplitHostPort(address); err != nil { 34 port := "80" 35 if request.TLS != nil { 36 port = "443" 37 } 38 address = net.JoinHostPort(address, port) 39 } 40 41 dstAddr := socks5.ParseAddr(address) 42 if dstAddr == nil { 43 return 44 } 45 46 left, right := net.Pipe() 47 48 in <- inbound.NewHTTP(dstAddr, localConn.RemoteAddr(), localConn.LocalAddr(), right) 49 50 serverConn = N.NewBufferedConn(left) 51 52 defer func() { 53 _ = serverConn.Close() 54 }() 55 } 56 57 err := request.Write(serverConn) 58 if err != nil { 59 _ = localConn.Close() 60 return 61 } 62 63 resp, err = http.ReadResponse(serverConn.Reader(), request) 64 if err != nil { 65 _ = localConn.Close() 66 return 67 } 68 69 if resp.StatusCode == http.StatusSwitchingProtocols { 70 removeProxyHeaders(resp.Header) 71 72 err = localConn.SetReadDeadline(time.Time{}) // set to not time out 73 if err != nil { 74 return 75 } 76 77 err = resp.Write(localConn) 78 if err != nil { 79 return 80 } 81 82 N.Relay(serverConn, localConn) // blocking here 83 _ = localConn.Close() 84 resp = nil 85 } 86 return 87 }