153 lines
4.6 KiB
Go
153 lines
4.6 KiB
Go
// Copyright 2025-present Gustavo "Guz" L. de Mello
|
|
// Copyright 2025-present The Lored.dev Contributors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package problem
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"errors"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
func NewInternalServerError(err error, opts ...Option) InternalServerError {
|
|
return InternalServerError{
|
|
RegisteredProblem: NewDetailed(http.StatusInternalServerError, err.Error(), opts...),
|
|
Errors: newErrorTree(err).Errors,
|
|
error: err,
|
|
}
|
|
}
|
|
|
|
type InternalServerError struct {
|
|
RegisteredProblem
|
|
Errors []ErrorTree `json:"errors" xml:"errors"`
|
|
|
|
error error `json:"-" xml:"-"`
|
|
}
|
|
|
|
var _ error = InternalServerError{}
|
|
|
|
func (p InternalServerError) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
p.Handler(p).ServeHTTP(w, r)
|
|
}
|
|
|
|
func (p InternalServerError) Error() string {
|
|
return p.error.Error()
|
|
}
|
|
|
|
func newErrorTree(err error) ErrorTree {
|
|
i := ErrorTree{Detail: err.Error(), Errors: []ErrorTree{}, error: err}
|
|
if us, ok := err.(interface{ Unwrap() []error }); ok {
|
|
for _, e := range us.Unwrap() {
|
|
i.Errors = append(i.Errors, newErrorTree(e))
|
|
}
|
|
} else if e := errors.Unwrap(err); e != nil {
|
|
i.Errors = append(i.Errors, newErrorTree(e))
|
|
}
|
|
return i
|
|
}
|
|
|
|
type ErrorTree struct {
|
|
Detail string `json:"detail" xml:"detail"`
|
|
Errors []ErrorTree `json:"errors" xml:"errors"`
|
|
|
|
XMLName xml.Name `json:"-" xml:"errors"`
|
|
error error `json:"-" xml:"-"`
|
|
}
|
|
|
|
var _ error = ErrorTree{}
|
|
|
|
func (i ErrorTree) Error() string {
|
|
return i.error.Error()
|
|
}
|
|
|
|
func NewNotImplemented[T time.Time | time.Duration](retryAfter T, opts ...Option) NotImplemented[T] {
|
|
p := NewStatus(http.StatusNotImplemented, opts...)
|
|
return NotImplemented[T]{RegisteredProblem: p, RetryAfter: RetryAfter[T]{time: retryAfter}}
|
|
}
|
|
|
|
type NotImplemented[T time.Time | time.Duration] struct {
|
|
RegisteredProblem
|
|
RetryAfter RetryAfter[T] `json:"retryAfter" xml:"retry-after"`
|
|
}
|
|
|
|
func (p NotImplemented[T]) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Retry-After", p.RetryAfter.String())
|
|
p.Handler(p).ServeHTTP(w, r)
|
|
}
|
|
|
|
func NewBadGateway(opts ...Option) BadGateway {
|
|
return BadGateway{NewStatus(http.StatusBadGateway, opts...)}
|
|
}
|
|
|
|
type BadGateway struct{ RegisteredProblem }
|
|
|
|
func NewServiceUnavailable[T time.Time | time.Duration](retryAfter T, opts ...Option) ServiceUnavailable[T] {
|
|
p := NewStatus(http.StatusNotImplemented, opts...)
|
|
return ServiceUnavailable[T]{RegisteredProblem: p, RetryAfter: RetryAfter[T]{time: retryAfter}}
|
|
}
|
|
|
|
type ServiceUnavailable[T time.Time | time.Duration] struct {
|
|
RegisteredProblem
|
|
RetryAfter RetryAfter[T] `json:"retryAfter" xml:"retry-after"`
|
|
}
|
|
|
|
func (p ServiceUnavailable[T]) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Retry-After", p.RetryAfter.String())
|
|
p.handler(p).ServeHTTP(w, r)
|
|
}
|
|
|
|
func NewGatewayTimeout(opts ...Option) GatewayTimeout {
|
|
return GatewayTimeout{NewStatus(http.StatusGatewayTimeout, opts...)}
|
|
}
|
|
|
|
type GatewayTimeout struct{ RegisteredProblem }
|
|
|
|
func NewHTTPVersionNotSupported(opts ...Option) HTTPVersionNotSupported {
|
|
return HTTPVersionNotSupported{NewStatus(http.StatusHTTPVersionNotSupported, opts...)}
|
|
}
|
|
|
|
type HTTPVersionNotSupported struct{ RegisteredProblem }
|
|
|
|
func NewVariantAlsoNegotiates(opts ...Option) VariantAlsoNegotiates {
|
|
return VariantAlsoNegotiates{NewStatus(http.StatusVariantAlsoNegotiates, opts...)}
|
|
}
|
|
|
|
type VariantAlsoNegotiates struct{ RegisteredProblem }
|
|
|
|
func NewInsufficientStorage(opts ...Option) InsufficientStorage {
|
|
return InsufficientStorage{NewStatus(http.StatusInsufficientStorage, opts...)}
|
|
}
|
|
|
|
type InsufficientStorage struct{ RegisteredProblem }
|
|
|
|
func NewLoopDetected(opts ...Option) LoopDetected {
|
|
return LoopDetected{NewStatus(http.StatusLoopDetected, opts...)}
|
|
}
|
|
|
|
type LoopDetected struct{ RegisteredProblem }
|
|
|
|
func NewNotExtended(opts ...Option) NotExtended {
|
|
return NotExtended{NewStatus(http.StatusNotExtended, opts...)}
|
|
}
|
|
|
|
type NotExtended struct{ RegisteredProblem }
|
|
|
|
func NewNetworkAuthenticationRequired(opts ...Option) NetworkAuthenticationRequired {
|
|
return NetworkAuthenticationRequired{NewStatus(http.StatusNetworkAuthenticationRequired, opts...)}
|
|
}
|
|
|
|
type NetworkAuthenticationRequired struct{ RegisteredProblem }
|