PluginProbe
StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more / 2.5.7
StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more v2.5.7
3.7.2 3.7.1 3.7.0 3.6.0 3.6.1 3.5.2 trunk 2.0 2.1 2.2 2.3 2.4 2.4.1 2.4.2 2.4.3 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.6.0 2.6.1 All 73 releases
stockpack / vendor / guzzlehttp / guzzle / tests / Handler / CurlFactoryTest.php

CurlFactoryTest.php in StockPack – Stock photos and AI images from Unsplash, Adobe Stock, Freepik and more 2.5.7, at vendor/guzzlehttp/guzzle/tests/Handler/CurlFactoryTest.php

771 lines 27.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace GuzzleHttp\Test\Handler;
3
4 use GuzzleHttp\Handler;
5 use GuzzleHttp\Handler\CurlFactory;
6 use GuzzleHttp\Handler\EasyHandle;
7 use GuzzleHttp\Psr7;
8 use GuzzleHttp\Tests\Server;
9 use GuzzleHttp\TransferStats;
10 use PHPUnit\Framework\TestCase;
11 use Psr\Http\Message\ResponseInterface;
12
13 /**
14 * @covers \GuzzleHttp\Handler\CurlFactory
15 */
16 class CurlFactoryTest extends TestCase
17 {
18 public static function setUpBeforeClass()
19 {
20 $_SERVER['curl_test'] = true;
21 unset($_SERVER['_curl']);
22 }
23
24 public static function tearDownAfterClass()
25 {
26 unset($_SERVER['_curl'], $_SERVER['curl_test']);
27 }
28
29 public function testCreatesCurlHandle()
30 {
31 Server::flush();
32 Server::enqueue([
33 new Psr7\Response(200, [
34 'Foo' => 'Bar',
35 'Baz' => 'bam',
36 'Content-Length' => 2,
37 ], 'hi')
38 ]);
39 $stream = Psr7\stream_for();
40 $request = new Psr7\Request('PUT', Server::$url, [
41 'Hi' => ' 123',
42 'Content-Length' => '7'
43 ], 'testing');
44 $f = new Handler\CurlFactory(3);
45 $result = $f->create($request, ['sink' => $stream]);
46 self::assertInstanceOf(EasyHandle::class, $result);
47 self::assertInternalType('resource', $result->handle);
48 self::assertInternalType('array', $result->headers);
49 self::assertSame($stream, $result->sink);
50 curl_close($result->handle);
51 self::assertSame('PUT', $_SERVER['_curl'][CURLOPT_CUSTOMREQUEST]);
52 self::assertSame(
53 'http://127.0.0.1:8126/',
54 $_SERVER['_curl'][CURLOPT_URL]
55 );
56 // Sends via post fields when the request is small enough
57 self::assertSame('testing', $_SERVER['_curl'][CURLOPT_POSTFIELDS]);
58 self::assertEquals(0, $_SERVER['_curl'][CURLOPT_RETURNTRANSFER]);
59 self::assertEquals(0, $_SERVER['_curl'][CURLOPT_HEADER]);
60 self::assertSame(150, $_SERVER['_curl'][CURLOPT_CONNECTTIMEOUT]);
61 self::assertInstanceOf('Closure', $_SERVER['_curl'][CURLOPT_HEADERFUNCTION]);
62 if (defined('CURLOPT_PROTOCOLS')) {
63 self::assertSame(
64 CURLPROTO_HTTP | CURLPROTO_HTTPS,
65 $_SERVER['_curl'][CURLOPT_PROTOCOLS]
66 );
67 }
68 self::assertContains('Expect:', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
69 self::assertContains('Accept:', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
70 self::assertContains('Content-Type:', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
71 self::assertContains('Hi: 123', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
72 self::assertContains('Host: 127.0.0.1:8126', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
73 }
74
75 public function testSendsHeadRequests()
76 {
77 Server::flush();
78 Server::enqueue([new Psr7\Response()]);
79 $a = new Handler\CurlMultiHandler();
80 $response = $a(new Psr7\Request('HEAD', Server::$url), []);
81 $response->wait();
82 self::assertEquals(true, $_SERVER['_curl'][CURLOPT_NOBODY]);
83 $checks = [CURLOPT_WRITEFUNCTION, CURLOPT_READFUNCTION, CURLOPT_INFILE];
84 foreach ($checks as $check) {
85 self::assertArrayNotHasKey($check, $_SERVER['_curl']);
86 }
87 self::assertEquals('HEAD', Server::received()[0]->getMethod());
88 }
89
90 public function testCanAddCustomCurlOptions()
91 {
92 Server::flush();
93 Server::enqueue([new Psr7\Response()]);
94 $a = new Handler\CurlMultiHandler();
95 $req = new Psr7\Request('GET', Server::$url);
96 $a($req, ['curl' => [CURLOPT_LOW_SPEED_LIMIT => 10]]);
97 self::assertEquals(10, $_SERVER['_curl'][CURLOPT_LOW_SPEED_LIMIT]);
98 }
99
100 public function testCanChangeCurlOptions()
101 {
102 Server::flush();
103 Server::enqueue([new Psr7\Response()]);
104 $a = new Handler\CurlMultiHandler();
105 $req = new Psr7\Request('GET', Server::$url);
106 $a($req, ['curl' => [CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_0]]);
107 self::assertEquals(CURL_HTTP_VERSION_1_0, $_SERVER['_curl'][CURLOPT_HTTP_VERSION]);
108 }
109
110 /**
111 * @expectedException \InvalidArgumentException
112 * @expectedExceptionMessage SSL CA bundle not found: /does/not/exist
113 */
114 public function testValidatesVerify()
115 {
116 $f = new Handler\CurlFactory(3);
117 $f->create(new Psr7\Request('GET', Server::$url), ['verify' => '/does/not/exist']);
118 }
119
120 public function testCanSetVerifyToFile()
121 {
122 $f = new Handler\CurlFactory(3);
123 $f->create(new Psr7\Request('GET', 'http://foo.com'), ['verify' => __FILE__]);
124 self::assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_CAINFO]);
125 self::assertEquals(2, $_SERVER['_curl'][CURLOPT_SSL_VERIFYHOST]);
126 self::assertEquals(true, $_SERVER['_curl'][CURLOPT_SSL_VERIFYPEER]);
127 }
128
129 public function testCanSetVerifyToDir()
130 {
131 $f = new Handler\CurlFactory(3);
132 $f->create(new Psr7\Request('GET', 'http://foo.com'), ['verify' => __DIR__]);
133 self::assertEquals(__DIR__, $_SERVER['_curl'][CURLOPT_CAPATH]);
134 self::assertEquals(2, $_SERVER['_curl'][CURLOPT_SSL_VERIFYHOST]);
135 self::assertEquals(true, $_SERVER['_curl'][CURLOPT_SSL_VERIFYPEER]);
136 }
137
138 public function testAddsVerifyAsTrue()
139 {
140 $f = new Handler\CurlFactory(3);
141 $f->create(new Psr7\Request('GET', Server::$url), ['verify' => true]);
142 self::assertEquals(2, $_SERVER['_curl'][CURLOPT_SSL_VERIFYHOST]);
143 self::assertEquals(true, $_SERVER['_curl'][CURLOPT_SSL_VERIFYPEER]);
144 self::assertArrayNotHasKey(CURLOPT_CAINFO, $_SERVER['_curl']);
145 }
146
147 public function testCanDisableVerify()
148 {
149 $f = new Handler\CurlFactory(3);
150 $f->create(new Psr7\Request('GET', Server::$url), ['verify' => false]);
151 self::assertEquals(0, $_SERVER['_curl'][CURLOPT_SSL_VERIFYHOST]);
152 self::assertEquals(false, $_SERVER['_curl'][CURLOPT_SSL_VERIFYPEER]);
153 }
154
155 public function testAddsProxy()
156 {
157 $f = new Handler\CurlFactory(3);
158 $f->create(new Psr7\Request('GET', Server::$url), ['proxy' => 'http://bar.com']);
159 self::assertEquals('http://bar.com', $_SERVER['_curl'][CURLOPT_PROXY]);
160 }
161
162 public function testAddsViaScheme()
163 {
164 $f = new Handler\CurlFactory(3);
165 $f->create(new Psr7\Request('GET', Server::$url), [
166 'proxy' => ['http' => 'http://bar.com', 'https' => 'https://t'],
167 ]);
168 self::assertEquals('http://bar.com', $_SERVER['_curl'][CURLOPT_PROXY]);
169 $this->checkNoProxyForHost('http://test.test.com', ['test.test.com'], false);
170 $this->checkNoProxyForHost('http://test.test.com', ['.test.com'], false);
171 $this->checkNoProxyForHost('http://test.test.com', ['*.test.com'], true);
172 $this->checkNoProxyForHost('http://test.test.com', ['*'], false);
173 $this->checkNoProxyForHost('http://127.0.0.1', ['127.0.0.*'], true);
174 }
175
176 private function checkNoProxyForHost($url, $noProxy, $assertUseProxy)
177 {
178 $f = new Handler\CurlFactory(3);
179 $f->create(new Psr7\Request('GET', $url), [
180 'proxy' => [
181 'http' => 'http://bar.com',
182 'https' => 'https://t',
183 'no' => $noProxy
184 ],
185 ]);
186 if ($assertUseProxy) {
187 self::assertArrayHasKey(CURLOPT_PROXY, $_SERVER['_curl']);
188 } else {
189 self::assertArrayNotHasKey(CURLOPT_PROXY, $_SERVER['_curl']);
190 }
191 }
192
193
194 /**
195 * @expectedException \InvalidArgumentException
196 * @expectedExceptionMessage SSL private key not found: /does/not/exist
197 */
198 public function testValidatesSslKey()
199 {
200 $f = new Handler\CurlFactory(3);
201 $f->create(new Psr7\Request('GET', Server::$url), ['ssl_key' => '/does/not/exist']);
202 }
203
204 public function testAddsSslKey()
205 {
206 $f = new Handler\CurlFactory(3);
207 $f->create(new Psr7\Request('GET', Server::$url), ['ssl_key' => __FILE__]);
208 self::assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLKEY]);
209 }
210
211 public function testAddsSslKeyWithPassword()
212 {
213 $f = new Handler\CurlFactory(3);
214 $f->create(new Psr7\Request('GET', Server::$url), ['ssl_key' => [__FILE__, 'test']]);
215 self::assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLKEY]);
216 self::assertEquals('test', $_SERVER['_curl'][CURLOPT_SSLKEYPASSWD]);
217 }
218
219 public function testAddsSslKeyWhenUsingArraySyntaxButNoPassword()
220 {
221 $f = new Handler\CurlFactory(3);
222 $f->create(new Psr7\Request('GET', Server::$url), ['ssl_key' => [__FILE__]]);
223
224 self::assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLKEY]);
225 }
226
227 /**
228 * @expectedException \InvalidArgumentException
229 * @expectedExceptionMessage SSL certificate not found: /does/not/exist
230 */
231 public function testValidatesCert()
232 {
233 $f = new Handler\CurlFactory(3);
234 $f->create(new Psr7\Request('GET', Server::$url), ['cert' => '/does/not/exist']);
235 }
236
237 public function testAddsCert()
238 {
239 $f = new Handler\CurlFactory(3);
240 $f->create(new Psr7\Request('GET', Server::$url), ['cert' => __FILE__]);
241 self::assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLCERT]);
242 }
243
244 public function testAddsCertWithPassword()
245 {
246 $f = new Handler\CurlFactory(3);
247 $f->create(new Psr7\Request('GET', Server::$url), ['cert' => [__FILE__, 'test']]);
248 self::assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLCERT]);
249 self::assertEquals('test', $_SERVER['_curl'][CURLOPT_SSLCERTPASSWD]);
250 }
251
252 /**
253 * @expectedException \InvalidArgumentException
254 * @expectedExceptionMessage progress client option must be callable
255 */
256 public function testValidatesProgress()
257 {
258 $f = new Handler\CurlFactory(3);
259 $f->create(new Psr7\Request('GET', Server::$url), ['progress' => 'foo']);
260 }
261
262 public function testEmitsDebugInfoToStream()
263 {
264 $res = fopen('php://memory', 'r+');
265 Server::flush();
266 Server::enqueue([new Psr7\Response()]);
267 $a = new Handler\CurlMultiHandler();
268 $response = $a(new Psr7\Request('HEAD', Server::$url), ['debug' => $res]);
269 $response->wait();
270 rewind($res);
271 $output = str_replace("\r", '', stream_get_contents($res));
272 self::assertContains("> HEAD / HTTP/1.1", $output);
273 self::assertContains("< HTTP/1.1 200", $output);
274 fclose($res);
275 }
276
277 public function testEmitsProgressToFunction()
278 {
279 Server::flush();
280 Server::enqueue([new Psr7\Response()]);
281 $a = new Handler\CurlMultiHandler();
282 $called = [];
283 $request = new Psr7\Request('HEAD', Server::$url);
284 $response = $a($request, [
285 'progress' => function () use (&$called) {
286 $called[] = func_get_args();
287 },
288 ]);
289 $response->wait();
290 self::assertNotEmpty($called);
291 foreach ($called as $call) {
292 self::assertCount(4, $call);
293 }
294 }
295
296 private function addDecodeResponse($withEncoding = true)
297 {
298 $content = gzencode('test');
299 $headers = ['Content-Length' => strlen($content)];
300 if ($withEncoding) {
301 $headers['Content-Encoding'] = 'gzip';
302 }
303 $response = new Psr7\Response(200, $headers, $content);
304 Server::flush();
305 Server::enqueue([$response]);
306 return $content;
307 }
308
309 public function testDecodesGzippedResponses()
310 {
311 $this->addDecodeResponse();
312 $handler = new Handler\CurlMultiHandler();
313 $request = new Psr7\Request('GET', Server::$url);
314 $response = $handler($request, ['decode_content' => true]);
315 $response = $response->wait();
316 self::assertEquals('test', (string) $response->getBody());
317 self::assertEquals('', $_SERVER['_curl'][CURLOPT_ENCODING]);
318 $sent = Server::received()[0];
319 self::assertFalse($sent->hasHeader('Accept-Encoding'));
320 }
321
322 public function testReportsOriginalSizeAndContentEncodingAfterDecoding()
323 {
324 $this->addDecodeResponse();
325 $handler = new Handler\CurlMultiHandler();
326 $request = new Psr7\Request('GET', Server::$url);
327 $response = $handler($request, ['decode_content' => true]);
328 $response = $response->wait();
329 self::assertSame(
330 'gzip',
331 $response->getHeaderLine('x-encoded-content-encoding')
332 );
333 self::assertSame(
334 strlen(gzencode('test')),
335 (int) $response->getHeaderLine('x-encoded-content-length')
336 );
337 }
338
339 public function testDecodesGzippedResponsesWithHeader()
340 {
341 $this->addDecodeResponse();
342 $handler = new Handler\CurlMultiHandler();
343 $request = new Psr7\Request('GET', Server::$url, ['Accept-Encoding' => 'gzip']);
344 $response = $handler($request, ['decode_content' => true]);
345 $response = $response->wait();
346 self::assertEquals('gzip', $_SERVER['_curl'][CURLOPT_ENCODING]);
347 $sent = Server::received()[0];
348 self::assertEquals('gzip', $sent->getHeaderLine('Accept-Encoding'));
349 self::assertEquals('test', (string) $response->getBody());
350 self::assertFalse($response->hasHeader('content-encoding'));
351 self::assertTrue(
352 !$response->hasHeader('content-length') ||
353 $response->getHeaderLine('content-length') == $response->getBody()->getSize()
354 );
355 }
356
357 public function testDoesNotForceDecode()
358 {
359 $content = $this->addDecodeResponse();
360 $handler = new Handler\CurlMultiHandler();
361 $request = new Psr7\Request('GET', Server::$url);
362 $response = $handler($request, ['decode_content' => false]);
363 $response = $response->wait();
364 $sent = Server::received()[0];
365 self::assertFalse($sent->hasHeader('Accept-Encoding'));
366 self::assertEquals($content, (string) $response->getBody());
367 }
368
369 public function testProtocolVersion()
370 {
371 Server::flush();
372 Server::enqueue([new Psr7\Response()]);
373 $a = new Handler\CurlMultiHandler();
374 $request = new Psr7\Request('GET', Server::$url, [], null, '1.0');
375 $a($request, []);
376 self::assertEquals(CURL_HTTP_VERSION_1_0, $_SERVER['_curl'][CURLOPT_HTTP_VERSION]);
377 }
378
379 public function testSavesToStream()
380 {
381 $stream = fopen('php://memory', 'r+');
382 $this->addDecodeResponse();
383 $handler = new Handler\CurlMultiHandler();
384 $request = new Psr7\Request('GET', Server::$url);
385 $response = $handler($request, [
386 'decode_content' => true,
387 'sink' => $stream,
388 ]);
389 $response->wait();
390 rewind($stream);
391 self::assertEquals('test', stream_get_contents($stream));
392 }
393
394 public function testSavesToGuzzleStream()
395 {
396 $stream = Psr7\stream_for();
397 $this->addDecodeResponse();
398 $handler = new Handler\CurlMultiHandler();
399 $request = new Psr7\Request('GET', Server::$url);
400 $response = $handler($request, [
401 'decode_content' => true,
402 'sink' => $stream,
403 ]);
404 $response->wait();
405 self::assertEquals('test', (string) $stream);
406 }
407
408 public function testSavesToFileOnDisk()
409 {
410 $tmpfile = tempnam(sys_get_temp_dir(), 'testfile');
411 $this->addDecodeResponse();
412 $handler = new Handler\CurlMultiHandler();
413 $request = new Psr7\Request('GET', Server::$url);
414 $response = $handler($request, [
415 'decode_content' => true,
416 'sink' => $tmpfile,
417 ]);
418 $response->wait();
419 self::assertStringEqualsFile($tmpfile, 'test');
420 unlink($tmpfile);
421 }
422
423 public function testDoesNotAddMultipleContentLengthHeaders()
424 {
425 $this->addDecodeResponse();
426 $handler = new Handler\CurlMultiHandler();
427 $request = new Psr7\Request('PUT', Server::$url, ['Content-Length' => 3], 'foo');
428 $response = $handler($request, []);
429 $response->wait();
430 $sent = Server::received()[0];
431 self::assertEquals(3, $sent->getHeaderLine('Content-Length'));
432 self::assertFalse($sent->hasHeader('Transfer-Encoding'));
433 self::assertEquals('foo', (string) $sent->getBody());
434 }
435
436 public function testSendsPostWithNoBodyOrDefaultContentType()
437 {
438 Server::flush();
439 Server::enqueue([new Psr7\Response()]);
440 $handler = new Handler\CurlMultiHandler();
441 $request = new Psr7\Request('POST', Server::$url);
442 $response = $handler($request, []);
443 $response->wait();
444 $received = Server::received()[0];
445 self::assertEquals('POST', $received->getMethod());
446 self::assertFalse($received->hasHeader('content-type'));
447 self::assertSame('0', $received->getHeaderLine('content-length'));
448 }
449
450 /**
451 * @expectedException \GuzzleHttp\Exception\RequestException
452 * @expectedExceptionMessage but attempting to rewind the request body failed
453 */
454 public function testFailsWhenCannotRewindRetryAfterNoResponse()
455 {
456 $factory = new Handler\CurlFactory(1);
457 $stream = Psr7\stream_for('abc');
458 $stream->read(1);
459 $stream = new Psr7\NoSeekStream($stream);
460 $request = new Psr7\Request('PUT', Server::$url, [], $stream);
461 $fn = function ($request, $options) use (&$fn, $factory) {
462 $easy = $factory->create($request, $options);
463 return Handler\CurlFactory::finish($fn, $easy, $factory);
464 };
465 $fn($request, [])->wait();
466 }
467
468 public function testRetriesWhenBodyCanBeRewound()
469 {
470 $callHandler = $called = false;
471
472 $fn = function ($r, $options) use (&$callHandler) {
473 $callHandler = true;
474 return \GuzzleHttp\Promise\promise_for(new Psr7\Response());
475 };
476
477 $bd = Psr7\FnStream::decorate(Psr7\stream_for('test'), [
478 'tell' => function () {
479 return 1;
480 },
481 'rewind' => function () use (&$called) {
482 $called = true;
483 }
484 ]);
485
486 $factory = new Handler\CurlFactory(1);
487 $req = new Psr7\Request('PUT', Server::$url, [], $bd);
488 $easy = $factory->create($req, []);
489 $res = Handler\CurlFactory::finish($fn, $easy, $factory);
490 $res = $res->wait();
491 self::assertTrue($callHandler);
492 self::assertTrue($called);
493 self::assertEquals('200', $res->getStatusCode());
494 }
495
496 /**
497 * @expectedException \GuzzleHttp\Exception\RequestException
498 * @expectedExceptionMessage The cURL request was retried 3 times
499 */
500 public function testFailsWhenRetryMoreThanThreeTimes()
501 {
502 $factory = new Handler\CurlFactory(1);
503 $call = 0;
504 $fn = function ($request, $options) use (&$mock, &$call, $factory) {
505 $call++;
506 $easy = $factory->create($request, $options);
507 return Handler\CurlFactory::finish($mock, $easy, $factory);
508 };
509 $mock = new Handler\MockHandler([$fn, $fn, $fn]);
510 $p = $mock(new Psr7\Request('PUT', Server::$url, [], 'test'), []);
511 $p->wait(false);
512 self::assertEquals(3, $call);
513 $p->wait(true);
514 }
515
516 public function testHandles100Continue()
517 {
518 Server::flush();
519 Server::enqueue([
520 new Psr7\Response(200, ['Test' => 'Hello', 'Content-Length' => 4], 'test'),
521 ]);
522 $request = new Psr7\Request('PUT', Server::$url, [
523 'Expect' => '100-Continue'
524 ], 'test');
525 $handler = new Handler\CurlMultiHandler();
526 $response = $handler($request, [])->wait();
527 self::assertSame(200, $response->getStatusCode());
528 self::assertSame('OK', $response->getReasonPhrase());
529 self::assertSame('Hello', $response->getHeaderLine('Test'));
530 self::assertSame('4', $response->getHeaderLine('Content-Length'));
531 self::assertSame('test', (string) $response->getBody());
532 }
533
534 /**
535 * @expectedException \GuzzleHttp\Exception\ConnectException
536 */
537 public function testCreatesConnectException()
538 {
539 $m = new \ReflectionMethod(CurlFactory::class, 'finishError');
540 $m->setAccessible(true);
541 $factory = new Handler\CurlFactory(1);
542 $easy = $factory->create(new Psr7\Request('GET', Server::$url), []);
543 $easy->errno = CURLE_COULDNT_CONNECT;
544 $response = $m->invoke(
545 null,
546 function () {
547 },
548 $easy,
549 $factory
550 );
551 $response->wait();
552 }
553
554 public function testAddsTimeouts()
555 {
556 $f = new Handler\CurlFactory(3);
557 $f->create(new Psr7\Request('GET', Server::$url), [
558 'timeout' => 0.1,
559 'connect_timeout' => 0.2
560 ]);
561 self::assertEquals(100, $_SERVER['_curl'][CURLOPT_TIMEOUT_MS]);
562 self::assertEquals(200, $_SERVER['_curl'][CURLOPT_CONNECTTIMEOUT_MS]);
563 }
564
565 public function testAddsStreamingBody()
566 {
567 $f = new Handler\CurlFactory(3);
568 $bd = Psr7\FnStream::decorate(Psr7\stream_for('foo'), [
569 'getSize' => function () {
570 return null;
571 }
572 ]);
573 $request = new Psr7\Request('PUT', Server::$url, [], $bd);
574 $f->create($request, []);
575 self::assertEquals(1, $_SERVER['_curl'][CURLOPT_UPLOAD]);
576 self::assertInternalType('callable', $_SERVER['_curl'][CURLOPT_READFUNCTION]);
577 }
578
579 /**
580 * @expectedException \RuntimeException
581 * @expectedExceptionMessage Directory /does/not/exist/so does not exist for sink value of /does/not/exist/so/error.txt
582 */
583 public function testEnsuresDirExistsBeforeThrowingWarning()
584 {
585 $f = new Handler\CurlFactory(3);
586 $f->create(new Psr7\Request('GET', Server::$url), [
587 'sink' => '/does/not/exist/so/error.txt'
588 ]);
589 }
590
591 public function testClosesIdleHandles()
592 {
593 $f = new Handler\CurlFactory(3);
594 $req = new Psr7\Request('GET', Server::$url);
595 $easy = $f->create($req, []);
596 $h1 = $easy->handle;
597 $f->release($easy);
598 self::assertCount(1, self::readAttribute($f, 'handles'));
599 $easy = $f->create($req, []);
600 self::assertSame($easy->handle, $h1);
601 $easy2 = $f->create($req, []);
602 $easy3 = $f->create($req, []);
603 $easy4 = $f->create($req, []);
604 $f->release($easy);
605 self::assertCount(1, self::readAttribute($f, 'handles'));
606 $f->release($easy2);
607 self::assertCount(2, self::readAttribute($f, 'handles'));
608 $f->release($easy3);
609 self::assertCount(3, self::readAttribute($f, 'handles'));
610 $f->release($easy4);
611 self::assertCount(3, self::readAttribute($f, 'handles'));
612 }
613
614 /**
615 * @expectedException \InvalidArgumentException
616 */
617 public function testEnsuresOnHeadersIsCallable()
618 {
619 $req = new Psr7\Request('GET', Server::$url);
620 $handler = new Handler\CurlHandler();
621 $handler($req, ['on_headers' => 'error!']);
622 }
623
624 /**
625 * @expectedException \GuzzleHttp\Exception\RequestException
626 * @expectedExceptionMessage An error was encountered during the on_headers event
627 * @expectedExceptionMessage test
628 */
629 public function testRejectsPromiseWhenOnHeadersFails()
630 {
631 Server::flush();
632 Server::enqueue([
633 new Psr7\Response(200, ['X-Foo' => 'bar'], 'abc 123')
634 ]);
635 $req = new Psr7\Request('GET', Server::$url);
636 $handler = new Handler\CurlHandler();
637 $promise = $handler($req, [
638 'on_headers' => function () {
639 throw new \Exception('test');
640 }
641 ]);
642 $promise->wait();
643 }
644
645 public function testSuccessfullyCallsOnHeadersBeforeWritingToSink()
646 {
647 Server::flush();
648 Server::enqueue([
649 new Psr7\Response(200, ['X-Foo' => 'bar'], 'abc 123')
650 ]);
651 $req = new Psr7\Request('GET', Server::$url);
652 $got = null;
653
654 $stream = Psr7\stream_for();
655 $stream = Psr7\FnStream::decorate($stream, [
656 'write' => function ($data) use ($stream, &$got) {
657 self::assertNotNull($got);
658 return $stream->write($data);
659 }
660 ]);
661
662 $handler = new Handler\CurlHandler();
663 $promise = $handler($req, [
664 'sink' => $stream,
665 'on_headers' => function (ResponseInterface $res) use (&$got) {
666 $got = $res;
667 self::assertEquals('bar', $res->getHeaderLine('X-Foo'));
668 }
669 ]);
670
671 $response = $promise->wait();
672 self::assertSame(200, $response->getStatusCode());
673 self::assertSame('bar', $response->getHeaderLine('X-Foo'));
674 self::assertSame('abc 123', (string) $response->getBody());
675 }
676
677 public function testInvokesOnStatsOnSuccess()
678 {
679 Server::flush();
680 Server::enqueue([new Psr7\Response(200)]);
681 $req = new Psr7\Request('GET', Server::$url);
682 $gotStats = null;
683 $handler = new Handler\CurlHandler();
684 $promise = $handler($req, [
685 'on_stats' => function (TransferStats $stats) use (&$gotStats) {
686 $gotStats = $stats;
687 }
688 ]);
689 $response = $promise->wait();
690 self::assertSame(200, $response->getStatusCode());
691 self::assertSame(200, $gotStats->getResponse()->getStatusCode());
692 self::assertSame(
693 Server::$url,
694 (string) $gotStats->getEffectiveUri()
695 );
696 self::assertSame(
697 Server::$url,
698 (string) $gotStats->getRequest()->getUri()
699 );
700 self::assertGreaterThan(0, $gotStats->getTransferTime());
701 self::assertArrayHasKey('appconnect_time', $gotStats->getHandlerStats());
702 }
703
704 public function testInvokesOnStatsOnError()
705 {
706 $req = new Psr7\Request('GET', 'http://127.0.0.1:123');
707 $gotStats = null;
708 $handler = new Handler\CurlHandler();
709 $promise = $handler($req, [
710 'connect_timeout' => 0.001,
711 'timeout' => 0.001,
712 'on_stats' => function (TransferStats $stats) use (&$gotStats) {
713 $gotStats = $stats;
714 }
715 ]);
716 $promise->wait(false);
717 self::assertFalse($gotStats->hasResponse());
718 self::assertSame(
719 'http://127.0.0.1:123',
720 (string) $gotStats->getEffectiveUri()
721 );
722 self::assertSame(
723 'http://127.0.0.1:123',
724 (string) $gotStats->getRequest()->getUri()
725 );
726 self::assertInternalType('float', $gotStats->getTransferTime());
727 self::assertInternalType('int', $gotStats->getHandlerErrorData());
728 self::assertArrayHasKey('appconnect_time', $gotStats->getHandlerStats());
729 }
730
731 public function testRewindsBodyIfPossible()
732 {
733 $body = Psr7\stream_for(str_repeat('x', 1024 * 1024 * 2));
734 $body->seek(1024 * 1024);
735 self::assertSame(1024 * 1024, $body->tell());
736
737 $req = new Psr7\Request('POST', 'https://www.example.com', [
738 'Content-Length' => 1024 * 1024 * 2,
739 ], $body);
740 $factory = new CurlFactory(1);
741 $factory->create($req, []);
742
743 self::assertSame(0, $body->tell());
744 }
745
746 public function testDoesNotRewindUnseekableBody()
747 {
748 $body = Psr7\stream_for(str_repeat('x', 1024 * 1024 * 2));
749 $body->seek(1024 * 1024);
750 $body = new Psr7\NoSeekStream($body);
751 self::assertSame(1024 * 1024, $body->tell());
752
753 $req = new Psr7\Request('POST', 'https://www.example.com', [
754 'Content-Length' => 1024 * 1024,
755 ], $body);
756 $factory = new CurlFactory(1);
757 $factory->create($req, []);
758
759 self::assertSame(1024 * 1024, $body->tell());
760 }
761
762 public function testRelease()
763 {
764 $factory = new CurlFactory(1);
765 $easyHandle = new EasyHandle();
766 $easyHandle->handle = curl_init();
767
768 self::assertEmpty($factory->release($easyHandle));
769 }
770 }
771