|
|
|
@ -12,15 +12,17 @@ import (
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type HttpReadSeeker struct {
|
|
|
|
|
offset int64
|
|
|
|
|
url string
|
|
|
|
|
contentLength int64
|
|
|
|
|
method string
|
|
|
|
|
body io.Reader
|
|
|
|
|
client *http.Client
|
|
|
|
|
headers map[string]string
|
|
|
|
|
ctx context.Context
|
|
|
|
|
allowedContentTypes []string
|
|
|
|
|
offset int64
|
|
|
|
|
url string
|
|
|
|
|
contentLength int64
|
|
|
|
|
method string
|
|
|
|
|
body io.Reader
|
|
|
|
|
client *http.Client
|
|
|
|
|
headers map[string]string
|
|
|
|
|
ctx context.Context
|
|
|
|
|
allowedContentTypes []string
|
|
|
|
|
allowedStatusCodes []int
|
|
|
|
|
notAllowedStatusCodes []int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type HttpReadSeekerConf func(h *HttpReadSeeker)
|
|
|
|
@ -90,6 +92,18 @@ func AllowedContentTypes(types ...string) HttpReadSeekerConf {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func AllowedStatusCodes(codes ...int) HttpReadSeekerConf {
|
|
|
|
|
return func(h *HttpReadSeeker) {
|
|
|
|
|
h.allowedStatusCodes = codes
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NotAllowedStatusCodes(codes ...int) HttpReadSeekerConf {
|
|
|
|
|
return func(h *HttpReadSeeker) {
|
|
|
|
|
h.notAllowedStatusCodes = codes
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewHttpReadSeeker(url string, conf ...HttpReadSeekerConf) *HttpReadSeeker {
|
|
|
|
|
rs := &HttpReadSeeker{
|
|
|
|
|
offset: 0,
|
|
|
|
@ -121,6 +135,9 @@ func (h *HttpReadSeeker) fix() *HttpReadSeeker {
|
|
|
|
|
if h.client == nil {
|
|
|
|
|
h.client = http.DefaultClient
|
|
|
|
|
}
|
|
|
|
|
if len(h.notAllowedStatusCodes) == 0 {
|
|
|
|
|
h.notAllowedStatusCodes = []int{http.StatusNotFound}
|
|
|
|
|
}
|
|
|
|
|
return h
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -138,6 +155,10 @@ func (h *HttpReadSeeker) Read(p []byte) (n int, err error) {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
if err := h.checkStatusCode(resp.StatusCode); err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
if err := h.checkContentType(resp.Header.Get("Content-Type")); err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
@ -148,11 +169,24 @@ func (h *HttpReadSeeker) Read(p []byte) (n int, err error) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (h *HttpReadSeeker) checkContentType(ct string) error {
|
|
|
|
|
if ct == "" {
|
|
|
|
|
return errors.New("content type is empty")
|
|
|
|
|
if len(h.allowedContentTypes) != 0 {
|
|
|
|
|
if ct == "" || slices.Index(h.allowedContentTypes, ct) == -1 {
|
|
|
|
|
return fmt.Errorf("content type `%s` not allowed", ct)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if len(h.allowedContentTypes) != 0 && slices.Index(h.allowedContentTypes, ct) == -1 {
|
|
|
|
|
return fmt.Errorf("content type `%s` not allowed", ct)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (h *HttpReadSeeker) checkStatusCode(code int) error {
|
|
|
|
|
if len(h.allowedStatusCodes) != 0 {
|
|
|
|
|
if slices.Index(h.allowedStatusCodes, code) == -1 {
|
|
|
|
|
return fmt.Errorf("status code `%d` not allowed", code)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if len(h.notAllowedStatusCodes) != 0 {
|
|
|
|
|
if slices.Index(h.notAllowedStatusCodes, code) != -1 {
|
|
|
|
|
return fmt.Errorf("status code `%d` not allowed", code)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
@ -177,6 +211,10 @@ func (h *HttpReadSeeker) Seek(offset int64, whence int) (int64, error) {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
if err := h.checkStatusCode(resp.StatusCode); err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
if err := h.checkContentType(resp.Header.Get("Content-Type")); err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|