@@ -174,7 +174,7 @@ public function request(string $method, string $url, array $options = []): Respo
174174 $ freshness = $ this ->evaluateCacheFreshness ($ cachedData );
175175
176176 if (Freshness::Fresh === $ freshness ) {
177- return $ this ->createResponseFromCache ($ metadataKey , $ cachedData , $ method , $ url , $ options , $ fullUrlTag );
177+ return $ this ->createResponseFromCache ($ cachedData , $ method , $ url , $ options , $ fullUrlTag );
178178 }
179179
180180 if (isset ($ cachedData ['headers ' ]['etag ' ])) {
@@ -206,15 +206,14 @@ function (ChunkInterface $chunk, AsyncContext $context) use (
206206 $ method ,
207207 $ options ,
208208 ): \Generator {
209- static $ chunkIndex = -1 ;
210- static $ varyFields ;
209+ static $ chunkKey = null ;
211210
212211 if (null !== $ chunk ->getError () || $ chunk ->isTimeout ()) {
213212 if (Freshness::StaleButUsable === $ freshness ) {
214213 // avoid throwing exception in ErrorChunk#__destruct()
215214 $ chunk instanceof ErrorChunk && $ chunk ->didThrow (true );
216215 $ context ->passthru ();
217- $ context ->replaceResponse ($ this ->createResponseFromCache ($ metadataKey , $ cachedData , $ method , $ url , $ options , $ fullUrlTag ));
216+ $ context ->replaceResponse ($ this ->createResponseFromCache ($ cachedData , $ method , $ url , $ options , $ fullUrlTag ));
218217
219218 return ;
220219 }
@@ -234,10 +233,10 @@ function (ChunkInterface $chunk, AsyncContext $context) use (
234233 }
235234
236235 $ headers = $ context ->getHeaders ();
237- $ cacheControl = self ::parseCacheControlHeader ($ headers ['cache-control ' ] ?? []);
238236
239237 if ($ chunk ->isFirst ()) {
240238 $ statusCode = $ context ->getStatusCode ();
239+ $ cacheControl = self ::parseCacheControlHeader ($ headers ['cache-control ' ] ?? []);
241240
242241 if (304 === $ statusCode && null !== $ freshness ) {
243242 $ maxAge = $ this ->determineMaxAge ($ headers , $ cacheControl );
@@ -254,15 +253,15 @@ function (ChunkInterface $chunk, AsyncContext $context) use (
254253 }, \INF );
255254
256255 $ context ->passthru ();
257- $ context ->replaceResponse ($ this ->createResponseFromCache ($ metadataKey , $ cachedData , $ method , $ url , $ options , $ fullUrlTag ));
256+ $ context ->replaceResponse ($ this ->createResponseFromCache ($ cachedData , $ method , $ url , $ options , $ fullUrlTag ));
258257
259258 return ;
260259 }
261260
262261 if ($ statusCode >= 500 && $ statusCode < 600 ) {
263262 if (Freshness::StaleButUsable === $ freshness ) {
264263 $ context ->passthru ();
265- $ context ->replaceResponse ($ this ->createResponseFromCache ($ metadataKey , $ cachedData , $ method , $ url , $ options , $ fullUrlTag ));
264+ $ context ->replaceResponse ($ this ->createResponseFromCache ($ cachedData , $ method , $ url , $ options , $ fullUrlTag ));
266265
267266 return ;
268267 }
@@ -275,6 +274,14 @@ function (ChunkInterface $chunk, AsyncContext $context) use (
275274 }
276275 }
277276
277+ if (!$ this ->isServerResponseCacheable ($ statusCode , $ options ['normalized_headers ' ], $ headers , $ cacheControl )) {
278+ $ context ->passthru ();
279+
280+ yield $ chunk ;
281+
282+ return ;
283+ }
284+
278285 // recomputing vary fields in case it changed or for first request
279286 $ varyFields = [];
280287 foreach ($ headers ['vary ' ] ?? [] as $ vary ) {
@@ -295,31 +302,17 @@ function (ChunkInterface $chunk, AsyncContext $context) use (
295302 return ;
296303 }
297304
298- $ metadataKey = self ::getMetadataKey ($ requestHash , $ options ['normalized_headers ' ], $ varyFields );
299-
300- yield $ chunk ;
301-
302- return ;
303- }
304-
305- if (!$ this ->isServerResponseCacheable ($ context ->getStatusCode (), $ options ['normalized_headers ' ], $ headers , $ cacheControl )) {
306- $ context ->passthru ();
307-
308- yield $ chunk ;
309-
310- return ;
311- }
312-
313- if ($ chunk ->isLast ()) {
314305 $ this ->cache ->get ($ varyKey , static function (ItemInterface $ item ) use ($ varyFields , $ expiresAt , $ fullUrlTag ): array {
315306 $ item ->tag ($ fullUrlTag )->expiresAt ($ expiresAt );
316307
317308 return $ varyFields ;
318309 }, \INF );
319310
311+ $ metadataKey = self ::getMetadataKey ($ requestHash , $ options ['normalized_headers ' ], $ varyFields );
320312 $ maxAge = $ this ->determineMaxAge ($ headers , $ cacheControl );
313+ $ chunkKey = "{$ metadataKey }_chunk_ " .bin2hex (random_bytes (8 ));
321314
322- $ this ->cache ->get ($ metadataKey , static function (ItemInterface $ item ) use ($ context , $ headers , $ maxAge , $ expiresAt , $ fullUrlTag , $ chunkIndex ): array {
315+ $ this ->cache ->get ($ metadataKey , static function (ItemInterface $ item ) use ($ context , $ headers , $ maxAge , $ expiresAt , $ fullUrlTag , $ chunkKey ): array {
323316 $ item ->tag ($ fullUrlTag )->expiresAt ($ expiresAt );
324317
325318 return [
@@ -328,7 +321,7 @@ function (ChunkInterface $chunk, AsyncContext $context) use (
328321 'initial_age ' => (int ) ($ headers ['age ' ][0 ] ?? 0 ),
329322 'stored_at ' => time (),
330323 'expires_at ' => self ::calculateExpiresAt ($ maxAge ),
331- 'chunks_count ' => $ chunkIndex ,
324+ 'first_chunk ' => $ chunkKey ,
332325 ];
333326 }, \INF );
334327
@@ -337,13 +330,31 @@ function (ChunkInterface $chunk, AsyncContext $context) use (
337330 return ;
338331 }
339332
340- ++$ chunkIndex ;
341- $ chunkKey = "{$ metadataKey }_chunk_ {$ chunkIndex }" ;
342- $ this ->cache ->get ($ chunkKey , static function (ItemInterface $ item ) use ($ expiresAt , $ fullUrlTag , $ chunk ): string {
333+ if ($ chunk ->isLast ()) {
334+ $ this ->cache ->get ($ chunkKey , static function (ItemInterface $ item ) use ($ expiresAt , $ fullUrlTag , $ chunk ): array {
335+ $ item ->tag ($ fullUrlTag )->expiresAt ($ expiresAt );
336+
337+ return [
338+ 'content ' => $ chunk ->getContent (),
339+ 'next_chunk ' => null ,
340+ ];
341+ }, \INF );
342+
343+ yield $ chunk ;
344+
345+ return ;
346+ }
347+
348+ $ nextChunkKey = "{$ metadataKey }_chunk_ " .bin2hex (random_bytes (8 ));
349+ $ this ->cache ->get ($ chunkKey , static function (ItemInterface $ item ) use ($ expiresAt , $ fullUrlTag , $ chunk , $ nextChunkKey ): array {
343350 $ item ->tag ($ fullUrlTag )->expiresAt ($ expiresAt );
344351
345- return $ chunk ->getContent ();
352+ return [
353+ 'content ' => $ chunk ->getContent (),
354+ 'next_chunk ' => $ nextChunkKey ,
355+ ];
346356 }, \INF );
357+ $ chunkKey = $ nextChunkKey ;
347358
348359 yield $ chunk ;
349360 }
@@ -689,19 +700,27 @@ private function hasExplicitExpiration(array $headers, array $cacheControl): boo
689700 * response headers and content. The constructed MockResponse is then
690701 * returned.
691702 *
692- * @param array{chunks_count: int , status_code: int, initial_age: int, headers: array<string, string|string[]>, stored_at: int} $cachedData
703+ * @param array{first_chunk: string , status_code: int, initial_age: int, headers: array<string, string|string[]>, stored_at: int} $cachedData
693704 */
694- private function createResponseFromCache (string $ key , array $ cachedData , string $ method , string $ url , array $ options , string $ fullUrlTag ): MockResponse
705+ private function createResponseFromCache (array $ cachedData , string $ method , string $ url , array $ options , string $ fullUrlTag ): MockResponse
695706 {
696707 $ cache = $ this ->cache ;
697708 $ callback = static function (ItemInterface $ item ) use ($ cache , $ fullUrlTag ): never {
698709 $ cache ->invalidateTags ([$ fullUrlTag ]);
699710
700711 throw new ChunkCacheItemNotFoundException (\sprintf ('Missing cache item for chunk with key "%s". This indicates an internal cache inconsistency. ' , $ item ->getKey ()));
701712 };
702- $ body = static function () use ($ cache , $ key , $ cachedData , $ callback ): \Generator {
703- for ($ i = 0 ; $ i <= $ cachedData ['chunks_count ' ]; ++$ i ) {
704- yield $ cache ->get ("{$ key }_chunk_ {$ i }" , $ callback , 0 );
713+ $ body = static function () use ($ cache , $ cachedData , $ callback ): \Generator {
714+ $ chunk = $ cache ->get ($ cachedData ['first_chunk ' ], $ callback , 0 );
715+
716+ yield $ chunk ['content ' ];
717+
718+ while (null !== $ chunk ['next_chunk ' ]) {
719+ $ chunk = $ cache ->get ($ chunk ['next_chunk ' ], $ callback , 0 );
720+
721+ if ('' !== $ chunk ['content ' ]) {
722+ yield $ chunk ['content ' ];
723+ }
705724 }
706725 };
707726
0 commit comments