@@ -12,6 +12,7 @@ import (
12
12
"google.golang.org/api/option"
13
13
14
14
"github.com/imgproxy/imgproxy/v3/config"
15
+ "github.com/imgproxy/imgproxy/v3/httprange"
15
16
)
16
17
17
18
// For tests
@@ -58,40 +59,82 @@ func (t transport) RoundTrip(req *http.Request) (*http.Response, error) {
58
59
obj = obj .Generation (g )
59
60
}
60
61
62
+ var (
63
+ reader * storage.Reader
64
+ statusCode int
65
+ size int64
66
+ )
67
+
61
68
header := make (http.Header )
62
69
63
- if config . ETagEnabled {
64
- attrs , err := obj . Attrs ( req . Context () )
70
+ if r := req . Header . Get ( "Range" ); len ( r ) != 0 {
71
+ start , end , err := httprange . Parse ( r )
65
72
if err != nil {
66
- return handleError (req , err )
73
+ return httprange . InvalidHTTPRangeResponse (req ), nil
67
74
}
68
- header .Set ("ETag" , attrs .Etag )
69
-
70
- if etag := req .Header .Get ("If-None-Match" ); len (etag ) > 0 && attrs .Etag == etag {
71
- return & http.Response {
72
- StatusCode : http .StatusNotModified ,
73
- Proto : "HTTP/1.0" ,
74
- ProtoMajor : 1 ,
75
- ProtoMinor : 0 ,
76
- Header : header ,
77
- ContentLength : 0 ,
78
- Body : nil ,
79
- Close : false ,
80
- Request : req ,
81
- }, nil
75
+
76
+ if end != 0 {
77
+ length := end - start + 1
78
+ if end < 0 {
79
+ length = - 1
80
+ }
81
+
82
+ reader , err = obj .NewRangeReader (req .Context (), start , length )
83
+ if err != nil {
84
+ return nil , err
85
+ }
86
+
87
+ if end < 0 || end >= reader .Attrs .Size {
88
+ end = reader .Attrs .Size - 1
89
+ }
90
+
91
+ size = end - reader .Attrs .StartOffset + 1
92
+
93
+ statusCode = http .StatusPartialContent
94
+ header .Set ("Content-Range" , fmt .Sprintf ("bytes %d-%d/%d" , reader .Attrs .StartOffset , end , reader .Attrs .Size ))
82
95
}
83
96
}
84
97
85
- reader , err := obj .NewReader (req .Context ())
86
- if err != nil {
87
- return handleError (req , err )
98
+ // We haven't initialize reader yet, this means that we need non-ranged reader
99
+ if reader == nil {
100
+ if config .ETagEnabled {
101
+ attrs , err := obj .Attrs (req .Context ())
102
+ if err != nil {
103
+ return handleError (req , err )
104
+ }
105
+ header .Set ("ETag" , attrs .Etag )
106
+
107
+ if etag := req .Header .Get ("If-None-Match" ); len (etag ) > 0 && attrs .Etag == etag {
108
+ return & http.Response {
109
+ StatusCode : http .StatusNotModified ,
110
+ Proto : "HTTP/1.0" ,
111
+ ProtoMajor : 1 ,
112
+ ProtoMinor : 0 ,
113
+ Header : header ,
114
+ ContentLength : 0 ,
115
+ Body : nil ,
116
+ Close : false ,
117
+ Request : req ,
118
+ }, nil
119
+ }
120
+ }
121
+
122
+ var err error
123
+ reader , err = obj .NewReader (req .Context ())
124
+ if err != nil {
125
+ return handleError (req , err )
126
+ }
127
+
128
+ statusCode = 200
129
+ size = reader .Attrs .Size
88
130
}
89
131
132
+ header .Set ("Content-Length" , strconv .Itoa (int (size )))
133
+ header .Set ("Content-Type" , reader .Attrs .ContentType )
90
134
header .Set ("Cache-Control" , reader .Attrs .CacheControl )
91
135
92
136
return & http.Response {
93
- Status : "200 OK" ,
94
- StatusCode : 200 ,
137
+ StatusCode : statusCode ,
95
138
Proto : "HTTP/1.0" ,
96
139
ProtoMajor : 1 ,
97
140
ProtoMinor : 0 ,
0 commit comments