package httprange
import (
)
const (
httpHeaderIfMatch = "If-Match"
httpHeaderIfUnmodifiedSince = "If-Unmodified-Since"
)
type HTTPValidatorBuilder interface {
Build(context.Context, HTTPMetadataProvider, httpclient.Client) (httpclient.Client, error)
}
type HTTPStrongValidatorBuilder struct {
UseLastModified bool
}
func ( *HTTPStrongValidatorBuilder) ( context.Context, HTTPMetadataProvider, httpclient.Client) (httpclient.Client, error) {
switch := .Provide(); {
case .ETag != "" && !strings.HasPrefix(.ETag, weakETagPrefix):
return &HTTPStrongValidator{
Client: ,
Precondition: http.Header{
httpHeaderIfMatch: {.ETag},
},
ETag: .ETag,
}, nil
case .UseLastModified && !.LastModified.IsZero() && .Date.After(.LastModified):
:= .LastModified.UTC().Format(http.TimeFormat)
return &HTTPStrongValidator{
Client: ,
Precondition: http.Header{
httpHeaderIfUnmodifiedSince: {},
},
LastModified: .LastModified,
}, nil
default:
return nil, errNoApplicableValidator
}
}
type HTTPStrongValidator struct {
Client httpclient.Client
Precondition http.Header
ETag string
LastModified time.Time
}
func ( *HTTPStrongValidator) ( *http.Request) (*http.Response, error) {
.Header = setHeader(.Header, .Precondition)
, := .Client.Do()
if != nil {
return nil,
}
if := .checkValidator(); != nil {
_ = .Body.Close()
return nil, &HTTPResponseError{
Response: ,
cause: ,
}
}
return , nil
}
func ( *HTTPStrongValidator) ( *http.Response) error {
switch {
case .ETag != "":
, := parseETagOrZero(.Header)
if != nil {
return
}
if .ETag != {
return fmt.Errorf(
"httprange: ETag validator changed from %q to %q",
.ETag, ,
)
}
case !.LastModified.IsZero():
:= .Header.Get(httpHeaderLastModified)
, := http.ParseTime()
if != nil {
return
}
if !.Equal(.LastModified) {
return fmt.Errorf(
"httprange: Last-Modified validator changed from %q to %q",
.LastModified, ,
)
}
}
return nil
}