diff --git a/go.mod b/go.mod index 9f6fd63..4178f77 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/mojocn/base64Captcha v1.3.6 github.com/natefinch/lumberjack v2.0.0+incompatible github.com/quic-go/quic-go v0.42.0 + github.com/refraction-networking/utls v1.6.4 github.com/sirupsen/logrus v1.9.3 github.com/soheilhy/cmux v0.1.5 github.com/spf13/cobra v1.8.0 @@ -44,6 +45,7 @@ require ( go.etcd.io/etcd/client/v3 v3.5.13 golang.org/x/crypto v0.22.0 golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 + golang.org/x/net v0.24.0 golang.org/x/oauth2 v0.19.0 google.golang.org/grpc v1.63.2 google.golang.org/protobuf v1.33.0 @@ -64,6 +66,7 @@ require ( github.com/bytedance/sonic v1.11.3 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect + github.com/cloudflare/circl v1.3.7 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect @@ -100,6 +103,7 @@ require ( github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/klauspost/compress v1.17.4 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -128,7 +132,6 @@ require ( golang.org/x/arch v0.7.0 // indirect golang.org/x/image v0.15.0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.24.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/go.sum b/go.sum index cc9db3b..43c5456 100644 --- a/go.sum +++ b/go.sum @@ -47,6 +47,8 @@ github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0 github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= @@ -232,6 +234,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= @@ -327,6 +331,8 @@ github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM= github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= +github.com/refraction-networking/utls v1.6.4 h1:aeynTroaYn7y+mFtqv8D0bQ4bw0y9nJHneGxJ7lvRDM= +github.com/refraction-networking/utls v1.6.4/go.mod h1:2VL2xfiqgFAZtJKeUTlf+PSYFs3Eu7km0gCtXJ3m8zs= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= diff --git a/server/handlers/movie.go b/server/handlers/movie.go index ead16de..8f8c177 100644 --- a/server/handlers/movie.go +++ b/server/handlers/movie.go @@ -534,22 +534,20 @@ func proxyURL(ctx *gin.Context, u string, headers map[string]string) error { if req.Header.Get("User-Agent") == "" { req.Header.Set("User-Agent", utils.UA) } - resp, err := http.DefaultClient.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - ctx.Header("Accept-Ranges", resp.Header.Get("Accept-Ranges")) - ctx.Header("Cache-Control", resp.Header.Get("Cache-Control")) - ctx.Header("Content-Length", resp.Header.Get("Content-Length")) - ctx.Header("Content-Range", resp.Header.Get("Content-Range")) - ctx.Header("Content-Type", resp.Header.Get("Content-Type")) - ctx.Status(resp.StatusCode) - _, err = io.Copy(ctx.Writer, resp.Body) - if err != nil && err != io.EOF { - return err - } - return nil + return utils.HttpDo(req, func(resp *http.Response) error { + defer resp.Body.Close() + ctx.Status(resp.StatusCode) + ctx.Header("Accept-Ranges", resp.Header.Get("Accept-Ranges")) + ctx.Header("Cache-Control", resp.Header.Get("Cache-Control")) + ctx.Header("Content-Length", resp.Header.Get("Content-Length")) + ctx.Header("Content-Range", resp.Header.Get("Content-Range")) + ctx.Header("Content-Type", resp.Header.Get("Content-Type")) + _, err = io.Copy(ctx.Writer, resp.Body) + if err != nil && err != io.EOF { + return err + } + return nil + }) } type FormatErrNotSupportFileType string diff --git a/utils/utils.go b/utils/utils.go index 0453c4e..b5dadc9 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -1,6 +1,7 @@ package utils import ( + "context" "encoding/hex" "errors" "fmt" @@ -17,10 +18,12 @@ import ( "github.com/gin-gonic/gin" "github.com/google/uuid" + utls "github.com/refraction-networking/utls" "github.com/synctv-org/synctv/cmd/flags" "github.com/zijiren233/go-colorable" "github.com/zijiren233/stream" yamlcomment "github.com/zijiren233/yaml-comment" + "golang.org/x/net/http2" "gopkg.in/yaml.v3" ) @@ -415,3 +418,51 @@ func GetEnvFiles(root string) ([]string, error) { return envs, nil } + +func HttpDo(req *http.Request, handler func(*http.Response) error) error { + config := utls.Config{ServerName: req.URL.Hostname()} + dialConn, err := net.Dial("tcp", req.URL.Host) + if err != nil { + return err + } + uTlsConn := utls.UClient(dialConn, &config, utls.HelloChrome_Auto) + defer uTlsConn.Close() + err = uTlsConn.Handshake() + if err != nil { + return err + } + resp, err := httpGetOverConn(req, uTlsConn, uTlsConn.ConnectionState().NegotiatedProtocol) + if err != nil { + return err + } + return handler(resp) +} + +func httpGetOverConn(req *http.Request, conn net.Conn, alpn string) (*http.Response, error) { + switch alpn { + case "h2": + req.Proto = "HTTP/2.0" + req.ProtoMajor = 2 + req.ProtoMinor = 0 + + tr := http2.Transport{MaxHeaderListSize: 262144} + cConn, err := tr.NewClientConn(conn) + if err != nil { + return nil, err + } + return cConn.RoundTrip(req) + case "http/1.1", "": + req.Proto = "HTTP/1.1" + req.ProtoMajor = 1 + req.ProtoMinor = 1 + + tr := (http.DefaultTransport).(*http.Transport).Clone() + tr.MaxResponseHeaderBytes = 262144 + tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { + return conn, nil + } + return tr.RoundTrip(req) + default: + return nil, fmt.Errorf("unsupported ALPN: %v", alpn) + } +}