diff --git a/pkg/http/client.go b/pkg/http/client.go index 7163349..d094f6b 100644 --- a/pkg/http/client.go +++ b/pkg/http/client.go @@ -11,7 +11,6 @@ import ( "net" "net/http" "net/url" - "strconv" "strings" "time" @@ -168,7 +167,7 @@ func (r *HTTPClient) Do(req *http.Request) (*http.Response, error) { attempt := 0 var origBody []byte - if req.Method == "POST" { + if req.Method == "POST" || req.Method == "PUT" || req.Method == "PATCH" { origBody, _ = io.ReadAll(req.Body) } @@ -179,8 +178,12 @@ func (r *HTTPClient) Do(req *http.Request) (*http.Response, error) { if resp != nil && resp.Body != nil { resp.Body.Close() } - r.replaceHostIfNeeded(req) // needed for ipv6 + + r.replaceWithIPv6Host(req) // needed for ipv6 + resp, err = r.client.Do(req) + + // http 4xx and 5xx errors if resp != nil && resp.StatusCode/100 >= 4 { body, _ := io.ReadAll(resp.Body) if body != nil { @@ -192,6 +195,7 @@ func (r *HTTPClient) Do(req *http.Request) (*http.Response, error) { } } } + incr := r.shouldRetry(resp, reqHasRangeHeader, err, r.cfg.GetRateLimitSleepSecs()) if incr > 0 { attempt += incr @@ -213,34 +217,30 @@ func (r *HTTPClient) Do(req *http.Request) (*http.Response, error) { return resp, err } -func (r *HTTPClient) replaceHostIfNeeded(req *http.Request) { - if strings.HasSuffix(req.Host, "download.real-debrid.cloud") || !r.supportIPv6 || !r.cfg.ShouldForceIPv6() { +func (r *HTTPClient) replaceWithIPv6Host(req *http.Request) { + // don't replace host if IPv6 is not supported or not forced + if !r.supportIPv6 || !r.cfg.ShouldForceIPv6() { return } - // get subdomain of req.Host - subdomain := strings.Split(req.Host, ".")[0] - // check if subdomain is numeric - _, err := strconv.Atoi(subdomain) - if err == nil { - // subdomain is numeric, replace it with .cloud - req.Host = strings.Replace(req.Host, ".com", ".cloud", 1) - req.URL.Host = req.Host + // this host should be replaced + if !strings.HasSuffix(req.Host, ".download.real-debrid.com") { + return } - // check if host is in the list of IPv6 hosts - found := false + + req.Host = strings.Replace(req.Host, ".com", ".cloud", 1) + req.URL.Host = req.Host + // check if this host is in the list of IPv6 hosts for _, h := range r.ipv6Hosts { if h == req.Host { - found = true - break + return } } - if !found && !r.CanFetchFirstByte(req.URL.String()) { - req.Host = r.ipv6Hosts[rand.Intn(len(r.ipv6Hosts))] - r.log.Debugf("Host %s is not a valid IPv6 host, assigning a random IPv6 host: %s", req.URL.Host, req.Host) - req.URL.Host = req.Host - } else { - r.ipv6Hosts = append(r.ipv6Hosts, req.Host) - } + + // if not then just assign a random IPv6 host + req.Host = r.ipv6Hosts[rand.Intn(len(r.ipv6Hosts))] + req.URL.Host = req.Host + r.log.Debugf("Host %s is not a valid IPv6 host, assigning a random IPv6 host: %s", req.URL.Host, req.Host) + // if !found && !r.CanFetchFirstByte(req.URL.String()) { } func (r *HTTPClient) proxyDialer(proxyURL *url.URL) (proxy.Dialer, error) { @@ -287,9 +287,19 @@ func (r *HTTPClient) shouldRetry(resp *http.Response, reqHasRangeHeader bool, er } if resp != nil { if resp.StatusCode == 429 { + // Too many requests: retry infinitely time.Sleep(time.Duration(rateLimitSleep) * time.Second) return 0 } + if resp.StatusCode/100 == 4 { + // other client errors: retry + return 1 + } + if resp.StatusCode/100 == 5 { + // server errors: don't retry + return -1 + } + // if the request has a Range header but the server doesn't respond with a Content-Range header if resp.StatusCode/100 == 2 && resp.Header.Get("Content-Range") == "" && reqHasRangeHeader { time.Sleep(10 * time.Millisecond) return 0