* @param string $server the server name / ip address
* @param integer $port the port the server is listening on, when omitted defaults to 80 or 443 depending on
* protocol used
- * @param string $method the http protocol variant: defaults to 'http'; 'https' and 'http11' can be used if CURL is
- * installed. The value set here can be overridden in any call to $this->send().
+ * @param string $method the http protocol variant: defaults to 'http'; 'https', 'http11', 'http2' and 'http2tls' can
+ * be used if CURL is installed. The value set here can be overridden in any call to $this->send().
*/
public function __construct($path, $server = '', $port = '', $method = '')
{
* This timeout value is passed to fsockopen(). It is also used for detecting server
* timeouts during communication (i.e. if the server does not send anything to the client
* for $timeout seconds, the connection will be closed).
- * @param string $method valid values are 'http', 'http11' and 'https'. If left unspecified, the http protocol
- * chosen during creation of the object will be used.
+ * @param string $method valid values are 'http', 'http11', 'https', 'http2' and 'http2tls'. If left unspecified,
+ * the http protocol chosen during creation of the object will be used.
*
* @return Response|Response[] Note that the client will always return a Response object, even if the call fails
* @todo allow throwing exceptions instead of returning responses in case of failed calls and/or Fault responses
/// @todo we could be smarter about this and force usage of curl in scenarios where it is both available and
/// needed, such as digest or ntlm auth. Do not attempt to use it for https if not present
$useCurl = ($this->use_curl == self::USE_CURL_ALWAYS) || ($this->use_curl == self::USE_CURL_AUTO &&
- ($method == 'https' || $method == 'http11'));
+ ($method == 'https' || $method == 'http11' || $method == 'http2' || $method == 'http2tls'));
if ($useCurl) {
$r = $this->sendPayloadCURL(
* @param string $proxyUsername
* @param string $proxyPassword
* @param int $proxyAuthType
- * @param string $method 'http' (let curl decide), 'http10', 'http11' or 'https'
+ * @param string $method 'http' (let curl decide), 'http10', 'http11', 'https', 'http2' or 'http2tls'
* @param bool $keepAlive
* @param string $key
* @param string $keyPass
$this->errstr = 'SSL unavailable on this install';
return new Response(0, PhpXmlRpc::$xmlrpcerr['no_ssl'], PhpXmlRpc::$xmlrpcstr['no_ssl']);
}
+ } elseif (($method == 'http2' || $method == 'http2tls') && !defined('CURL_HTTP_VERSION_2')) {
+ $this->errstr = 'HTTP/2 unavailable on this install';
+ return new Response(0, PhpXmlRpc::$xmlrpcerr['no_http2'], PhpXmlRpc::$xmlrpcstr['no_http2']);
}
if ($port == 0) {
- if (in_array($method, array('http', 'http10', 'http11'))) {
+ if (in_array($method, array('http', 'http10', 'http11', 'http2'))) {
$port = 80;
} else {
$port = 443;
}
if (!$keepAlive || !$this->xmlrpc_curl_handle) {
- if ($method == 'http11' || $method == 'http10') {
+ if ($method == 'http11' || $method == 'http10' || $method == 'http2') {
$protocol = 'http';
} else {
- $protocol = $method;
+ if ($method == 'http2tls') {
+ $protocol = 'https';
+ } else {
+ $protocol = $method;
+ }
}
$curl = curl_init($protocol . '://' . $server . ':' . $port . $this->path);
if ($keepAlive) {
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout == 1 ? 1 : $timeout - 1);
}
- if ($method == 'http10') {
- curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
- } elseif ($method == 'http11') {
- curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ switch($method) {
+ case 'http10':
+ curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+ break;
+ case 'http11':
+ curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+ break;
+ case 'http2':
+ curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2);
+ break;
+ case 'http2tls':
+ curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
+ break;
}
if ($username && $password) {
}
}
- if ($method == 'https') {
+ if ($method == 'https' || $method == 'http2tls') {
// set cert file
if ($cert) {
curl_setopt($curl, CURLOPT_SSLCERT, $cert);
'multicall_recursion' => 12,
'multicall_noparams' => 13,
'multicall_notarray' => 14,
+ 'no_http2' => 15,
'cannot_decompress' => 103,
'decompress_fail' => 104,
'multicall_recursion' => 'Recursive system.multicall forbidden',
'multicall_noparams' => 'Missing params',
'multicall_notarray' => 'params is not an array',
+ 'no_http2' => 'No HTTP/2 support compiled in',
'cannot_decompress' => 'Received from server compressed HTTP and cannot decompress',
'decompress_fail' => 'Received from server invalid compressed HTTP',
$this->$method();
}
+ /**
+ * @dataProvider getSingleHttpTestMethods
+ * @param string $method
+ */
+ public function testHttp2($method)
+ {
+ if (!function_exists('curl_init'))
+ {
+ $this->markTestSkipped('CURL missing: cannot test http/2');
+ return;
+ }
+
+ $this->method = 'http2'; // not an error the double assignment!
+ $this->client->method = 'http2';
+ //$this->client->keepalive = false; // q: is this a good idea?
+ $this->$method();
+ }
+
+ /**
+ * @dataProvider getSingleHttpTestMethods
+ * @param string $method
+ */
+ public function testHttp2tls($method)
+ {
+ if (!function_exists('curl_init'))
+ {
+ $this->markTestSkipped('CURL missing: cannot test http/2 tls');
+ return;
+ } else if ($this->args['HTTPSSERVER'] == '')
+ {
+ $this->markTestSkipped('HTTPS SERVER definition missing: cannot test http/2 tls');
+ return;
+ }
+
+ $this->client->server = $this->args['HTTPSSERVER'];
+ $this->method = 'http2tls';
+ $this->client->method = 'http2tls';
+ $this->client->path = $this->args['HTTPSURI'];
+ $this->client->setSSLVerifyPeer(!$this->args['HTTPSIGNOREPEER']);
+ $this->client->setSSLVerifyHost($this->args['HTTPSVERIFYHOST']);
+ $this->client->setSSLVersion($this->args['SSLVERSION']);
+
+ $this->$method();
+ }
+
/**
* @dataProvider getSingleHttpTestMethods
* @param string $method