-
Notifications
You must be signed in to change notification settings - Fork 245
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fixes #21071
- Loading branch information
Showing
13 changed files
with
312 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package network_utils | ||
|
||
import ( | ||
"context" | ||
"crypto/tls" | ||
"errors" | ||
"net" | ||
"net/http" | ||
"strings" | ||
) | ||
|
||
// IsConnectionError checks if the error is related to network issues. | ||
func IsConnectionError(err error) bool { | ||
if err == nil { | ||
return false | ||
} | ||
|
||
// Check for net.Error (timeout or other network errors) | ||
var netErr net.Error | ||
if errors.As(err, &netErr) { | ||
if netErr.Timeout() { | ||
return true | ||
} | ||
} | ||
|
||
// Check for DNS errors | ||
var dnsErr *net.DNSError | ||
if errors.As(err, &dnsErr) { | ||
return true | ||
} | ||
|
||
// Check for network operation errors (e.g., connection refused) | ||
var opErr *net.OpError | ||
if errors.As(err, &opErr) { | ||
return true | ||
} | ||
|
||
// Check for TLS errors | ||
var tlsRecordErr *tls.RecordHeaderError | ||
if errors.As(err, &tlsRecordErr) { | ||
return true | ||
} | ||
|
||
// FIXME: Check for TLS ECH Rejection Error (tls.ECHRejectionError is added in go 1.23) | ||
|
||
// Check for TLS Certificate Verification Error | ||
var certVerifyErr *tls.CertificateVerificationError | ||
if errors.As(err, &certVerifyErr) { | ||
return true | ||
} | ||
|
||
// Check for TLS Alert Error | ||
var alertErr tls.AlertError | ||
if errors.As(err, &alertErr) { | ||
return true | ||
} | ||
|
||
// Check if context deadline exceeded | ||
if errors.Is(err, context.DeadlineExceeded) { | ||
return true | ||
} | ||
|
||
// Check for specific HTTP server closed error | ||
if errors.Is(err, http.ErrServerClosed) { | ||
return true | ||
} | ||
|
||
// Common connection refused or timeout errors | ||
errMsg := strings.ToLower(err.Error()) | ||
if strings.Contains(errMsg, "i/o timeout") || | ||
strings.Contains(errMsg, "connection refused") || | ||
strings.Contains(errMsg, "network is unreachable") || | ||
strings.Contains(errMsg, "no such host") || | ||
strings.Contains(errMsg, "tls handshake timeout") { | ||
return true | ||
} | ||
|
||
return false | ||
} | ||
|
||
func IsRPSLimitError(err error) bool { | ||
if err == nil { | ||
return false | ||
} | ||
errMsg := strings.ToLower(err.Error()) | ||
if strings.Contains(errMsg, "backoff_seconds") || | ||
strings.Contains(errMsg, "has exceeded its throughput limit") || | ||
strings.Contains(errMsg, "request rate exceeded") { | ||
return true | ||
} | ||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
package network_utils | ||
|
||
import ( | ||
"context" | ||
"crypto/tls" | ||
"errors" | ||
"net" | ||
"net/http" | ||
"testing" | ||
) | ||
|
||
// TestIsConnectionError tests the isConnectionError function. | ||
func TestIsConnectionError(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
err error | ||
wantResult bool | ||
}{ | ||
{ | ||
name: "nil error", | ||
err: nil, | ||
wantResult: false, | ||
}, | ||
{ | ||
name: "net.Error timeout", | ||
err: &net.DNSError{IsTimeout: true}, | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "DNS error", | ||
err: &net.DNSError{}, | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "net.OpError", | ||
err: &net.OpError{}, | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "tls.RecordHeaderError", | ||
err: &tls.RecordHeaderError{}, | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "tls.CertificateVerificationError", | ||
err: &tls.CertificateVerificationError{}, | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "tls.AlertError", | ||
err: tls.AlertError(0), | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "context.DeadlineExceeded", | ||
err: context.DeadlineExceeded, | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "http.ErrServerClosed", | ||
err: http.ErrServerClosed, | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "i/o timeout error message", | ||
err: errors.New("i/o timeout"), | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "connection refused error message", | ||
err: errors.New("connection refused"), | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "network is unreachable error message", | ||
err: errors.New("network is unreachable"), | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "no such host error message", | ||
err: errors.New("no such host"), | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "tls handshake timeout error message", | ||
err: errors.New("tls handshake timeout"), | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "rps limit error 1", | ||
err: errors.New("backoff_seconds"), | ||
wantResult: false, | ||
}, | ||
{ | ||
name: "rps limit error 2", | ||
err: errors.New("has exceeded its throughput limit"), | ||
wantResult: false, | ||
}, | ||
{ | ||
name: "rps limit error 3", | ||
err: errors.New("request rate exceeded"), | ||
wantResult: false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got := IsConnectionError(tt.err) | ||
if got != tt.wantResult { | ||
t.Errorf("isConnectionError(%v) = %v; want %v", tt.err, got, tt.wantResult) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestIsRPSLimitError(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
err error | ||
wantResult bool | ||
}{ | ||
{ | ||
name: "Error contains 'backoff_seconds'", | ||
err: errors.New("Error: backoff_seconds: 30"), | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "Error contains 'has exceeded its throughput limit'", | ||
err: errors.New("Your application has exceeded its throughput limit."), | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "Error contains 'request rate exceeded'", | ||
err: errors.New("Request rate exceeded. Please try again later."), | ||
wantResult: true, | ||
}, | ||
{ | ||
name: "Error does not contain any matching phrases", | ||
err: errors.New("Some other error occurred."), | ||
wantResult: false, | ||
}, | ||
{ | ||
name: "Error is nil", | ||
err: nil, | ||
wantResult: false, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got := IsRPSLimitError(tt.err) | ||
if got != tt.wantResult { | ||
t.Errorf("IsRPSLimitError(%v) = %v; want %v", tt.err, got, tt.wantResult) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.