123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797 |
- <?php
- namespace GuzzleHttp\Test\Handler;
- use GuzzleHttp\Exception\ConnectException;
- use GuzzleHttp\Exception\RequestException;
- use GuzzleHttp\Handler\StreamHandler;
- use GuzzleHttp\Psr7;
- use GuzzleHttp\Psr7\FnStream;
- use GuzzleHttp\Psr7\Request;
- use GuzzleHttp\Psr7\Response;
- use GuzzleHttp\RequestOptions;
- use GuzzleHttp\Tests\Server;
- use GuzzleHttp\TransferStats;
- use GuzzleHttp\Utils;
- use PHPUnit\Framework\TestCase;
- use Psr\Http\Message\ResponseInterface;
- /**
- * @covers \GuzzleHttp\Handler\StreamHandler
- */
- class StreamHandlerTest extends TestCase
- {
- private function queueRes()
- {
- Server::flush();
- Server::enqueue([
- new Response(200, [
- 'Foo' => 'Bar',
- 'Content-Length' => 8,
- ], 'hi there'),
- ]);
- }
- public function testReturnsResponseForSuccessfulRequest()
- {
- $this->queueRes();
- $handler = new StreamHandler();
- $response = $handler(
- new Request('GET', Server::$url, ['Foo' => 'Bar']),
- []
- )->wait();
- self::assertSame(200, $response->getStatusCode());
- self::assertSame('OK', $response->getReasonPhrase());
- self::assertSame('Bar', $response->getHeaderLine('Foo'));
- self::assertSame('8', $response->getHeaderLine('Content-Length'));
- self::assertSame('hi there', (string) $response->getBody());
- $sent = Server::received()[0];
- self::assertSame('GET', $sent->getMethod());
- self::assertSame('/', $sent->getUri()->getPath());
- self::assertSame('127.0.0.1:8126', $sent->getHeaderLine('Host'));
- self::assertSame('Bar', $sent->getHeaderLine('foo'));
- }
- public function testAddsErrorToResponse()
- {
- $handler = new StreamHandler();
- $this->expectException(ConnectException::class);
- $handler(
- new Request('GET', 'http://localhost:123'),
- ['timeout' => 0.01]
- )->wait();
- }
- public function testStreamAttributeKeepsStreamOpen()
- {
- $this->queueRes();
- $handler = new StreamHandler();
- $request = new Request(
- 'PUT',
- Server::$url.'foo?baz=bar',
- ['Foo' => 'Bar'],
- 'test'
- );
- $response = $handler($request, ['stream' => true])->wait();
- self::assertSame(200, $response->getStatusCode());
- self::assertSame('OK', $response->getReasonPhrase());
- self::assertSame('8', $response->getHeaderLine('Content-Length'));
- $body = $response->getBody();
- $stream = $body->detach();
- self::assertIsResource($stream);
- self::assertSame('http', \stream_get_meta_data($stream)['wrapper_type']);
- self::assertSame('hi there', \stream_get_contents($stream));
- \fclose($stream);
- $sent = Server::received()[0];
- self::assertSame('PUT', $sent->getMethod());
- self::assertSame('http://127.0.0.1:8126/foo?baz=bar', (string) $sent->getUri());
- self::assertSame('Bar', $sent->getHeaderLine('Foo'));
- self::assertSame('test', (string) $sent->getBody());
- }
- public function testDrainsResponseIntoTempStream()
- {
- $this->queueRes();
- $handler = new StreamHandler();
- $request = new Request('GET', Server::$url);
- $response = $handler($request, [])->wait();
- $body = $response->getBody();
- $stream = $body->detach();
- self::assertSame('php://temp', \stream_get_meta_data($stream)['uri']);
- self::assertSame('hi', \fread($stream, 2));
- \fclose($stream);
- }
- public function testDrainsResponseIntoSaveToBody()
- {
- $r = \fopen('php://temp', 'r+');
- $this->queueRes();
- $handler = new StreamHandler();
- $request = new Request('GET', Server::$url);
- $response = $handler($request, ['sink' => $r])->wait();
- $body = $response->getBody()->detach();
- self::assertSame('php://temp', \stream_get_meta_data($body)['uri']);
- self::assertSame('hi', \fread($body, 2));
- self::assertSame(' there', \stream_get_contents($r));
- \fclose($r);
- }
- public function testDrainsResponseIntoSaveToBodyAtPath()
- {
- $tmpfname = \tempnam(\sys_get_temp_dir(), 'save_to_path');
- $this->queueRes();
- $handler = new StreamHandler();
- $request = new Request('GET', Server::$url);
- $response = $handler($request, ['sink' => $tmpfname])->wait();
- $body = $response->getBody();
- self::assertSame($tmpfname, $body->getMetadata('uri'));
- self::assertSame('hi', $body->read(2));
- $body->close();
- \unlink($tmpfname);
- }
- public function testDrainsResponseIntoSaveToBodyAtNonExistentPath()
- {
- $tmpfname = \tempnam(\sys_get_temp_dir(), 'save_to_path');
- \unlink($tmpfname);
- $this->queueRes();
- $handler = new StreamHandler();
- $request = new Request('GET', Server::$url);
- $response = $handler($request, ['sink' => $tmpfname])->wait();
- $body = $response->getBody();
- self::assertSame($tmpfname, $body->getMetadata('uri'));
- self::assertSame('hi', $body->read(2));
- $body->close();
- \unlink($tmpfname);
- }
- public function testDrainsResponseAndReadsOnlyContentLengthBytes()
- {
- Server::flush();
- Server::enqueue([
- new Response(200, [
- 'Foo' => 'Bar',
- 'Content-Length' => 8,
- ], 'hi there... This has way too much data!'),
- ]);
- $handler = new StreamHandler();
- $request = new Request('GET', Server::$url);
- $response = $handler($request, [])->wait();
- $body = $response->getBody();
- $stream = $body->detach();
- self::assertSame('hi there', \stream_get_contents($stream));
- \fclose($stream);
- }
- public function testDoesNotDrainWhenHeadRequest()
- {
- Server::flush();
- // Say the content-length is 8, but return no response.
- Server::enqueue([
- new Response(200, [
- 'Foo' => 'Bar',
- 'Content-Length' => 8,
- ], ''),
- ]);
- $handler = new StreamHandler();
- $request = new Request('HEAD', Server::$url);
- $response = $handler($request, [])->wait();
- $body = $response->getBody();
- $stream = $body->detach();
- self::assertSame('', \stream_get_contents($stream));
- \fclose($stream);
- }
- public function testAutomaticallyDecompressGzip()
- {
- Server::flush();
- $content = \gzencode('test');
- Server::enqueue([
- new Response(200, [
- 'Content-Encoding' => 'gzip',
- 'Content-Length' => \strlen($content),
- ], $content),
- ]);
- $handler = new StreamHandler();
- $request = new Request('GET', Server::$url);
- $response = $handler($request, ['decode_content' => true])->wait();
- self::assertSame('test', (string) $response->getBody());
- self::assertFalse($response->hasHeader('content-encoding'));
- self::assertTrue(!$response->hasHeader('content-length') || $response->getHeaderLine('content-length') == $response->getBody()->getSize());
- }
- public function testAutomaticallyDecompressGzipHead()
- {
- Server::flush();
- $content = \gzencode('test');
- Server::enqueue([
- new Response(200, [
- 'Content-Encoding' => 'gzip',
- 'Content-Length' => \strlen($content),
- ], $content),
- ]);
- $handler = new StreamHandler();
- $request = new Request('HEAD', Server::$url);
- $response = $handler($request, ['decode_content' => true])->wait();
- // Verify that the content-length matches the encoded size.
- self::assertTrue(!$response->hasHeader('content-length') || $response->getHeaderLine('content-length') == \strlen($content));
- }
- public function testReportsOriginalSizeAndContentEncodingAfterDecoding()
- {
- Server::flush();
- $content = \gzencode('test');
- Server::enqueue([
- new Response(200, [
- 'Content-Encoding' => 'gzip',
- 'Content-Length' => \strlen($content),
- ], $content),
- ]);
- $handler = new StreamHandler();
- $request = new Request('GET', Server::$url);
- $response = $handler($request, ['decode_content' => true])->wait();
- self::assertSame(
- 'gzip',
- $response->getHeaderLine('x-encoded-content-encoding')
- );
- self::assertSame(
- \strlen($content),
- (int) $response->getHeaderLine('x-encoded-content-length')
- );
- }
- public function testDoesNotForceGzipDecode()
- {
- Server::flush();
- $content = \gzencode('test');
- Server::enqueue([
- new Response(200, [
- 'Content-Encoding' => 'gzip',
- 'Content-Length' => \strlen($content),
- ], $content),
- ]);
- $handler = new StreamHandler();
- $request = new Request('GET', Server::$url);
- $response = $handler($request, ['decode_content' => false])->wait();
- self::assertSame($content, (string) $response->getBody());
- self::assertSame('gzip', $response->getHeaderLine('content-encoding'));
- self::assertEquals(\strlen($content), $response->getHeaderLine('content-length'));
- }
- public function testProtocolVersion()
- {
- $this->queueRes();
- $handler = new StreamHandler();
- $request = new Request('GET', Server::$url, [], null, '1.0');
- $handler($request, []);
- self::assertSame('1.0', Server::received()[0]->getProtocolVersion());
- }
- protected function getSendResult(array $opts)
- {
- $this->queueRes();
- $handler = new StreamHandler();
- $opts['stream'] = true;
- $request = new Request('GET', Server::$url);
- return $handler($request, $opts)->wait();
- }
- public function testAddsProxy()
- {
- $this->expectException(ConnectException::class);
- $this->expectExceptionMessage('Connection refused');
- $this->getSendResult(['proxy' => '127.0.0.1:8125']);
- }
- public function testAddsProxyByProtocol()
- {
- $url = Server::$url;
- $res = $this->getSendResult(['proxy' => ['http' => $url]]);
- $opts = \stream_context_get_options($res->getBody()->detach());
- foreach ([\PHP_URL_HOST, \PHP_URL_PORT] as $part) {
- self::assertSame(parse_url($url, $part), parse_url($opts['http']['proxy'], $part));
- }
- }
- public function testAddsProxyButHonorsNoProxy()
- {
- $url = Server::$url;
- $res = $this->getSendResult(['proxy' => [
- 'http' => $url,
- 'no' => ['*'],
- ]]);
- $opts = \stream_context_get_options($res->getBody()->detach());
- self::assertArrayNotHasKey('proxy', $opts['http']);
- }
- public function testUsesProxy()
- {
- $this->queueRes();
- $handler = new StreamHandler();
- $request = new Request('GET', 'http://www.example.com', [], null, '1.0');
- $response = $handler($request, [
- 'proxy' => Server::$url,
- ])->wait();
- self::assertSame(200, $response->getStatusCode());
- self::assertSame('OK', $response->getReasonPhrase());
- self::assertSame('Bar', $response->getHeaderLine('Foo'));
- self::assertSame('8', $response->getHeaderLine('Content-Length'));
- self::assertSame('hi there', (string) $response->getBody());
- }
- public function testAddsTimeout()
- {
- $res = $this->getSendResult(['stream' => true, 'timeout' => 200]);
- $opts = \stream_context_get_options($res->getBody()->detach());
- self::assertEquals(200, $opts['http']['timeout']);
- }
- public function testVerifiesVerifyIsValidIfPath()
- {
- $this->expectException(RequestException::class);
- $this->expectExceptionMessage('SSL CA bundle not found: /does/not/exist');
- $this->getSendResult(['verify' => '/does/not/exist']);
- }
- public function testVerifyCanBeDisabled()
- {
- $handler = $this->getSendResult(['verify' => false]);
- self::assertInstanceOf(Response::class, $handler);
- }
- public function testVerifiesCertIfValidPath()
- {
- $this->expectException(RequestException::class);
- $this->expectExceptionMessage('SSL certificate not found: /does/not/exist');
- $this->getSendResult(['cert' => '/does/not/exist']);
- }
- public function testVerifyCanBeSetToPath()
- {
- $path = Utils::defaultCaBundle();
- $res = $this->getSendResult(['verify' => $path]);
- $opts = \stream_context_get_options($res->getBody()->detach());
- self::assertTrue($opts['ssl']['verify_peer']);
- self::assertTrue($opts['ssl']['verify_peer_name']);
- self::assertSame($path, $opts['ssl']['cafile']);
- self::assertFileExists($opts['ssl']['cafile']);
- }
- public function testUsesSystemDefaultBundle()
- {
- $res = $this->getSendResult(['verify' => true]);
- $opts = \stream_context_get_options($res->getBody()->detach());
- self::assertArrayNotHasKey('cafile', $opts['ssl']);
- }
- public function testEnsuresVerifyOptionIsValid()
- {
- $this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage('Invalid verify request option');
- $this->getSendResult(['verify' => 10]);
- }
- public function testEnsuresCryptoMethodOptionIsValid()
- {
- $this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage('Invalid crypto_method request option: unknown version provided');
- $this->getSendResult(['crypto_method' => 123]);
- }
- public function testSetsCryptoMethodTls10()
- {
- $res = $this->getSendResult(['crypto_method' => \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT]);
- $opts = \stream_context_get_options($res->getBody()->detach());
- self::assertSame(\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT, $opts['http']['crypto_method']);
- }
- public function testSetsCryptoMethodTls11()
- {
- $res = $this->getSendResult(['crypto_method' => \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT]);
- $opts = \stream_context_get_options($res->getBody()->detach());
- self::assertSame(\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT, $opts['http']['crypto_method']);
- }
- public function testSetsCryptoMethodTls12()
- {
- $res = $this->getSendResult(['crypto_method' => \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT]);
- $opts = \stream_context_get_options($res->getBody()->detach());
- self::assertSame(\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT, $opts['http']['crypto_method']);
- }
- /**
- * @requires PHP >=7.4
- */
- public function testSetsCryptoMethodTls13()
- {
- $res = $this->getSendResult(['crypto_method' => \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT]);
- $opts = \stream_context_get_options($res->getBody()->detach());
- self::assertSame(\STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT, $opts['http']['crypto_method']);
- }
- public function testCanSetPasswordWhenSettingCert()
- {
- $path = __FILE__;
- $res = $this->getSendResult(['cert' => [$path, 'foo']]);
- $opts = \stream_context_get_options($res->getBody()->detach());
- self::assertSame($path, $opts['ssl']['local_cert']);
- self::assertSame('foo', $opts['ssl']['passphrase']);
- }
- public function testDebugAttributeWritesToStream()
- {
- $this->queueRes();
- $f = \fopen('php://temp', 'w+');
- $this->getSendResult(['debug' => $f]);
- \fseek($f, 0);
- $contents = \stream_get_contents($f);
- self::assertStringContainsString('<GET http://127.0.0.1:8126/> [CONNECT]', $contents);
- self::assertStringContainsString('<GET http://127.0.0.1:8126/> [FILE_SIZE_IS]', $contents);
- self::assertStringContainsString('<GET http://127.0.0.1:8126/> [PROGRESS]', $contents);
- }
- public function testDebugAttributeWritesStreamInfoToBuffer()
- {
- $called = false;
- $this->queueRes();
- $buffer = \fopen('php://temp', 'r+');
- $this->getSendResult([
- 'progress' => static function () use (&$called) {
- $called = true;
- },
- 'debug' => $buffer,
- ]);
- \fseek($buffer, 0);
- $contents = \stream_get_contents($buffer);
- self::assertStringContainsString('<GET http://127.0.0.1:8126/> [CONNECT]', $contents);
- self::assertStringContainsString('<GET http://127.0.0.1:8126/> [FILE_SIZE_IS] message: "Content-Length: 8"', $contents);
- self::assertStringContainsString('<GET http://127.0.0.1:8126/> [PROGRESS] bytes_max: "8"', $contents);
- self::assertTrue($called);
- }
- public function testEmitsProgressInformation()
- {
- $called = [];
- $this->queueRes();
- $this->getSendResult([
- 'progress' => static function (...$args) use (&$called) {
- $called[] = $args;
- },
- ]);
- self::assertNotEmpty($called);
- self::assertEquals(8, $called[0][0]);
- self::assertEquals(0, $called[0][1]);
- }
- public function testEmitsProgressInformationAndDebugInformation()
- {
- $called = [];
- $this->queueRes();
- $buffer = \fopen('php://memory', 'w+');
- $this->getSendResult([
- 'debug' => $buffer,
- 'progress' => static function (...$args) use (&$called) {
- $called[] = $args;
- },
- ]);
- self::assertNotEmpty($called);
- self::assertEquals(8, $called[0][0]);
- self::assertEquals(0, $called[0][1]);
- \rewind($buffer);
- self::assertNotEmpty(\stream_get_contents($buffer));
- \fclose($buffer);
- }
- public function testPerformsShallowMergeOfCustomContextOptions()
- {
- $res = $this->getSendResult([
- 'stream_context' => [
- 'http' => [
- 'request_fulluri' => true,
- 'method' => 'HEAD',
- ],
- 'socket' => [
- 'bindto' => '127.0.0.1:0',
- ],
- 'ssl' => [
- 'verify_peer' => false,
- ],
- ],
- ]);
- $opts = \stream_context_get_options($res->getBody()->detach());
- self::assertSame('HEAD', $opts['http']['method']);
- self::assertTrue($opts['http']['request_fulluri']);
- self::assertSame('127.0.0.1:0', $opts['socket']['bindto']);
- self::assertFalse($opts['ssl']['verify_peer']);
- }
- public function testEnsuresThatStreamContextIsAnArray()
- {
- $this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage('stream_context must be an array');
- $this->getSendResult(['stream_context' => 'foo']);
- }
- public function testDoesNotAddContentTypeByDefault()
- {
- $this->queueRes();
- $handler = new StreamHandler();
- $request = new Request('PUT', Server::$url, ['Content-Length' => 3], 'foo');
- $handler($request, []);
- $req = Server::received()[0];
- self::assertEquals('', $req->getHeaderLine('Content-Type'));
- self::assertEquals(3, $req->getHeaderLine('Content-Length'));
- }
- public function testAddsContentLengthByDefault()
- {
- $this->queueRes();
- $handler = new StreamHandler();
- $request = new Request('PUT', Server::$url, [], 'foo');
- $handler($request, []);
- $req = Server::received()[0];
- self::assertEquals(3, $req->getHeaderLine('Content-Length'));
- }
- public function testAddsContentLengthEvenWhenEmpty()
- {
- $this->queueRes();
- $handler = new StreamHandler();
- $request = new Request('PUT', Server::$url, [], '');
- $handler($request, []);
- $req = Server::received()[0];
- self::assertEquals(0, $req->getHeaderLine('Content-Length'));
- }
- public function testSupports100Continue()
- {
- Server::flush();
- $response = new Response(200, ['Test' => 'Hello', 'Content-Length' => '4'], 'test');
- Server::enqueue([$response]);
- $request = new Request('PUT', Server::$url, ['Expect' => '100-Continue'], 'test');
- $handler = new StreamHandler();
- $response = $handler($request, [])->wait();
- self::assertSame(200, $response->getStatusCode());
- self::assertSame('Hello', $response->getHeaderLine('Test'));
- self::assertSame('4', $response->getHeaderLine('Content-Length'));
- self::assertSame('test', (string) $response->getBody());
- }
- public function testDoesSleep()
- {
- $response = new response(200);
- Server::enqueue([$response]);
- $a = new StreamHandler();
- $request = new Request('GET', Server::$url);
- $s = Utils::currentTime();
- $a($request, ['delay' => 0.1])->wait();
- self::assertGreaterThan(0.0001, Utils::currentTime() - $s);
- }
- public function testEnsuresOnHeadersIsCallable()
- {
- $req = new Request('GET', Server::$url);
- $handler = new StreamHandler();
- $this->expectException(\InvalidArgumentException::class);
- $handler($req, ['on_headers' => 'error!']);
- }
- public function testRejectsPromiseWhenOnHeadersFails()
- {
- Server::flush();
- Server::enqueue([
- new Response(200, ['X-Foo' => 'bar'], 'abc 123'),
- ]);
- $req = new Request('GET', Server::$url);
- $handler = new StreamHandler();
- $promise = $handler($req, [
- 'on_headers' => static function () {
- throw new \Exception('test');
- },
- ]);
- $this->expectException(RequestException::class);
- $this->expectExceptionMessage('An error was encountered during the on_headers event');
- $promise->wait();
- }
- public function testSuccessfullyCallsOnHeadersBeforeWritingToSink()
- {
- Server::flush();
- Server::enqueue([
- new Response(200, ['X-Foo' => 'bar'], 'abc 123'),
- ]);
- $req = new Request('GET', Server::$url);
- $got = null;
- $stream = Psr7\Utils::streamFor();
- $stream = FnStream::decorate($stream, [
- 'write' => static function ($data) use ($stream, &$got) {
- self::assertNotNull($got);
- return $stream->write($data);
- },
- ]);
- $handler = new StreamHandler();
- $promise = $handler($req, [
- 'sink' => $stream,
- 'on_headers' => static function (ResponseInterface $res) use (&$got) {
- $got = $res;
- self::assertSame('bar', $res->getHeaderLine('X-Foo'));
- },
- ]);
- $response = $promise->wait();
- self::assertSame(200, $response->getStatusCode());
- self::assertSame('bar', $response->getHeaderLine('X-Foo'));
- self::assertSame('abc 123', (string) $response->getBody());
- }
- public function testInvokesOnStatsOnSuccess()
- {
- Server::flush();
- Server::enqueue([new Psr7\Response(200)]);
- $req = new Psr7\Request('GET', Server::$url);
- $gotStats = null;
- $handler = new StreamHandler();
- $promise = $handler($req, [
- 'on_stats' => static function (TransferStats $stats) use (&$gotStats) {
- $gotStats = $stats;
- },
- ]);
- $response = $promise->wait();
- self::assertSame(200, $response->getStatusCode());
- self::assertSame(200, $gotStats->getResponse()->getStatusCode());
- self::assertSame(
- Server::$url,
- (string) $gotStats->getEffectiveUri()
- );
- self::assertSame(
- Server::$url,
- (string) $gotStats->getRequest()->getUri()
- );
- self::assertGreaterThan(0, $gotStats->getTransferTime());
- }
- public function testInvokesOnStatsOnError()
- {
- $req = new Psr7\Request('GET', 'http://127.0.0.1:123');
- $gotStats = null;
- $handler = new StreamHandler();
- $promise = $handler($req, [
- 'connect_timeout' => 0.001,
- 'timeout' => 0.001,
- 'on_stats' => static function (TransferStats $stats) use (&$gotStats) {
- $gotStats = $stats;
- },
- ]);
- $promise->wait(false);
- self::assertFalse($gotStats->hasResponse());
- self::assertSame(
- 'http://127.0.0.1:123',
- (string) $gotStats->getEffectiveUri()
- );
- self::assertSame(
- 'http://127.0.0.1:123',
- (string) $gotStats->getRequest()->getUri()
- );
- self::assertIsFloat($gotStats->getTransferTime());
- self::assertInstanceOf(
- ConnectException::class,
- $gotStats->getHandlerErrorData()
- );
- }
- public function testStreamIgnoresZeroTimeout()
- {
- Server::flush();
- Server::enqueue([new Psr7\Response(200)]);
- $req = new Psr7\Request('GET', Server::$url);
- $gotStats = null;
- $handler = new StreamHandler();
- $promise = $handler($req, [
- 'connect_timeout' => 10,
- 'timeout' => 0,
- ]);
- $response = $promise->wait();
- self::assertSame(200, $response->getStatusCode());
- }
- public function testDrainsResponseAndReadsAllContentWhenContentLengthIsZero()
- {
- Server::flush();
- Server::enqueue([
- new Response(200, [
- 'Foo' => 'Bar',
- 'Content-Length' => '0',
- ], 'hi there... This has a lot of data!'),
- ]);
- $handler = new StreamHandler();
- $request = new Request('GET', Server::$url);
- $response = $handler($request, [])->wait();
- $body = $response->getBody();
- $stream = $body->detach();
- self::assertSame('hi there... This has a lot of data!', \stream_get_contents($stream));
- \fclose($stream);
- }
- public function testHonorsReadTimeout()
- {
- Server::flush();
- $handler = new StreamHandler();
- $response = $handler(
- new Request('GET', Server::$url.'guzzle-server/read-timeout'),
- [
- RequestOptions::READ_TIMEOUT => 1,
- RequestOptions::STREAM => true,
- ]
- )->wait();
- self::assertSame(200, $response->getStatusCode());
- self::assertSame('OK', $response->getReasonPhrase());
- $body = $response->getBody()->detach();
- $line = \fgets($body);
- self::assertSame("sleeping 60 seconds ...\n", $line);
- $line = \fgets($body);
- self::assertFalse($line);
- self::assertTrue(\stream_get_meta_data($body)['timed_out']);
- self::assertFalse(\feof($body));
- }
- public function testHandlesGarbageHttpServerGracefully()
- {
- $handler = new StreamHandler();
- $this->expectException(RequestException::class);
- $this->expectExceptionMessage('An error was encountered while creating the response');
- $handler(
- new Request('GET', Server::$url.'guzzle-server/garbage'),
- [
- RequestOptions::STREAM => true,
- ]
- )->wait();
- }
- public function testHandlesInvalidStatusCodeGracefully()
- {
- $handler = new StreamHandler();
- $this->expectException(RequestException::class);
- $this->expectExceptionMessage('An error was encountered while creating the response');
- $handler(
- new Request('GET', Server::$url.'guzzle-server/bad-status'),
- [
- RequestOptions::STREAM => true,
- ]
- )->wait();
- }
- public function testRejectsNonHttpSchemes()
- {
- $handler = new StreamHandler();
- $this->expectException(RequestException::class);
- $this->expectExceptionMessage("The scheme 'file' is not supported.");
- $handler(
- new Request('GET', 'file:///etc/passwd'),
- [
- RequestOptions::STREAM => true,
- ]
- )->wait();
- }
- }
|