From f406eb8ec59842fbdb04a6d5deed3eb546d3ad93 Mon Sep 17 00:00:00 2001 From: Abhinav Prakash Date: Sat, 22 Feb 2025 12:29:51 +0530 Subject: [PATCH] fix::> New ErrorContentBlocked struct added Signed-off-by: Abhinav Prakash --- gateway/errors.go | 48 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/gateway/errors.go b/gateway/errors.go index 5ea15ff18..5efc1951d 100644 --- a/gateway/errors.go +++ b/gateway/errors.go @@ -36,6 +36,12 @@ type ErrorRetryAfter struct { RetryAfter time.Duration } +// ErrorContentBlocked represents an error when content is blocked due to filtering +type ErrorContentBlocked struct { + Err error + StatusCode int +} + func NewErrorRetryAfter(err error, retryAfter time.Duration) *ErrorRetryAfter { if err == nil { err = ErrServiceUnavailable @@ -49,6 +55,18 @@ func NewErrorRetryAfter(err error, retryAfter time.Duration) *ErrorRetryAfter { } } +func NewErrorContentBlocked(err error, statusCode int) *ErrorContentBlocked { + // Will default to Error:451 if no status code is provided + if statusCode != http.StatusGone && statusCode != http.StatusUnavailableForLegalReasons { + statusCode = http.StatusUnavailableForLegalReasons // 451 by default + } + + return &ErrorContentBlocked{ + Err: err, + StatusCode: statusCode, + } +} + func (e *ErrorRetryAfter) Error() string { var text string if e.Err != nil { @@ -73,6 +91,26 @@ func (e *ErrorRetryAfter) Is(err error) bool { } } +func (e *ErrorContentBlocked) Error() string { + if e.Err != nil { + return fmt.Sprintf("content blocked: %s", e.Err.Error()) + } + return "content blocked and cannot be provided" +} + +func (e *ErrorContentBlocked) Unwrap() error { + return e.Err +} + +func (e *ErrorContentBlocked) Is(err error) bool { + switch err.(type) { + case *ErrorContentBlocked: + return true + default: + return false + } +} + // RetryAfterHeader returns the [Retry-After] header value as a string, representing the number // of seconds to wait before making a new request, rounded to the nearest second. // This function follows the [Retry-After] header definition as specified in RFC 9110. @@ -187,7 +225,12 @@ func webError(w http.ResponseWriter, r *http.Request, c *Config, err error, defa case errors.Is(err, &cid.ErrInvalidCid{}): code = http.StatusBadRequest case isErrContentBlocked(err): - code = http.StatusGone + var blocked *ErrorContentBlocked + if errors.As(err, &blocked) { + code = blocked.StatusCode + } else { + code = http.StatusUnavailableForLegalReasons // Default to 451 + } case isErrNotFound(err): code = http.StatusNotFound case errors.Is(err, context.DeadlineExceeded): @@ -255,5 +298,6 @@ func isErrNotFound(err error) bool { func isErrContentBlocked(err error) bool { // TODO: we match error message to avoid pulling nopfs as a dependency // Ref. https://github.com/ipfs-shipyard/nopfs/blob/cde3b5ba964c13e977f4a95f3bd8ca7d7710fbda/status.go#L87-L89 - return strings.Contains(err.Error(), "blocked and cannot be provided") + var blocked *ErrorContentBlocked + return errors.As(err, &blocked) }