Variable GUZZLE_HANDLER_CHECK_PHPConst
GUZZLE_HANDLER_CHECK_PHP: "\nuse Drupal\\drupflare\\Http\\CachedFetchHandler;\nuse Drupal\\drupflare\\StreamWrapper\\HttpsStreamWrapper;\nuse GuzzleHttp\\Client;\nuse GuzzleHttp\\Exception\\ConnectException;\nuse GuzzleHttp\\Handler\\StreamHandler;\nuse GuzzleHttp\\HandlerStack;\n\n// __CFW_FIBER_SHIM__\n// __CFW_HOST_HELPERS__\nchdir('/drupal');\n\n$checks = [];\n$assert = function (string $label, bool $ok, $detail = null) use (&$checks) {\n\t$checks[] = ['label' => $label, 'ok' => $ok, 'detail' => $detail];\n};\n\ntry {\n\tif (!isset($GLOBALS['__pw_autoloader']) || !is_object($GLOBALS['__pw_autoloader'])) {\n\t\t$GLOBALS['__pw_autoloader'] = require '/drupal/autoload.php';\n\t}\n\t$autoloader = $GLOBALS['__pw_autoloader'];\n\t$autoloader->addPsr4('Drupal\\\\drupflare\\\\', '/drupal/modules/custom/drupflare/src/');\n\t$autoloader->addPsr4('Drupflare\\\\StreamHttp\\\\', '/drupal/libraries/drupflare-stream-http/src/');\n\n\tHttpsStreamWrapper::register();\n\t$url = getenv('CFW_TEST_URL') ?: 'https://example.com/';\n\n\t// the mechanism, measured rather than reasoned: no userland wrapper can populate either the\n\t// magic local or its 8.4 replacement, so the consumer has nothing to read\n\t$fh = @fopen($url, 'r');\n\t$assert('the wrapper opens the seeded url', is_resource($fh));\n\tif (is_resource($fh)) {\n\t\t$assert('and the body is there to be read', stream_get_contents($fh) !== '');\n\t\t$assert(\n\t\t\t'but $http_response_header is not set',\n\t\t\t!array_key_exists('http_response_header', get_defined_vars()),\n\t\t);\n\t\tif (function_exists('http_get_last_response_headers')) {\n\t\t\t$assert(\n\t\t\t\t'and the 8.4 replacement answers NULL for the same reason',\n\t\t\t\thttp_get_last_response_headers() === null,\n\t\t\t);\n\t\t}\n\t\tfclose($fh);\n\t}\n\n\t// CONTROL: core's handler, over the working wrapper. It must still fail.\n\t$core = HandlerStack::create(new StreamHandler());\n\t$coreClient = new Client(['handler' => $core]);\n\t$coreFailed = false;\n\t$coreReason = '';\n\ttry {\n\t\t$coreClient->get($url);\n\t} catch (Throwable $e) {\n\t\t$coreFailed = true;\n\t\t$coreReason = get_class($e) . ': ' . $e->getMessage();\n\t}\n\t$assert('CONTROL: core StreamHandler still cannot build a response', $coreFailed, $coreReason);\n\t$assert(\n\t\t'and it fails where the report says it does',\n\t\tstr_contains($coreReason, 'creating the response'),\n\t\t$coreReason,\n\t);\n\n\t// the fix, through the class the service provider now installs\n\t$stack = HandlerStack::create(new CachedFetchHandler());\n\t$client = new Client(['handler' => $stack]);\n\t$response = $client->get($url);\n\t$assert(\n\t\t'CachedFetchHandler answers 200',\n\t\t$response->getStatusCode() === 200,\n\t\t$response->getStatusCode(),\n\t);\n\t$assert(\n\t\t'with a body',\n\t\tstrlen((string) $response->getBody()) > 0,\n\t\tstrlen((string) $response->getBody()),\n\t);\n\t$assert(\n\t\t'and the headers the drain stored',\n\t\t$response->getHeaderLine('content-type') !== '',\n\t\t$response->getHeaderLine('content-type'),\n\t);\n\n\t// the negative case: an uncached url is a refusal a caller's error path already handles, never\n\t// a 2xx carrying an explanation\n\t$missing = 'https://example.invalid/never-prefetched-' . bin2hex(random_bytes(3));\n\t$refused = '';\n\ttry {\n\t\t$client->get($missing);\n\t} catch (Throwable $e) {\n\t\t$refused = get_class($e);\n\t}\n\t$assert('an uncached url rejects', $refused !== '', $refused);\n\t$assert(\n\t\t'as a ConnectException, which is what a failed socket raises too',\n\t\t$refused === ConnectException::class,\n\t\t$refused,\n\t);\n} catch (Throwable $e) {\n\t$assert(\n\t\t'no exception escaped the guzzle check',\n\t\tfalse,\n\t\tget_class($e) . ': ' . $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine(),\n\t);\n}\n\n$passed = count(array_filter($checks, fn($c) => $c['ok']));\necho json_encode([\n\t'passed' => $passed,\n\t'failed' => count($checks) - $passed,\n\t'checks' => $checks,\n]);\n"