diff --git a/internal/playback/service.go b/internal/playback/service.go index a16b45b..d24c948 100644 --- a/internal/playback/service.go +++ b/internal/playback/service.go @@ -32,7 +32,7 @@ func NewPlaybackService(repo domain.PlaybackRepository, providers []domain.Provi jikan: jikan, episodes: episodes, auditSvc: auditSvc, - httpClient: &http.Client{Timeout: 10 * time.Second}, + httpClient: netutil.NewClient(), proxyTokenKey: string(proxyTokenKey), proxyTokens: newProxyTokenStore(), } diff --git a/pkg/net/proxytransport.go b/pkg/net/proxytransport.go index d1bfa2f..409294c 100644 --- a/pkg/net/proxytransport.go +++ b/pkg/net/proxytransport.go @@ -1,8 +1,11 @@ package netutil import ( + "context" + "errors" "net" "net/http" + "syscall" "time" ) @@ -16,10 +19,28 @@ func newTransport(dialTimeout, tlsTimeout, headerTimeout time.Duration) *http.Tr TLSHandshakeTimeout: tlsTimeout, ResponseHeaderTimeout: headerTimeout, ExpectContinueTimeout: 1 * time.Second, - DialContext: dialer.DialContext, + DialContext: dialWithIPv4Fallback(dialer), } } +func dialWithIPv4Fallback(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) { + return func(ctx context.Context, network string, address string) (net.Conn, error) { + conn, err := dialer.DialContext(ctx, network, address) + if err == nil { + return conn, nil + } + if network != "tcp" || !isUnreachableNetwork(err) { + return nil, err + } + + return dialer.DialContext(ctx, "tcp4", address) + } +} + +func isUnreachableNetwork(err error) bool { + return errors.Is(err, syscall.ENETUNREACH) || errors.Is(err, syscall.EHOSTUNREACH) +} + func NewClient() *http.Client { return &http.Client{ Transport: newTransport(10*time.Second, 10*time.Second, 30*time.Second),