@@ -294,11 +294,9 @@ private function readResponse(
294
294
Request $ request ,
295
295
Cancellation $ originalCancellation ,
296
296
Cancellation $ readingCancellation ,
297
- Stream $ stream
297
+ Stream $ stream,
298
298
): Response {
299
299
$ bodyEmitter = new Queue ();
300
- $ bodyCallback = static fn (string $ data ) => $ bodyEmitter ->push ($ data );
301
-
302
300
$ trailersDeferred = new DeferredFuture ;
303
301
$ trailersDeferred ->getFuture ()->ignore ();
304
302
@@ -307,17 +305,17 @@ private function readResponse(
307
305
$ trailers = $ headers ;
308
306
};
309
307
310
- $ parser = new Http1Parser ($ request , $ stream , $ bodyCallback , $ trailersCallback );
308
+ $ parser = new Http1Parser ($ request , $ stream , $ bodyEmitter -> pushAsync (...) , $ trailersCallback );
311
309
312
310
$ start = now ();
313
- $ timeout = $ request ->getInactivityTimeout ();
311
+ $ inactivityTimeout = $ request ->getInactivityTimeout ();
314
312
315
313
try {
316
314
if ($ this ->socket === null ) {
317
315
throw new SocketException ('Socket closed prior to response completion ' );
318
316
}
319
317
320
- while (null !== $ chunk = $ this ->readChunk ($ timeout )) {
318
+ while (null !== $ chunk = $ this ->readChunk ($ inactivityTimeout )) {
321
319
parseChunk:
322
320
$ response = $ parser ->parse ($ chunk );
323
321
if ($ response === null ) {
@@ -355,7 +353,7 @@ private function readResponse(
355
353
}
356
354
357
355
$ chunk = $ parser ->getBuffer ();
358
- $ parser = new Http1Parser ($ request , $ stream , $ bodyCallback , $ trailersCallback );
356
+ $ parser = new Http1Parser ($ request , $ stream , $ bodyEmitter -> pushAsync (...) , $ trailersCallback );
359
357
goto parseChunk;
360
358
}
361
359
@@ -374,22 +372,26 @@ private function readResponse(
374
372
$ response ->setTrailers ($ trailersDeferred ->getFuture ());
375
373
$ response ->setBody (new ResponseBodyStream (
376
374
new ReadableIterableStream ($ bodyEmitter ->pipe ()),
377
- $ bodyDeferredCancellation
375
+ $ bodyDeferredCancellation,
378
376
));
379
377
378
+ [$ requestTimeout , $ explicitTimeout , $ priorTimeout ] = $ this ->determineKeepAliveTimeout ($ response );
379
+
380
380
// Read body async
381
381
EventLoop::queue (function () use (
382
382
$ parser ,
383
383
$ request ,
384
- $ response ,
384
+ $ requestTimeout ,
385
+ $ explicitTimeout ,
386
+ $ priorTimeout ,
387
+ $ inactivityTimeout ,
385
388
$ bodyEmitter ,
386
389
$ trailersDeferred ,
387
390
$ originalCancellation ,
388
391
$ readingCancellation ,
389
392
$ bodyCancellation ,
390
393
$ stream ,
391
- $ timeout ,
392
- &$ trailers
394
+ &$ trailers ,
393
395
) {
394
396
$ closeId = $ bodyCancellation ->subscribe ($ this ->close (...));
395
397
@@ -401,31 +403,24 @@ private function readResponse(
401
403
$ chunk = null ;
402
404
403
405
try {
404
- /** @psalm-suppress PossiblyNullReference */
405
406
do {
406
- /** @noinspection CallableParameterUseCaseInTypeContextInspection */
407
407
$ parser ->parse ($ chunk );
408
- /**
409
- * @noinspection NotOptimalIfConditionsInspection
410
- * @psalm-suppress TypeDoesNotContainType
411
- */
412
408
if ($ parser ->isComplete ()) {
413
409
break ;
414
410
}
415
411
416
- /** @psalm-suppress TypeDoesNotContainNull */
417
412
if ($ this ->socket === null ) {
418
413
throw new SocketException ('Socket closed prior to response completion ' );
419
414
}
420
- } while (null !== $ chunk = $ this ->socket -> read ( $ timeout > 0 ? new TimeoutCancellation ( $ timeout ) : null ));
415
+ } while (null !== $ chunk = $ this ->readChunk ( $ inactivityTimeout ));
421
416
} catch (CancelledException $ e ) {
422
417
$ this ->close ();
423
418
$ originalCancellation ->throwIfRequested ();
424
419
425
420
throw new TimeoutException (
426
- 'Inactivity timeout exceeded, more than ' . $ timeout . ' seconds elapsed from last data received ' ,
427
- 0 ,
428
- $ e
421
+ 'Inactivity timeout exceeded, more than ' . $ inactivityTimeout
422
+ . ' seconds elapsed from last data received ' ,
423
+ previous: $ e ,
429
424
);
430
425
}
431
426
@@ -443,10 +438,11 @@ private function readResponse(
443
438
}
444
439
}
445
440
446
- $ timeout = $ this ->determineKeepAliveTimeout ($ response );
441
+ $ this ->explicitTimeout = $ explicitTimeout ?: $ this ->explicitTimeout ;
442
+ $ this ->priorTimeout = $ priorTimeout ?? $ this ->priorTimeout ;
447
443
448
- if ($ timeout > 0 && $ parser ->getState () !== Http1Parser::BODY_IDENTITY_EOF ) {
449
- $ this ->timeoutWatcher = EventLoop::delay ($ timeout , $ this ->close (...));
444
+ if ($ requestTimeout > 0 && $ parser ->getState () !== Http1Parser::BODY_IDENTITY_EOF ) {
445
+ $ this ->timeoutWatcher = EventLoop::delay ($ requestTimeout , $ this ->close (...));
450
446
EventLoop::unreference ($ this ->timeoutWatcher );
451
447
$ this ->watchIdleConnection ();
452
448
} else {
@@ -504,7 +500,7 @@ private function readResponse(
504
500
throw new TimeoutException ('Allowed transfer timeout exceeded, took longer than ' . $ request ->getTransferTimeout () . ' s ' , 0 , $ e );
505
501
}
506
502
507
- throw new TimeoutException ('Inactivity timeout exceeded, more than ' . $ timeout . ' seconds elapsed from last data received ' , 0 , $ e );
503
+ throw new TimeoutException ('Inactivity timeout exceeded, more than ' . $ inactivityTimeout . ' seconds elapsed from last data received ' , 0 , $ e );
508
504
} catch (\Throwable $ e ) {
509
505
$ this ->close ();
510
506
throw new SocketException ('Receiving the response headers failed: ' . $ e ->getMessage (), 0 , $ e );
@@ -546,33 +542,34 @@ private function getRemainingTime(): float
546
542
return \max (0 , $ timestamp - now ());
547
543
}
548
544
549
- private function determineKeepAliveTimeout (Response $ response ): int
545
+ /**
546
+ * @return array{int, bool, int|null}
547
+ */
548
+ private function determineKeepAliveTimeout (Response $ response ): array
550
549
{
551
550
$ request = $ response ->getRequest ();
552
551
553
552
$ requestConnHeader = $ request ->getHeader ('connection ' ) ?? '' ;
554
553
$ responseConnHeader = $ response ->getHeader ('connection ' ) ?? '' ;
555
554
556
555
if (!\strcasecmp ($ requestConnHeader , 'close ' )) {
557
- return 0 ;
556
+ return [ 0 , false , null ] ;
558
557
}
559
558
560
559
if ($ response ->getProtocolVersion () === '1.0 ' ) {
561
- return 0 ;
560
+ return [ 0 , false , null ] ;
562
561
}
563
562
564
563
if (!\strcasecmp ($ responseConnHeader , 'close ' )) {
565
- return 0 ;
564
+ return [ 0 , false , null ] ;
566
565
}
567
566
568
567
$ params = Http \parseMultipleHeaderFields ($ response , 'keep-alive ' )[0 ] ?? null ;
569
568
570
569
$ timeout = (int ) ($ params ['timeout ' ] ?? $ this ->priorTimeout );
571
- if (isset ($ params ['timeout ' ])) {
572
- $ this ->explicitTimeout = true ;
573
- }
570
+ $ timeout = \min (\max (0 , $ timeout ), self ::MAX_KEEP_ALIVE_TIMEOUT );
574
571
575
- return $ this -> priorTimeout = \min ( \max ( 0 , $ timeout ), self :: MAX_KEEP_ALIVE_TIMEOUT ) ;
572
+ return [ $ timeout , isset ( $ params [ ' timeout ' ] ), $ timeout ] ;
576
573
}
577
574
578
575
/**
0 commit comments