Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom option for cURL multi handler #2287

Merged
merged 2 commits into from Oct 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/faq.rst
Expand Up @@ -65,6 +65,23 @@ used with a client.
]
]);

If you use asynchronous requests with cURL multi handler and want to tweak it,
additional options can be specified as an associative array in the
**options** key of the ``CurlMultiHandler`` constructor.

.. code-block:: php

use \GuzzleHttp\Client;
use \GuzzleHttp\HandlerStack;
use \GuzzleHttp\Handler\CurlMultiHandler;

$client = new Client(['handler' => HandlerStack::create(new CurlMultiHandler([
'options' => [
CURLMOPT_MAX_TOTAL_CONNECTIONS => 50,
CURLMOPT_MAX_HOST_CONNECTIONS => 5,
]
]))]);


How can I add custom stream context options?
============================================
Expand Down
18 changes: 16 additions & 2 deletions src/Handler/CurlMultiHandler.php
@@ -1,9 +1,9 @@
<?php
namespace GuzzleHttp\Handler;

use GuzzleHttp\Exception\InvalidArgumentException;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Psr7;
use Psr\Http\Message\RequestInterface;

/**
Expand All @@ -23,13 +23,16 @@ class CurlMultiHandler
private $active;
private $handles = [];
private $delays = [];
private $options = [];

/**
* This handler accepts the following options:
*
* - handle_factory: An optional factory used to create curl handles
* - select_timeout: Optional timeout (in seconds) to block before timing
* out while selecting curl handles. Defaults to 1 second.
* - options: An associative array of CURLMOPT_* options and
* corresponding values for curl_multi_setopt()
*
* @param array $options
*/
Expand All @@ -45,12 +48,23 @@ public function __construct(array $options = [])
} else {
$this->selectTimeout = 1;
}

$this->options = isset($options['options']) ? $options['options'] : [];
}

public function __get($name)
{
if ($name === '_mh') {
return $this->_mh = curl_multi_init();
$this->_mh = curl_multi_init();

foreach ($this->options as $option => $value) {
// A warning is raised in case of a wrong option.
curl_multi_setopt($this->_mh, $option, $value);
}

// Further calls to _mh will return the value directly, without entering the
// __get() method at all.
return $this->_mh;
}

throw new \BadMethodCallException();
Expand Down
23 changes: 23 additions & 0 deletions tests/Handler/CurlMultiHandlerTest.php
Expand Up @@ -9,6 +9,29 @@

class CurlMultiHandlerTest extends TestCase
{
public function setUp()
{
$_SERVER['curl_test'] = true;
unset($_SERVER['_curl_multi']);
}

public function tearDown()
{
unset($_SERVER['_curl_multi'], $_SERVER['curl_test']);
}

public function testCanAddCustomCurlOptions()
alexeyshockov marked this conversation as resolved.
Show resolved Hide resolved
{
Server::flush();
Server::enqueue([new Response()]);
$a = new CurlMultiHandler(['options' => [
CURLMOPT_MAXCONNECTS => 5,
]]);
$request = new Request('GET', Server::$url);
$a($request, []);
$this->assertEquals(5, $_SERVER['_curl_multi'][CURLMOPT_MAXCONNECTS]);
}

public function testSendsRequest()
{
Server::enqueue([new Response()]);
Expand Down
14 changes: 12 additions & 2 deletions tests/bootstrap.php
Expand Up @@ -10,7 +10,7 @@
});
}

// Override curl_setopt_array() to get the last set curl options
// Override curl_setopt_array() and curl_multi_setopt() to get the last set curl options
namespace GuzzleHttp\Handler {
function curl_setopt_array($handle, array $options)
{
Expand All @@ -19,6 +19,16 @@ function curl_setopt_array($handle, array $options)
} else {
unset($_SERVER['_curl']);
}
\curl_setopt_array($handle, $options);
return \curl_setopt_array($handle, $options);
}

function curl_multi_setopt($handle, $option, $value)
{
if (!empty($_SERVER['curl_test'])) {
$_SERVER['_curl_multi'][$option] = $value;
} else {
unset($_SERVER['_curl_multi']);
}
return \curl_multi_setopt($handle, $option, $value);
}
}