123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946 |
- <?php
- namespace GuzzleHttp\Test\Handler;
- use GuzzleHttp\Exception\ConnectException;
- use GuzzleHttp\Exception\RequestException;
- use GuzzleHttp\Handler;
- use GuzzleHttp\Handler\CurlFactory;
- use GuzzleHttp\Handler\EasyHandle;
- use GuzzleHttp\Promise as P;
- use GuzzleHttp\Psr7;
- use GuzzleHttp\Tests\Helpers;
- use GuzzleHttp\Tests\Server;
- use GuzzleHttp\TransferStats;
- use PHPUnit\Framework\TestCase;
- use Psr\Http\Message\ResponseInterface;
- /**
- * @covers \GuzzleHttp\Handler\CurlFactory
- */
- class CurlFactoryTest extends TestCase
- {
- public static function setUpBeforeClass(): void
- {
- $_SERVER['curl_test'] = true;
- unset($_SERVER['_curl']);
- }
- public static function tearDownAfterClass(): void
- {
- unset($_SERVER['_curl'], $_SERVER['curl_test']);
- }
- public function testCreatesCurlHandle()
- {
- Server::flush();
- Server::enqueue([
- new Psr7\Response(200, [
- 'Foo' => 'Bar',
- 'Baz' => 'bam',
- 'Content-Length' => 2,
- ], 'hi'),
- ]);
- $stream = Psr7\Utils::streamFor();
- $request = new Psr7\Request('PUT', Server::$url, [
- 'Hi' => ' 123',
- 'Content-Length' => '7',
- ], 'testing');
- $f = new Handler\CurlFactory(3);
- $result = $f->create($request, ['sink' => $stream]);
- self::assertInstanceOf(EasyHandle::class, $result);
- if (\PHP_VERSION_ID >= 80000) {
- self::assertInstanceOf(\CurlHandle::class, $result->handle);
- } else {
- self::assertIsResource($result->handle);
- }
- self::assertIsArray($result->headers);
- self::assertSame($stream, $result->sink);
- \curl_close($result->handle);
- self::assertSame('PUT', $_SERVER['_curl'][\CURLOPT_CUSTOMREQUEST]);
- self::assertSame(
- 'http://127.0.0.1:8126/',
- $_SERVER['_curl'][\CURLOPT_URL]
- );
- // Sends via post fields when the request is small enough
- self::assertSame('testing', $_SERVER['_curl'][\CURLOPT_POSTFIELDS]);
- self::assertEquals(0, $_SERVER['_curl'][\CURLOPT_RETURNTRANSFER]);
- self::assertEquals(0, $_SERVER['_curl'][\CURLOPT_HEADER]);
- self::assertSame(300, $_SERVER['_curl'][\CURLOPT_CONNECTTIMEOUT]);
- self::assertInstanceOf('Closure', $_SERVER['_curl'][\CURLOPT_HEADERFUNCTION]);
- if (\defined('CURLOPT_PROTOCOLS')) {
- self::assertSame(
- \CURLPROTO_HTTP | \CURLPROTO_HTTPS,
- $_SERVER['_curl'][\CURLOPT_PROTOCOLS]
- );
- }
- self::assertContains('Expect:', $_SERVER['_curl'][\CURLOPT_HTTPHEADER]);
- self::assertContains('Accept:', $_SERVER['_curl'][\CURLOPT_HTTPHEADER]);
- self::assertContains('Content-Type:', $_SERVER['_curl'][\CURLOPT_HTTPHEADER]);
- self::assertContains('Hi: 123', $_SERVER['_curl'][\CURLOPT_HTTPHEADER]);
- self::assertContains('Host: 127.0.0.1:8126', $_SERVER['_curl'][\CURLOPT_HTTPHEADER]);
- }
- public function testSendsHeadRequests()
- {
- Server::flush();
- Server::enqueue([new Psr7\Response()]);
- $a = new Handler\CurlMultiHandler();
- $response = $a(new Psr7\Request('HEAD', Server::$url), []);
- $response->wait();
- self::assertTrue($_SERVER['_curl'][\CURLOPT_NOBODY]);
- $checks = [\CURLOPT_READFUNCTION, \CURLOPT_FILE, \CURLOPT_INFILE];
- foreach ($checks as $check) {
- self::assertArrayNotHasKey($check, $_SERVER['_curl']);
- }
- self::assertEquals('HEAD', Server::received()[0]->getMethod());
- }
- public function testCanAddCustomCurlOptions()
- {
- Server::flush();
- Server::enqueue([new Psr7\Response()]);
- $a = new Handler\CurlMultiHandler();
- $req = new Psr7\Request('GET', Server::$url);
- $a($req, ['curl' => [\CURLOPT_LOW_SPEED_LIMIT => 10]]);
- self::assertEquals(10, $_SERVER['_curl'][\CURLOPT_LOW_SPEED_LIMIT]);
- }
- public function testCanChangeCurlOptions()
- {
- Server::flush();
- Server::enqueue([new Psr7\Response()]);
- $a = new Handler\CurlMultiHandler();
- $req = new Psr7\Request('GET', Server::$url);
- $a($req, ['curl' => [\CURLOPT_HTTP_VERSION => \CURL_HTTP_VERSION_1_0]]);
- self::assertEquals(\CURL_HTTP_VERSION_1_0, $_SERVER['_curl'][\CURLOPT_HTTP_VERSION]);
- }
- public function testValidatesVerify()
- {
- $f = new Handler\CurlFactory(3);
- $this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage('SSL CA bundle not found: /does/not/exist');
- $f->create(new Psr7\Request('GET', Server::$url), ['verify' => '/does/not/exist']);
- }
- public function testCanSetVerifyToFile()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', 'http://foo.com'), ['verify' => __FILE__]);
- self::assertEquals(__FILE__, $_SERVER['_curl'][\CURLOPT_CAINFO]);
- self::assertEquals(2, $_SERVER['_curl'][\CURLOPT_SSL_VERIFYHOST]);
- self::assertTrue($_SERVER['_curl'][\CURLOPT_SSL_VERIFYPEER]);
- }
- public function testCanSetVerifyToDir()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', 'http://foo.com'), ['verify' => __DIR__]);
- self::assertEquals(__DIR__, $_SERVER['_curl'][\CURLOPT_CAPATH]);
- self::assertEquals(2, $_SERVER['_curl'][\CURLOPT_SSL_VERIFYHOST]);
- self::assertTrue($_SERVER['_curl'][\CURLOPT_SSL_VERIFYPEER]);
- }
- public function testAddsVerifyAsTrue()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['verify' => true]);
- self::assertEquals(2, $_SERVER['_curl'][\CURLOPT_SSL_VERIFYHOST]);
- self::assertTrue($_SERVER['_curl'][\CURLOPT_SSL_VERIFYPEER]);
- self::assertArrayNotHasKey(\CURLOPT_CAINFO, $_SERVER['_curl']);
- }
- public function testCanDisableVerify()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['verify' => false]);
- self::assertEquals(0, $_SERVER['_curl'][\CURLOPT_SSL_VERIFYHOST]);
- self::assertFalse($_SERVER['_curl'][\CURLOPT_SSL_VERIFYPEER]);
- }
- public function testAddsProxy()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['proxy' => 'http://bar.com']);
- self::assertEquals('http://bar.com', $_SERVER['_curl'][\CURLOPT_PROXY]);
- }
- public function testAddsViaScheme()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), [
- 'proxy' => ['http' => 'http://bar.com', 'https' => 'https://t'],
- ]);
- self::assertEquals('http://bar.com', $_SERVER['_curl'][\CURLOPT_PROXY]);
- $this->checkNoProxyForHost('http://test.test.com', ['test.test.com'], false);
- $this->checkNoProxyForHost('http://test.test.com', ['.test.com'], false);
- $this->checkNoProxyForHost('http://test.test.com', ['*.test.com'], true);
- $this->checkNoProxyForHost('http://test.test.com', ['*'], false);
- $this->checkNoProxyForHost('http://127.0.0.1', ['127.0.0.*'], true);
- }
- private function checkNoProxyForHost($url, $noProxy, $assertUseProxy)
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', $url), [
- 'proxy' => [
- 'http' => 'http://bar.com',
- 'https' => 'https://t',
- 'no' => $noProxy,
- ],
- ]);
- if ($assertUseProxy) {
- self::assertArrayHasKey(\CURLOPT_PROXY, $_SERVER['_curl']);
- } else {
- self::assertArrayNotHasKey(\CURLOPT_PROXY, $_SERVER['_curl']);
- }
- }
- public function testUsesProxy()
- {
- Server::flush();
- Server::enqueue([
- new Psr7\Response(200, [
- 'Foo' => 'Bar',
- 'Baz' => 'bam',
- 'Content-Length' => 2,
- ], 'hi'),
- ]);
- $handler = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('GET', 'http://www.example.com', [], null, '1.0');
- $promise = $handler($request, [
- 'proxy' => Server::$url,
- ]);
- $response = $promise->wait();
- self::assertSame(200, $response->getStatusCode());
- self::assertSame('Bar', $response->getHeaderLine('Foo'));
- self::assertSame('2', $response->getHeaderLine('Content-Length'));
- self::assertSame('hi', (string) $response->getBody());
- }
- public function testValidatesCryptoMethodInvalidMethod()
- {
- $f = new Handler\CurlFactory(3);
- $this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage('Invalid crypto_method request option: unknown version provided');
- $f->create(new Psr7\Request('GET', Server::$url), ['crypto_method' => 123]);
- }
- public function testAddsCryptoMethodTls10()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['crypto_method' => \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT]);
- self::assertEquals(\CURL_SSLVERSION_TLSv1_0, $_SERVER['_curl'][\CURLOPT_SSLVERSION]);
- }
- public function testAddsCryptoMethodTls11()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['crypto_method' => \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT]);
- self::assertEquals(\CURL_SSLVERSION_TLSv1_1, $_SERVER['_curl'][\CURLOPT_SSLVERSION]);
- }
- public function testAddsCryptoMethodTls12()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['crypto_method' => \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT]);
- self::assertEquals(\CURL_SSLVERSION_TLSv1_2, $_SERVER['_curl'][\CURLOPT_SSLVERSION]);
- }
- /**
- * @requires PHP >= 7.4
- */
- public function testAddsCryptoMethodTls13()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['crypto_method' => \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT]);
- self::assertEquals(\CURL_SSLVERSION_TLSv1_3, $_SERVER['_curl'][\CURLOPT_SSLVERSION]);
- }
- public function testValidatesSslKey()
- {
- $f = new Handler\CurlFactory(3);
- $this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage('SSL private key not found: /does/not/exist');
- $f->create(new Psr7\Request('GET', Server::$url), ['ssl_key' => '/does/not/exist']);
- }
- public function testAddsSslKey()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['ssl_key' => __FILE__]);
- self::assertEquals(__FILE__, $_SERVER['_curl'][\CURLOPT_SSLKEY]);
- }
- public function testAddsSslKeyWithPassword()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['ssl_key' => [__FILE__, 'test']]);
- self::assertEquals(__FILE__, $_SERVER['_curl'][\CURLOPT_SSLKEY]);
- self::assertEquals('test', $_SERVER['_curl'][\CURLOPT_SSLKEYPASSWD]);
- }
- public function testAddsSslKeyWhenUsingArraySyntaxButNoPassword()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['ssl_key' => [__FILE__]]);
- self::assertEquals(__FILE__, $_SERVER['_curl'][\CURLOPT_SSLKEY]);
- }
- public function testValidatesCert()
- {
- $f = new Handler\CurlFactory(3);
- $this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage('SSL certificate not found: /does/not/exist');
- $f->create(new Psr7\Request('GET', Server::$url), ['cert' => '/does/not/exist']);
- }
- public function testAddsCert()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['cert' => __FILE__]);
- self::assertEquals(__FILE__, $_SERVER['_curl'][\CURLOPT_SSLCERT]);
- }
- public function testAddsCertWithPassword()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['cert' => [__FILE__, 'test']]);
- self::assertEquals(__FILE__, $_SERVER['_curl'][\CURLOPT_SSLCERT]);
- self::assertEquals('test', $_SERVER['_curl'][\CURLOPT_SSLCERTPASSWD]);
- }
- public function testAddsDerCert()
- {
- $certFile = tempnam(sys_get_temp_dir(), 'mock_test_cert');
- rename($certFile, $certFile .= '.der');
- try {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['cert' => $certFile]);
- self::assertArrayHasKey(\CURLOPT_SSLCERTTYPE, $_SERVER['_curl']);
- self::assertEquals('DER', $_SERVER['_curl'][\CURLOPT_SSLCERTTYPE]);
- } finally {
- @\unlink($certFile);
- }
- }
- public function testAddsP12Cert()
- {
- $certFile = tempnam(sys_get_temp_dir(), 'mock_test_cert');
- rename($certFile, $certFile .= '.p12');
- try {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), ['cert' => $certFile]);
- self::assertArrayHasKey(\CURLOPT_SSLCERTTYPE, $_SERVER['_curl']);
- self::assertEquals('P12', $_SERVER['_curl'][\CURLOPT_SSLCERTTYPE]);
- } finally {
- @\unlink($certFile);
- }
- }
- public function testValidatesProgress()
- {
- $f = new Handler\CurlFactory(3);
- $this->expectException(\InvalidArgumentException::class);
- $this->expectExceptionMessage('progress client option must be callable');
- $f->create(new Psr7\Request('GET', Server::$url), ['progress' => 'foo']);
- }
- public function testEmitsDebugInfoToStream()
- {
- $res = \fopen('php://temp', 'r+');
- Server::flush();
- Server::enqueue([new Psr7\Response()]);
- $a = new Handler\CurlMultiHandler();
- $response = $a(new Psr7\Request('HEAD', Server::$url), ['debug' => $res]);
- $response->wait();
- \rewind($res);
- $output = \str_replace("\r", '', \stream_get_contents($res));
- self::assertStringContainsString('> HEAD / HTTP/1.1', $output);
- self::assertStringContainsString('< HTTP/1.1 200', $output);
- \fclose($res);
- }
- public function testEmitsProgressToFunction()
- {
- Server::flush();
- Server::enqueue([new Psr7\Response()]);
- $a = new Handler\CurlMultiHandler();
- $called = [];
- $request = new Psr7\Request('HEAD', Server::$url);
- $response = $a($request, [
- 'progress' => static function (...$args) use (&$called) {
- $called[] = $args;
- },
- ]);
- $response->wait();
- self::assertNotEmpty($called);
- foreach ($called as $call) {
- self::assertCount(4, $call);
- }
- }
- private function addDecodeResponse($withEncoding = true)
- {
- $content = \gzencode('test');
- $headers = ['Content-Length' => \strlen($content)];
- if ($withEncoding) {
- $headers['Content-Encoding'] = 'gzip';
- }
- $response = new Psr7\Response(200, $headers, $content);
- Server::flush();
- Server::enqueue([$response]);
- return $content;
- }
- public function testDecodesGzippedResponses()
- {
- $this->addDecodeResponse();
- $handler = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('GET', Server::$url);
- $response = $handler($request, ['decode_content' => true]);
- $response = $response->wait();
- self::assertEquals('test', (string) $response->getBody());
- self::assertEquals('', $_SERVER['_curl'][\CURLOPT_ENCODING]);
- $sent = Server::received()[0];
- self::assertFalse($sent->hasHeader('Accept-Encoding'));
- }
- public function testReportsOriginalSizeAndContentEncodingAfterDecoding()
- {
- $this->addDecodeResponse();
- $handler = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('GET', Server::$url);
- $response = $handler($request, ['decode_content' => true]);
- $response = $response->wait();
- self::assertSame(
- 'gzip',
- $response->getHeaderLine('x-encoded-content-encoding')
- );
- self::assertSame(
- \strlen(\gzencode('test')),
- (int) $response->getHeaderLine('x-encoded-content-length')
- );
- }
- public function testDecodesGzippedResponsesWithHeader()
- {
- $this->addDecodeResponse();
- $handler = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('GET', Server::$url, ['Accept-Encoding' => 'gzip']);
- $response = $handler($request, ['decode_content' => true]);
- $response = $response->wait();
- self::assertEquals('gzip', $_SERVER['_curl'][\CURLOPT_ENCODING]);
- $sent = Server::received()[0];
- self::assertEquals('gzip', $sent->getHeaderLine('Accept-Encoding'));
- self::assertEquals('test', (string) $response->getBody());
- self::assertFalse($response->hasHeader('content-encoding'));
- self::assertTrue(
- !$response->hasHeader('content-length')
- || $response->getHeaderLine('content-length') == $response->getBody()->getSize()
- );
- }
- /**
- * https://github.com/guzzle/guzzle/issues/2799
- */
- public function testDecodesGzippedResponsesWithHeaderForHeadRequest()
- {
- $this->addDecodeResponse();
- $handler = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('HEAD', Server::$url, ['Accept-Encoding' => 'gzip']);
- $response = $handler($request, ['decode_content' => true]);
- $response = $response->wait();
- self::assertEquals('gzip', $_SERVER['_curl'][\CURLOPT_ENCODING]);
- $sent = Server::received()[0];
- self::assertEquals('gzip', $sent->getHeaderLine('Accept-Encoding'));
- // Verify that the content-length matches the encoded size.
- self::assertTrue(
- !$response->hasHeader('content-length')
- || $response->getHeaderLine('content-length') == \strlen(\gzencode('test'))
- );
- }
- public function testDoesNotForceDecode()
- {
- $content = $this->addDecodeResponse();
- $handler = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('GET', Server::$url);
- $response = $handler($request, ['decode_content' => false]);
- $response = $response->wait();
- $sent = Server::received()[0];
- self::assertFalse($sent->hasHeader('Accept-Encoding'));
- self::assertEquals($content, (string) $response->getBody());
- }
- public function testProtocolVersion()
- {
- Server::flush();
- Server::enqueue([new Psr7\Response()]);
- $a = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('GET', Server::$url, [], null, '1.0');
- $a($request, []);
- self::assertEquals(\CURL_HTTP_VERSION_1_0, $_SERVER['_curl'][\CURLOPT_HTTP_VERSION]);
- }
- public function testSavesToStream()
- {
- $stream = \fopen('php://memory', 'r+');
- $this->addDecodeResponse();
- $handler = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('GET', Server::$url);
- $response = $handler($request, [
- 'decode_content' => true,
- 'sink' => $stream,
- ]);
- $response->wait();
- \rewind($stream);
- self::assertEquals('test', \stream_get_contents($stream));
- }
- public function testSavesToGuzzleStream()
- {
- $stream = Psr7\Utils::streamFor();
- $this->addDecodeResponse();
- $handler = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('GET', Server::$url);
- $response = $handler($request, [
- 'decode_content' => true,
- 'sink' => $stream,
- ]);
- $response->wait();
- self::assertEquals('test', (string) $stream);
- }
- public function testSavesToFileOnDisk()
- {
- $tmpfile = \tempnam(\sys_get_temp_dir(), 'testfile');
- $this->addDecodeResponse();
- $handler = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('GET', Server::$url);
- $response = $handler($request, [
- 'decode_content' => true,
- 'sink' => $tmpfile,
- ]);
- $response->wait();
- self::assertStringEqualsFile($tmpfile, 'test');
- @\unlink($tmpfile);
- }
- public function testDoesNotAddMultipleContentLengthHeaders()
- {
- $this->addDecodeResponse();
- $handler = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('PUT', Server::$url, ['Content-Length' => 3], 'foo');
- $response = $handler($request, []);
- $response->wait();
- $sent = Server::received()[0];
- self::assertEquals(3, $sent->getHeaderLine('Content-Length'));
- self::assertFalse($sent->hasHeader('Transfer-Encoding'));
- self::assertEquals('foo', (string) $sent->getBody());
- }
- public function testSendsPostWithNoBodyOrDefaultContentType()
- {
- Server::flush();
- Server::enqueue([new Psr7\Response()]);
- $handler = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('POST', Server::$url);
- $response = $handler($request, []);
- $response->wait();
- $received = Server::received()[0];
- self::assertEquals('POST', $received->getMethod());
- self::assertFalse($received->hasHeader('content-type'));
- self::assertSame('0', $received->getHeaderLine('content-length'));
- }
- public function testFailsWhenCannotRewindRetryAfterNoResponse()
- {
- $factory = new Handler\CurlFactory(1);
- $stream = Psr7\Utils::streamFor('abc');
- $stream->read(1);
- $stream = new Psr7\NoSeekStream($stream);
- $request = new Psr7\Request('PUT', Server::$url, [], $stream);
- $fn = static function ($request, $options) use (&$fn, $factory) {
- $easy = $factory->create($request, $options);
- return Handler\CurlFactory::finish($fn, $easy, $factory);
- };
- $this->expectException(RequestException::class);
- $this->expectExceptionMessage('but attempting to rewind the request body failed');
- $fn($request, [])->wait();
- }
- public function testRetriesWhenBodyCanBeRewound()
- {
- $callHandler = $called = false;
- $fn = static function ($r, $options) use (&$callHandler) {
- $callHandler = true;
- return P\Create::promiseFor(new Psr7\Response());
- };
- $bd = Psr7\FnStream::decorate(Psr7\Utils::streamFor('test'), [
- 'tell' => static function () {
- return 1;
- },
- 'rewind' => static function () use (&$called) {
- $called = true;
- },
- ]);
- $factory = new Handler\CurlFactory(1);
- $req = new Psr7\Request('PUT', Server::$url, [], $bd);
- $easy = $factory->create($req, []);
- $res = Handler\CurlFactory::finish($fn, $easy, $factory);
- $res = $res->wait();
- self::assertTrue($callHandler);
- self::assertTrue($called);
- self::assertEquals('200', $res->getStatusCode());
- }
- public function testFailsWhenRetryMoreThanThreeTimes()
- {
- $factory = new Handler\CurlFactory(1);
- $call = 0;
- $fn = static function ($request, $options) use (&$mock, &$call, $factory) {
- ++$call;
- $easy = $factory->create($request, $options);
- return Handler\CurlFactory::finish($mock, $easy, $factory);
- };
- $mock = new Handler\MockHandler([$fn, $fn, $fn]);
- $p = $mock(new Psr7\Request('PUT', Server::$url, [], 'test'), []);
- $p->wait(false);
- self::assertEquals(3, $call);
- $this->expectException(RequestException::class);
- $this->expectExceptionMessage('The cURL request was retried 3 times');
- $p->wait(true);
- }
- public function testHandles100Continue()
- {
- Server::flush();
- Server::enqueue([
- new Psr7\Response(200, ['Test' => 'Hello', 'Content-Length' => 4], 'test'),
- ]);
- $request = new Psr7\Request('PUT', Server::$url, [
- 'Expect' => '100-Continue',
- ], 'test');
- $handler = new Handler\CurlMultiHandler();
- $response = $handler($request, [])->wait();
- self::assertSame(200, $response->getStatusCode());
- self::assertSame('OK', $response->getReasonPhrase());
- self::assertSame('Hello', $response->getHeaderLine('Test'));
- self::assertSame('4', $response->getHeaderLine('Content-Length'));
- self::assertSame('test', (string) $response->getBody());
- }
- public function testCreatesConnectException()
- {
- $m = new \ReflectionMethod(CurlFactory::class, 'finishError');
- $m->setAccessible(true);
- $factory = new Handler\CurlFactory(1);
- $easy = $factory->create(new Psr7\Request('GET', Server::$url), []);
- $easy->errno = \CURLE_COULDNT_CONNECT;
- $response = $m->invoke(
- null,
- static function () {
- },
- $easy,
- $factory
- );
- $this->expectException(ConnectException::class);
- $response->wait();
- }
- public function testAddsTimeouts()
- {
- $f = new Handler\CurlFactory(3);
- $f->create(new Psr7\Request('GET', Server::$url), [
- 'timeout' => 0.1,
- 'connect_timeout' => 0.2,
- ]);
- self::assertEquals(100, $_SERVER['_curl'][\CURLOPT_TIMEOUT_MS]);
- self::assertEquals(200, $_SERVER['_curl'][\CURLOPT_CONNECTTIMEOUT_MS]);
- }
- public function testAddsStreamingBody()
- {
- $f = new Handler\CurlFactory(3);
- $bd = Psr7\FnStream::decorate(Psr7\Utils::streamFor('foo'), [
- 'getSize' => static function () {
- return null;
- },
- ]);
- $request = new Psr7\Request('PUT', Server::$url, [], $bd);
- $f->create($request, []);
- self::assertEquals(1, $_SERVER['_curl'][\CURLOPT_UPLOAD]);
- self::assertIsCallable($_SERVER['_curl'][\CURLOPT_READFUNCTION]);
- }
- public function testEnsuresDirExistsBeforeThrowingWarning()
- {
- $f = new Handler\CurlFactory(3);
- $this->expectException(\RuntimeException::class);
- $this->expectExceptionMessage('Directory /does/not/exist/so does not exist for sink value of /does/not/exist/so/error.txt');
- $f->create(new Psr7\Request('GET', Server::$url), [
- 'sink' => '/does/not/exist/so/error.txt',
- ]);
- }
- public function testClosesIdleHandles()
- {
- $f = new Handler\CurlFactory(3);
- $req = new Psr7\Request('GET', Server::$url);
- $easy = $f->create($req, []);
- $h1 = $easy->handle;
- $f->release($easy);
- self::assertCount(1, Helpers::readObjectAttribute($f, 'handles'));
- $easy = $f->create($req, []);
- self::assertSame($easy->handle, $h1);
- $easy2 = $f->create($req, []);
- $easy3 = $f->create($req, []);
- $easy4 = $f->create($req, []);
- $f->release($easy);
- self::assertCount(1, Helpers::readObjectAttribute($f, 'handles'));
- $f->release($easy2);
- self::assertCount(2, Helpers::readObjectAttribute($f, 'handles'));
- $f->release($easy3);
- self::assertCount(3, Helpers::readObjectAttribute($f, 'handles'));
- $f->release($easy4);
- self::assertCount(3, Helpers::readObjectAttribute($f, 'handles'));
- }
- public function testRejectsPromiseWhenCreateResponseFails()
- {
- Server::flush();
- Server::enqueueRaw(999, 'Incorrect', ['X-Foo' => 'bar'], 'abc 123');
- $req = new Psr7\Request('GET', Server::$url);
- $handler = new Handler\CurlHandler();
- $promise = $handler($req, []);
- $this->expectException(\GuzzleHttp\Exception\RequestException::class);
- $this->expectExceptionMessage('An error was encountered while creating the response');
- $promise->wait();
- }
- public function testEnsuresOnHeadersIsCallable()
- {
- $req = new Psr7\Request('GET', Server::$url);
- $handler = new Handler\CurlHandler();
- $this->expectException(\InvalidArgumentException::class);
- $handler($req, ['on_headers' => 'error!']);
- }
- public function testRejectsPromiseWhenOnHeadersFails()
- {
- Server::flush();
- Server::enqueue([
- new Psr7\Response(200, ['X-Foo' => 'bar'], 'abc 123'),
- ]);
- $req = new Psr7\Request('GET', Server::$url);
- $handler = new Handler\CurlHandler();
- $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 Psr7\Response(200, ['X-Foo' => 'bar'], 'abc 123'),
- ]);
- $req = new Psr7\Request('GET', Server::$url);
- $got = null;
- $stream = Psr7\Utils::streamFor();
- $stream = Psr7\FnStream::decorate($stream, [
- 'write' => static function ($data) use ($stream, &$got) {
- self::assertNotNull($got);
- return $stream->write($data);
- },
- ]);
- $handler = new Handler\CurlHandler();
- $promise = $handler($req, [
- 'sink' => $stream,
- 'on_headers' => static function (ResponseInterface $res) use (&$got) {
- $got = $res;
- self::assertEquals('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 Handler\CurlHandler();
- $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());
- self::assertArrayHasKey('appconnect_time', $gotStats->getHandlerStats());
- }
- public function testInvokesOnStatsOnError()
- {
- $req = new Psr7\Request('GET', 'http://127.0.0.1:123');
- $gotStats = null;
- $handler = new Handler\CurlHandler();
- $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::assertIsInt($gotStats->getHandlerErrorData());
- self::assertArrayHasKey('appconnect_time', $gotStats->getHandlerStats());
- }
- public function testRewindsBodyIfPossible()
- {
- $body = Psr7\Utils::streamFor(\str_repeat('x', 1024 * 1024 * 2));
- $body->seek(1024 * 1024);
- self::assertSame(1024 * 1024, $body->tell());
- $req = new Psr7\Request('POST', 'https://www.example.com', [
- 'Content-Length' => 1024 * 1024 * 2,
- ], $body);
- $factory = new CurlFactory(1);
- $factory->create($req, []);
- self::assertSame(0, $body->tell());
- }
- public function testDoesNotRewindUnseekableBody()
- {
- $body = Psr7\Utils::streamFor(\str_repeat('x', 1024 * 1024 * 2));
- $body->seek(1024 * 1024);
- $body = new Psr7\NoSeekStream($body);
- self::assertSame(1024 * 1024, $body->tell());
- $req = new Psr7\Request('POST', 'https://www.example.com', [
- 'Content-Length' => 1024 * 1024,
- ], $body);
- $factory = new CurlFactory(1);
- $factory->create($req, []);
- self::assertSame(1024 * 1024, $body->tell());
- }
- public function testRelease()
- {
- $factory = new CurlFactory(1);
- $easyHandle = new EasyHandle();
- $easyHandle->handle = \curl_init();
- self::assertEmpty($factory->release($easyHandle));
- }
- /**
- * https://github.com/guzzle/guzzle/issues/2735
- */
- public function testBodyEofOnWindows()
- {
- $expectedLength = 4097;
- Server::flush();
- Server::enqueue([
- new Psr7\Response(200, [
- 'Content-Length' => $expectedLength,
- ], \str_repeat('x', $expectedLength)),
- ]);
- $handler = new Handler\CurlMultiHandler();
- $request = new Psr7\Request('GET', Server::$url);
- $promise = $handler($request, []);
- $response = $promise->wait();
- $body = $response->getBody();
- $actualLength = 0;
- while (!$body->eof()) {
- $chunk = $body->read(4096);
- $actualLength += \strlen($chunk);
- }
- self::assertSame($expectedLength, $actualLength);
- }
- public function testHandlesGarbageHttpServerGracefully()
- {
- $a = new Handler\CurlMultiHandler();
- $this->expectException(RequestException::class);
- $this->expectExceptionMessage('cURL error 1: Received HTTP/0.9 when not allowed');
- $a(new Psr7\Request('GET', Server::$url.'guzzle-server/garbage'), [])->wait();
- }
- public function testHandlesInvalidStatusCodeGracefully()
- {
- $a = new Handler\CurlMultiHandler();
- $this->expectException(RequestException::class);
- $this->expectExceptionMessage('An error was encountered while creating the response');
- $a(new Psr7\Request('GET', Server::$url.'guzzle-server/bad-status'), [])->wait();
- }
- }
|