@@ -118,15 +118,14 @@ func (h *ObjectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
118118func (h * ObjectHandler ) handleGet (ctx context.Context , req * Request , input GetObjectRequest ) (* Response , error ) {
119119 bucket := req .PathParams ["bucket" ]
120120 key := req .PathParams ["key" ]
121-
122121 if bucket == "" || key == "" {
123122 return nil , & ValidationError {Field : "path" , Message : "invalid bucket or key" }
124123 }
125124
126125 cacheKey := cache .GetCacheKey (bucket , key )
127126 acceptsGzip := strings .Contains (req .Headers .Get ("Accept-Encoding" ), "gzip" )
128127
129- // Check cache
128+ // Fast path: Check cache
130129 if entry , found := cache .GetFromCache (cacheKey ); found {
131130 var responseData []byte
132131 var contentEncoding string
@@ -135,31 +134,29 @@ func (h *ObjectHandler) handleGet(ctx context.Context, req *Request, input GetOb
135134 contentEncoding = "gzip"
136135 } else {
137136 responseData = entry .Data
138- contentEncoding = ""
139- }
140-
141- headers := http.Header {
142- "Content-Type" : []string {entry .ContentType },
143- "Content-Length" : []string {fmt .Sprintf ("%d" , len (responseData ))},
144- "Last-Modified" : []string {entry .LastModified .UTC ().Format (http .TimeFormat )},
145- "ETag" : []string {entry .ETag },
146- "Content-Encoding" : []string {contentEncoding },
147137 }
148138
149139 return & Response {
150- StatusCode : http .StatusOK ,
151- Headers : headers ,
140+ StatusCode : http .StatusOK ,
141+ Headers : http.Header {
142+ "Content-Type" : []string {entry .ContentType },
143+ "Content-Length" : []string {fmt .Sprintf ("%d" , len (responseData ))},
144+ "Last-Modified" : []string {entry .LastModified .UTC ().Format (http .TimeFormat )},
145+ "ETag" : []string {entry .ETag },
146+ "Content-Encoding" : []string {contentEncoding },
147+ "X-Cache" : []string {"HIT" },
148+ },
152149 Body : responseData ,
153150 ContentType : entry .ContentType ,
154151 }, nil
155152 }
156153
157- h .logger .Info ("cache miss, fetching from storage" )
158-
154+ // Get object stats first
159155 obj , err := h .client .GetObject (ctx , bucket , key , minio.GetObjectOptions {})
160156 if err != nil {
161157 return nil , err
162158 }
159+ defer obj .Close ()
163160
164161 info , err := obj .Stat ()
165162 if err != nil {
@@ -169,7 +166,40 @@ func (h *ObjectHandler) handleGet(ctx context.Context, req *Request, input GetOb
169166 return nil , err
170167 }
171168
172- // Read the entire object into memory
169+ // For very large files, stream directly
170+ if info .Size > cache .MaxCacheSize * 2 {
171+ h .logger .Info ("large file detected, streaming response" ,
172+ "size" , info .Size ,
173+ "content_type" , info .ContentType ,
174+ )
175+ headers := http.Header {
176+ "Content-Type" : []string {info .ContentType },
177+ "Last-Modified" : []string {info .LastModified .UTC ().Format (http .TimeFormat )},
178+ "ETag" : []string {info .ETag },
179+ "X-Cache" : []string {"BYPASS" },
180+ }
181+
182+ if acceptsGzip && cache .ShouldCompress (info .ContentType , info .Size ) {
183+ return & Response {
184+ StatusCode : http .StatusOK ,
185+ Headers : headers ,
186+ Body : obj ,
187+ ContentType : info .ContentType ,
188+ IsStreaming : true ,
189+ }, nil
190+ }
191+
192+ headers .Set ("Content-Length" , fmt .Sprintf ("%d" , info .Size ))
193+ return & Response {
194+ StatusCode : http .StatusOK ,
195+ Headers : headers ,
196+ Body : obj ,
197+ ContentType : info .ContentType ,
198+ IsStreaming : true ,
199+ }, nil
200+ }
201+
202+ // For smaller files, read into memory
173203 data , err := io .ReadAll (obj )
174204 if err != nil {
175205 return nil , fmt .Errorf ("failed to read object data: %w" , err )
@@ -180,13 +210,18 @@ func (h *ObjectHandler) handleGet(ctx context.Context, req *Request, input GetOb
180210 "content_type" , info .ContentType ,
181211 )
182212
183- // Cache the object
184- cache .AddToCache (cacheKey , data , info .ContentType , int64 (len (data )), info .LastModified , info .ETag )
213+ // Cache smaller files in a goroutine
214+ if int64 (len (data )) <= cache .MaxCacheSize / 2 {
215+ go func () {
216+ cache .AddToCache (cacheKey , data , info .ContentType , int64 (len (data )), info .LastModified , info .ETag )
217+ }()
218+ }
185219
186220 headers := http.Header {
187221 "Content-Type" : []string {info .ContentType },
188222 "Last-Modified" : []string {info .LastModified .UTC ().Format (http .TimeFormat )},
189223 "ETag" : []string {info .ETag },
224+ "X-Cache" : []string {"MISS" },
190225 }
191226
192227 responseData := data
@@ -201,7 +236,6 @@ func (h *ObjectHandler) handleGet(ctx context.Context, req *Request, input GetOb
201236 }
202237 }
203238
204- // Set Content-Length after compression decision
205239 headers .Set ("Content-Length" , fmt .Sprintf ("%d" , len (responseData )))
206240
207241 return & Response {
0 commit comments