mirror of
https://github.com/rclone/rclone.git
synced 2024-12-23 07:29:35 +01:00
Retry errors which indicate the connection closed prematurely.
See discussion in #442
This commit is contained in:
parent
5c2d8ffe33
commit
1752ee3c8b
@ -142,9 +142,6 @@ var retryErrorCodes = []int{
|
||||
// shouldRetry returns a boolean as to whether this resp and err
|
||||
// deserve to be retried. It returns the err as a convenience
|
||||
func shouldRetry(resp *http.Response, err error) (bool, error) {
|
||||
if err == io.EOF {
|
||||
return true, err
|
||||
}
|
||||
return fs.ShouldRetry(err) || fs.ShouldRetryHTTP(resp, retryErrorCodes), err
|
||||
}
|
||||
|
||||
|
9
fs/closed_conn.go
Normal file
9
fs/closed_conn.go
Normal file
@ -0,0 +1,9 @@
|
||||
// +build !windows
|
||||
|
||||
package fs
|
||||
|
||||
// isClosedConnErrorPlatform reports whether err is an error from use
|
||||
// of a closed network connection using platform specific error codes.
|
||||
func isClosedConnErrorPlatform(err error) bool {
|
||||
return false
|
||||
}
|
27
fs/closed_conn_win.go
Normal file
27
fs/closed_conn_win.go
Normal file
@ -0,0 +1,27 @@
|
||||
// +build windows
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// isClosedConnErrorPlatform reports whether err is an error from use
|
||||
// of a closed network connection using platform specific error codes.
|
||||
//
|
||||
// Code adapted from net/http
|
||||
func isClosedConnErrorPlatform(err error) bool {
|
||||
if oe, ok := err.(*net.OpError); ok && oe.Op == "read" {
|
||||
if se, ok := oe.Err.(*os.SyscallError); ok && se.Syscall == "wsarecv" {
|
||||
if errno, ok := se.Err.(syscall.Errno); ok {
|
||||
const WSAECONNABORTED syscall.Errno = 10053
|
||||
if errno == syscall.WSAECONNRESET || errno == WSAECONNABORTED {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
29
fs/error.go
29
fs/error.go
@ -4,8 +4,10 @@ package fs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Retry is an optional interface for error as to whether the
|
||||
@ -56,14 +58,39 @@ func RetryError(err error) error {
|
||||
return plainRetryError{err}
|
||||
}
|
||||
|
||||
// isClosedConnError reports whether err is an error from use of a closed
|
||||
// network connection.
|
||||
//
|
||||
// Code adapted from net/http
|
||||
func isClosedConnError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Note that this error isn't exported so we have to do a
|
||||
// string comparison :-(
|
||||
str := err.Error()
|
||||
if strings.Contains(str, "use of closed network connection") {
|
||||
return true
|
||||
}
|
||||
|
||||
return isClosedConnErrorPlatform(err)
|
||||
}
|
||||
|
||||
// ShouldRetry looks at an error and tries to work out if retrying the
|
||||
// operation that caused it would be a good idea. It returns true if
|
||||
// the error implements Timeout() or Temporary() and it returns true.
|
||||
// the error implements Timeout() or Temporary() or if the error
|
||||
// indicates a premature closing of the connection.
|
||||
func ShouldRetry(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Look for premature closing of connection
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF || isClosedConnError(err) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Unwrap url.Error
|
||||
if urlErr, ok := err.(*url.Error); ok {
|
||||
err = urlErr.Err
|
||||
|
Loading…
Reference in New Issue
Block a user