Skip to content

Commit 3d91340

Browse files
committed
Assert that cURL handles are correctly closed
1 parent 43b291e commit 3d91340

File tree

3 files changed

+85
-3
lines changed

3 files changed

+85
-3
lines changed

src/Transport/Curl.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,9 @@ public function request($url, $headers = array(), $data = array(), $options = ar
200200
$response = $this->response_data;
201201
}
202202

203-
if (true === $options['blocking']) {
203+
if (! isset($options['blocking']) || $options['blocking'] !== false) {
204204
// Need to remove the $this reference from the curl handle.
205-
// Otherwise \WpOrg\Requests\Transport\Curl wont be garbage collected and the curl_close() will never be called.
205+
// Otherwise \WpOrg\Requests\Transport\Curl won't be garbage collected and the curl_close() will never be called.
206206
curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, null);
207207
curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, null);
208208
}

tests/Transport/BaseTestCase.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ abstract class BaseTestCase extends TestCase {
1717

1818
protected $skip_https = false;
1919

20-
public function set_up() {
20+
protected function set_up() {
2121
// Intermediary variable $test_method. This can be simplified (removed) once the minimum supported PHP version is 7.0 or higher.
2222
$test_method = array($this->transport, 'test');
2323

tests/Transport/CurlTest.php

+82
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,63 @@
33
namespace WpOrg\Requests\Tests\Transport;
44

55
use WpOrg\Requests\Exception;
6+
use WpOrg\Requests\Hooks;
67
use WpOrg\Requests\Requests;
78
use WpOrg\Requests\Tests\Transport\BaseTestCase;
89
use WpOrg\Requests\Transport\Curl;
910

1011
final class CurlTest extends BaseTestCase {
1112
protected $transport = Curl::class;
1213

14+
/**
15+
* Temporary storage of the cURL handle to assert against.
16+
*
17+
* @var null|resource|\CurlHandle
18+
*/
19+
protected $curl_handle;
20+
21+
/**
22+
* Get the options to use for the cURL tests.
23+
*
24+
* This adds a hook on curl.before_request to store the cURL handle. This is
25+
* needed for asserting after the test scenarios that the cURL handle was
26+
* correctly closed.
27+
*
28+
* @param array $other
29+
* @return array
30+
*/
31+
protected function getOptions($other = array()) {
32+
$options = parent::getOptions($other);
33+
34+
$this->curl_handle = null;
35+
36+
$hooks = new Hooks();
37+
$hooks->register(
38+
'curl.before_request',
39+
function ($handle) {
40+
$this->curl_handle = $handle;
41+
}
42+
);
43+
44+
$options['hooks'] = $hooks;
45+
46+
return $options;
47+
}
48+
49+
/**
50+
* Post condition asserts to run after each scenario.
51+
*
52+
* This is used for asserting that cURL handles are not leaking memory.
53+
*/
54+
protected function assert_post_conditions( ) {
55+
if ($this->curl_handle === null) {
56+
// No cURL handle was used during this particular test scenario.
57+
return;
58+
}
59+
60+
$this->assertCurlHandleIsClosed($this->curl_handle);
61+
}
62+
1363
public function testBadIP() {
1464
$this->expectException(Exception::class);
1565
$this->expectExceptionMessage('t resolve host');
@@ -136,4 +186,36 @@ public function testSetsEmptyExpectHeaderIfBodySmallerThan1Mb() {
136186

137187
$this->assertFalse(isset($result['headers']['Expect']));
138188
}
189+
190+
/**
191+
* Assert that a provided cURL handle was properly closed.
192+
*
193+
* For PHP 8.0+, the cURL handle is not a resource that needs to be closed,
194+
* but rather a \CurlHandle object. The assertion just skips these.
195+
*
196+
* @param resource|\CurlHandle $handle CURL handle to check.
197+
*/
198+
private function assertCurlHandleIsClosed($handle) {
199+
if ($handle instanceof \CurlHandle) {
200+
// CURL handles have been changed from resources into CurlHandle
201+
// objects starting with PHP 8.0, which don;t need to be closed.
202+
return;
203+
}
204+
205+
self::assertThat(
206+
in_array(
207+
gettype($handle),
208+
array('resource', 'resource (closed)'),
209+
true
210+
),
211+
self::isTrue(),
212+
'Failed asserting that stored cURL handle was a resource.'
213+
);
214+
215+
self::assertThat(
216+
is_resource($handle) === false,
217+
self::isTrue(),
218+
'Failed asserting that stored cURL handle was properly closed.'
219+
);
220+
}
139221
}

0 commit comments

Comments
 (0)