Skip to content

Commit

Permalink
Prevent PHP warnings
Browse files Browse the repository at this point in the history
Prevent PHP warnings when an HTTP response includes a
`Content-Type: application/x-gzip` header, but the content is not
actually compressed. This issue also occurred with cached responses,
because compressed content is decoded during caching. Upon retrieval
from the cache, the header indicated compression, but the content was
already decoded.
  • Loading branch information
otsch committed Jul 24, 2024
1 parent 3c10453 commit a064aeb
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.9.5] - 2024-07-25
### Fixed
* Prevent PHP warnings when an HTTP response includes a `Content-Type: application/x-gzip` header, but the content is not actually compressed. This issue also occurred with cached responses, because compressed content is decoded during caching. Upon retrieval from the cache, the header indicated compression, but the content was already decoded.

## [1.9.4] - 2024-07-24
### Fixed
* When using `HttpLoader::cacheOnlyWhereUrl()` to restrict caching, the filter rule is not only applied when adding newly loaded responses to the cache, but also for using cached responses. Example: a response for `https://www.example.com/foo` is already available in the cache, but `$loader->cacheOnlyWhereUrl(Filter::urlPathStartsWith('/bar/'))` was called, the cached response is not used.
Expand Down
10 changes: 9 additions & 1 deletion src/Steps/Loading/Http.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,17 @@ public static function getBodyString(MessageInterface|RespondedRequest $message)

$contents = $message->getBody()->getContents();

if (in_array('application/x-gzip', $message->getHeader('Content-Type'), true)) {
if (in_array('application/x-gzip', $message->getHeader('Content-Type'), true) && function_exists('gzdecode')) {
// Temporarily set a new error handler, so decoding a string that actually isn't compressed, doesn't
// generate a warning.
$previousHandler = set_error_handler(function ($errno, $errstr) {
return $errno === E_WARNING && str_contains($errstr, 'gzdecode(): data error');
});

$decoded = gzdecode($contents);

set_error_handler($previousHandler);

$contents = $decoded === false ? $contents : $decoded;
}

Expand Down
30 changes: 30 additions & 0 deletions tests/Steps/Loading/HttpTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Psr\Http\Message\RequestInterface;
use stdClass;

use function tests\helper_getRespondedRequest;
use function tests\helper_invokeStepWithInput;
use function tests\helper_traverseIterable;

Expand Down Expand Up @@ -405,3 +406,32 @@ function ($key) {

helper_invokeStepWithInput($step, $inputArray);
});

test(
'the getBodyString() method does not generate a warning, when the response contains a ' .
'Content-Type: application/x-gzip header, but the content actually isn\'t compressed',
function () {
$warnings = [];

$previousHandler = set_error_handler(function ($errno, $errstr) use (&$warnings) {
if ($errno === E_WARNING) {
$warnings[] = $errstr;
}

return false;
});

$response = helper_getRespondedRequest(
url: 'https://example.com/yolo',
responseHeaders: ['Content-Type' => 'application/x-gzip'],
responseBody: 'Servas!',
);

$string = Http::getBodyString($response);

set_error_handler($previousHandler);

expect($warnings)->toBeEmpty()
->and($string)->toBe('Servas!');
},
);

0 comments on commit a064aeb

Please sign in to comment.