| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- package storage
- import (
- "context"
- "io"
- "net/http"
- "strconv"
- "strings"
- "github.com/imgproxy/imgproxy/v3/httpheaders"
- )
- // Reader represents a generic storage interface, which can read
- // objects from a storage backend.
- type Reader interface {
- // GetObject retrieves an object from the storage and returns
- // ObjectReader with the result.
- GetObject(
- ctx context.Context,
- reqHeader http.Header,
- bucket, key, query string,
- ) (*ObjectReader, error)
- }
- // ObjectReader represents a generic reader for a storage object.
- // It can be in any state: success, error, not found, etc.
- // It can be converted to HTTP response or used as-is.
- type ObjectReader struct {
- Status int // HTTP status code
- Headers http.Header // Response headers harvested from the engine response
- Body io.ReadCloser // Response body reader
- contentLength int64
- }
- // NewObjectOK creates a new Reader with a 200 OK status.
- func NewObjectOK(headers http.Header, body io.ReadCloser) *ObjectReader {
- return &ObjectReader{
- Status: http.StatusOK,
- Headers: headers,
- Body: body,
- contentLength: -1, // is set in Response()
- }
- }
- // NewObjectPartialContent creates a new Reader with a 206 Partial Content status.
- func NewObjectPartialContent(headers http.Header, body io.ReadCloser) *ObjectReader {
- return &ObjectReader{
- Status: http.StatusPartialContent,
- Headers: headers,
- Body: body,
- contentLength: -1, // is set in Response()
- }
- }
- // NewObjectNotFound creates a new Reader with a 404 Not Found status.
- func NewObjectNotFound(message string) *ObjectReader {
- return NewObjectError(http.StatusNotFound, message)
- }
- // NewObjectError creates a new Reader with a custom status code
- func NewObjectError(statusCode int, message string) *ObjectReader {
- return &ObjectReader{
- Status: statusCode,
- Body: io.NopCloser(strings.NewReader(message)),
- Headers: http.Header{httpheaders.ContentType: {"text/plain"}},
- contentLength: int64(len(message)),
- }
- }
- // NewObjectNotModified creates a new Reader with a 304 Not Modified status.
- func NewObjectNotModified(headers http.Header) *ObjectReader {
- // Copy headers relevant to NotModified response only
- nmHeaders := make(http.Header)
- httpheaders.Copy(
- headers,
- nmHeaders,
- []string{httpheaders.Etag, httpheaders.LastModified},
- )
- return &ObjectReader{
- Status: http.StatusNotModified,
- Headers: nmHeaders,
- contentLength: 0,
- }
- }
- // NewInvalidRang creates a new Reader with a 416 Range Not Satisfiable status.
- func NewObjectInvalidRange() *ObjectReader {
- return &ObjectReader{
- Status: http.StatusRequestedRangeNotSatisfiable,
- contentLength: 0,
- }
- }
- // ContentLength returns the content length of the response.
- func (r *ObjectReader) ContentLength() int64 {
- if r.contentLength > 0 {
- return r.contentLength
- }
- h := r.Headers.Get(httpheaders.ContentLength)
- if len(h) > 0 {
- p, err := strconv.ParseInt(h, 10, 64)
- if err != nil {
- return p
- }
- }
- return -1
- }
- // Response converts Reader to http.Response
- func (r *ObjectReader) Response(req *http.Request) *http.Response {
- return &http.Response{
- Status: http.StatusText(r.Status),
- StatusCode: r.Status,
- Proto: "HTTP/1.0",
- ProtoMajor: 1,
- ProtoMinor: 0,
- Header: r.Headers,
- Body: r.Body,
- Close: true,
- Request: req,
- ContentLength: r.ContentLength(),
- }
- }
|