Merge pull request #445 from zachborboa/master

Fix memory leaks
This commit is contained in:
Zach Borboa
2017-04-30 04:17:00 -07:00
committed by GitHub
3 changed files with 53 additions and 47 deletions
+26 -12
View File
@@ -110,7 +110,14 @@ class Curl
$this->setDefaultUserAgent();
$this->setDefaultTimeout();
$this->setOpt(CURLINFO_HEADER_OUT, true);
$this->setOpt(CURLOPT_HEADERFUNCTION, array($this, 'headerCallback'));
// Create a placeholder to temporarily store the header callback data.
$header_callback_data = new \stdClass();
$header_callback_data->rawResponseHeaders = '';
$header_callback_data->responseCookies = array();
$this->headerCallbackData = $header_callback_data;
$this->setOpt(CURLOPT_HEADERFUNCTION, $this->createHeaderCallback($header_callback_data));
$this->setOpt(CURLOPT_RETURNTRANSFER, true);
$this->headers = new CaseInsensitiveArray();
$this->setUrl($base_url);
@@ -370,6 +377,12 @@ class Curl
}
$this->curlError = !($this->curlErrorCode === 0);
// Transfer the header callback data and release the temporary store to avoid memory leak.
$this->rawResponseHeaders = $this->headerCallbackData->rawResponseHeaders;
$this->responseCookies = $this->headerCallbackData->responseCookies;
$this->headerCallbackData->rawResponseHeaders = null;
$this->headerCallbackData->responseCookies = null;
// Include additional error code information in error message when possible.
if ($this->curlError && function_exists('curl_strerror')) {
$this->curlErrorMessage =
@@ -491,21 +504,22 @@ class Curl
}
/**
* Header Callback
* Create Header Callback
*
* @access public
* @param $ch
* @param $header
* @access private
* @param $header_callback_data
*
* @return integer
* @return callable
*/
public function headerCallback($ch, $header)
private function createHeaderCallback($header_callback_data)
{
if (preg_match('/^Set-Cookie:\s*([^=]+)=([^;]+)/mi', $header, $cookie) === 1) {
$this->responseCookies[$cookie[1]] = trim($cookie[2], " \n\r\t\0\x0B");
}
$this->rawResponseHeaders .= $header;
return strlen($header);
return function ($ch, $header) use ($header_callback_data) {
if (preg_match('/^Set-Cookie:\s*([^=]+)=([^;]+)/mi', $header, $cookie) === 1) {
$header_callback_data->responseCookies[$cookie[1]] = trim($cookie[2], " \n\r\t\0\x0B");
}
$header_callback_data->rawResponseHeaders .= $header;
return strlen($header);
};
}
/**
+4
View File
@@ -662,6 +662,7 @@ class MultiCurl
$ch->curlErrorCode = $info_array['result'];
$ch->exec($ch->curl);
// Remove completed instance from active curls.
unset($this->activeCurls[$key]);
// Start a new request before removing the handle of the completed one.
@@ -670,6 +671,9 @@ class MultiCurl
}
curl_multi_remove_handle($this->multiCurl, $ch->curl);
// Clean up completed instance.
$ch->close();
break;
}
}
+23 -35
View File
@@ -1829,28 +1829,25 @@ class MultiCurlTest extends \PHPUnit\Framework\TestCase
$get_1 = $multi_curl->addGet(Test::TEST_URL, $data);
$get_1->complete(function ($instance) use ($multi_curl_user_agent) {
\PHPUnit\Framework\Assert::assertInstanceOf('Curl\Curl', $instance);
\PHPUnit\Framework\Assert::assertEquals($multi_curl_user_agent, $instance->getOpt(CURLOPT_USERAGENT));
});
$get_2 = $multi_curl->addGet(Test::TEST_URL, $data);
$get_2->complete(function ($instance) use ($multi_curl_user_agent) {
\PHPUnit\Framework\Assert::assertEquals($multi_curl_user_agent, $instance->getOpt(CURLOPT_USERAGENT));
\PHPUnit\Framework\Assert::assertEquals($multi_curl_user_agent, $instance->response);
});
$get_2 = $multi_curl->addGet(Test::TEST_URL, $data);
$get_2->beforeSend(function ($instance) use ($curl_user_agent) {
$get_3 = $multi_curl->addGet(Test::TEST_URL, $data);
$get_3->beforeSend(function ($instance) use ($curl_user_agent) {
$instance->setOpt(CURLOPT_USERAGENT, $curl_user_agent);
});
$get_2->complete(function ($instance) use ($curl_user_agent) {
\PHPUnit\Framework\Assert::assertInstanceOf('Curl\Curl', $instance);
$get_3->complete(function ($instance) use ($curl_user_agent) {
\PHPUnit\Framework\Assert::assertEquals($curl_user_agent, $instance->getOpt(CURLOPT_USERAGENT));
\PHPUnit\Framework\Assert::assertEquals($curl_user_agent, $instance->response);
});
$multi_curl->start();
$this->assertEquals($multi_curl_user_agent, $multi_curl->getOpt(CURLOPT_USERAGENT));
$this->assertEquals($multi_curl_user_agent, $get_1->getOpt(CURLOPT_USERAGENT));
$this->assertEquals($multi_curl_user_agent, $get_1->response);
$this->assertEquals($curl_user_agent, $get_2->getOpt(CURLOPT_USERAGENT));
$this->assertEquals($curl_user_agent, $get_2->response);
}
public function testSetHeaderAndOverride()
@@ -1890,31 +1887,28 @@ class MultiCurlTest extends \PHPUnit\Framework\TestCase
$multi_curl->setBasicAuthentication($username1, $password1);
$get_1 = $multi_curl->addGet(Test::TEST_URL);
$get_1->complete(function ($instance) use ($username1, $password1) {
\PHPUnit\Framework\Assert::assertInstanceOf('Curl\Curl', $instance);
\PHPUnit\Framework\Assert::assertEquals($username1, $instance->response->username);
\PHPUnit\Framework\Assert::assertEquals($password1, $instance->response->password);
$get_1->complete(function ($instance) {
\PHPUnit\Framework\Assert::assertEquals(CURLAUTH_BASIC, $instance->getOpt(CURLOPT_HTTPAUTH));
});
$get_2 = $multi_curl->addGet(Test::TEST_URL);
$get_2->beforeSend(function ($instance) use ($username2, $password2) {
$get_2->complete(function ($instance) use ($username1, $password1) {
\PHPUnit\Framework\Assert::assertEquals($username1, $instance->response->username);
\PHPUnit\Framework\Assert::assertEquals($password1, $instance->response->password);
\PHPUnit\Framework\Assert::assertEquals(CURLAUTH_BASIC, $instance->getOpt(CURLOPT_HTTPAUTH));
});
$get_3 = $multi_curl->addGet(Test::TEST_URL);
$get_3->beforeSend(function ($instance) use ($username2, $password2) {
$instance->setBasicAuthentication($username2, $password2);
});
$get_2->complete(function ($instance) use ($username2, $password2) {
\PHPUnit\Framework\Assert::assertInstanceOf('Curl\Curl', $instance);
$get_3->complete(function ($instance) use ($username2, $password2) {
\PHPUnit\Framework\Assert::assertEquals($username2, $instance->response->username);
\PHPUnit\Framework\Assert::assertEquals($password2, $instance->response->password);
\PHPUnit\Framework\Assert::assertEquals(CURLAUTH_BASIC, $instance->getOpt(CURLOPT_HTTPAUTH));
});
$multi_curl->start();
$this->assertEquals(CURLAUTH_BASIC, $multi_curl->getOpt(CURLOPT_HTTPAUTH));
$this->assertEquals(CURLAUTH_BASIC, $get_1->getOpt(CURLOPT_HTTPAUTH));
$this->assertEquals($username1, $get_1->response->username);
$this->assertEquals($password1, $get_1->response->password);
$this->assertEquals(CURLAUTH_BASIC, $get_2->getOpt(CURLOPT_HTTPAUTH));
$this->assertEquals($username2, $get_2->response->username);
$this->assertEquals($password2, $get_2->response->password);
}
public function testDigestHttpAuthSuccess()
@@ -2569,11 +2563,10 @@ class MultiCurlTest extends \PHPUnit\Framework\TestCase
public function testSequentialId()
{
$completed = array();
$multi_curl = new MultiCurl();
$multi_curl->complete(function ($instance) use (&$completed) {
$completed[] = $instance;
$multi_curl->complete(function ($instance) {
$sequential_id = $instance->getOpt(CURLOPT_POSTFIELDS);
\PHPUnit\Framework\Assert::assertEquals($sequential_id, $instance->id);
});
for ($i = 0; $i < 100; $i++) {
@@ -2581,11 +2574,6 @@ class MultiCurlTest extends \PHPUnit\Framework\TestCase
}
$multi_curl->start();
foreach ($completed as $instance) {
$sequential_id = $instance->getOpt(CURLOPT_POSTFIELDS);
$this->assertEquals($sequential_id, $instance->id);
}
}
public function testAscendingNumericalOrder()