From 189e5e2e51729382809941657cd3ee7e33ed3e7c Mon Sep 17 00:00:00 2001 From: ozh Date: Wed, 5 Feb 2014 12:41:11 +0100 Subject: [PATCH 1/6] Contextually check for a valid transport --- library/Requests.php | 37 ++++++++++++++++-------- library/Requests/Transport/cURL.php | 14 +++++++-- library/Requests/Transport/fsockopen.php | 13 +++++++-- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/library/Requests.php b/library/Requests.php index 854491b81..3cee4f80e 100755 --- a/library/Requests.php +++ b/library/Requests.php @@ -81,9 +81,9 @@ class Requests { * * Use {@see get_transport()} instead * - * @var string|null + * @var array */ - public static $transport = null; + public static $transport = array(); /** * This is a static class, do not instantiate it @@ -147,11 +147,15 @@ public static function add_transport($transport) { * @throws Requests_Exception If no valid transport is found (`notransport`) * @return Requests_Transport */ - protected static function get_transport() { + protected static function get_transport($capabilities = array()) { // Caching code, don't bother testing coverage // @codeCoverageIgnoreStart - if (self::$transport !== null) { - return new self::$transport(); + // array of capabilities as a string to be used as an array key + $cap_string = serialize($capabilities); + + // Don't search for a transport if it's already been done for these $capabilities + if (isset(self::$transport[$cap_string]) && self::$transport[$cap_string] !== null) { + return new self::$transport[$cap_string](); } // @codeCoverageIgnoreEnd @@ -167,17 +171,17 @@ protected static function get_transport() { if (!class_exists($class)) continue; - $result = call_user_func(array($class, 'test')); + $result = call_user_func(array($class, 'test'), $capabilities); if ($result) { - self::$transport = $class; + self::$transport[$cap_string] = $class; break; } } - if (self::$transport === null) { + if (self::$transport[$cap_string] === null) { throw new Requests_Exception('No working transports found', 'notransport', self::$transports); } - - return new self::$transport(); + + return new self::$transport[$cap_string](); } /**#@+ @@ -277,6 +281,10 @@ public static function patch($url, $headers, $data = array(), $options = array() * transport object. Defaults to the first working transport from * {@see getTransport()} * (string|Requests_Transport, default: {@see getTransport()}) + * - `needs_ssl`: whether the chosen transport will need to be able to perform HTTPS + * requests. If unset, this option automatically sets to True when the requested + * URL starts with 'https://' + * (boolean, default: false if $url is HTTP, true if $url is HTTPS) * - `hooks`: Hooks handler. * (Requests_Hooker, default: new Requests_Hooks()) * - `verify`: Should we verify SSL certificates? Allows passing in a custom @@ -314,7 +322,8 @@ public static function request($url, $headers = array(), $data = array(), $type } } else { - $transport = self::get_transport(); + $capabilities = array('ssl' => $options['needs_ssl']); + $transport = self::get_transport($capabilities); } $response = $transport->request($url, $headers, $data, $options); @@ -479,8 +488,12 @@ protected static function get_default_options($multirequest = false) { * @return array $options */ protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) { - if (!preg_match('/^http(s)?:\/\//i', $url)) { + if (!preg_match('/^http(s)?:\/\//i', $url, $matches)) { throw new Requests_Exception('Only HTTP requests are handled.', 'nonhttp', $url); + } else { + if (empty($options['needs_ssl'])) { + $options['needs_ssl'] = ($matches[0] == 'https://'); + } } if (empty($options['hooks'])) { diff --git a/library/Requests/Transport/cURL.php b/library/Requests/Transport/cURL.php index 6ae4d6d06..388237439 100755 --- a/library/Requests/Transport/cURL.php +++ b/library/Requests/Transport/cURL.php @@ -354,7 +354,17 @@ protected static function format_get($url, $data) { * @codeCoverageIgnore * @return boolean True if the transport is valid, false otherwise. */ - public static function test() { - return (function_exists('curl_init') && function_exists('curl_exec')); + public static function test($capabilities = array()) { + if (!function_exists('curl_init') && !function_exists('curl_exec')) + return false; + + // If needed, check that our installed curl version supports SSL + if (isset( $capabilities['ssl'] ) && $capabilities['ssl']) { + $curl_version = curl_version(); + if (!(CURL_VERSION_SSL & $curl_version['features'])) + return false; + } + + return true; } } diff --git a/library/Requests/Transport/fsockopen.php b/library/Requests/Transport/fsockopen.php index 9ce0258ec..ddc4ef8fb 100755 --- a/library/Requests/Transport/fsockopen.php +++ b/library/Requests/Transport/fsockopen.php @@ -385,7 +385,16 @@ public function verify_certificate_from_context($host, $context) { * @codeCoverageIgnore * @return boolean True if the transport is valid, false otherwise. */ - public static function test() { - return function_exists('fsockopen'); + public static function test($capabilities=array()) { + if (!function_exists('fsockopen')) + return false; + + // If needed, check that streams support SSL + if (isset( $capabilities['ssl'] ) && $capabilities['ssl']) { + if (!extension_loaded('openssl') OR !function_exists('openssl_x509_parse')) + return false; + } + + return true; } } From 2695b1ab16737ab959b37627ba0e18cc71bb4f01 Mon Sep 17 00:00:00 2001 From: ozh Date: Fri, 7 Feb 2014 16:38:38 +0100 Subject: [PATCH 2/6] Style & syntax fix --- library/Requests/Transport/fsockopen.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/Requests/Transport/fsockopen.php b/library/Requests/Transport/fsockopen.php index ddc4ef8fb..2cd3964c1 100755 --- a/library/Requests/Transport/fsockopen.php +++ b/library/Requests/Transport/fsockopen.php @@ -385,13 +385,13 @@ public function verify_certificate_from_context($host, $context) { * @codeCoverageIgnore * @return boolean True if the transport is valid, false otherwise. */ - public static function test($capabilities=array()) { + public static function test($capabilities = array()) { if (!function_exists('fsockopen')) return false; // If needed, check that streams support SSL if (isset( $capabilities['ssl'] ) && $capabilities['ssl']) { - if (!extension_loaded('openssl') OR !function_exists('openssl_x509_parse')) + if (!extension_loaded('openssl') || !function_exists('openssl_x509_parse')) return false; } From d561c61f353d5d107b6040303aedd8946f617ad9 Mon Sep 17 00:00:00 2001 From: ozh Date: Fri, 7 Feb 2014 16:43:04 +0100 Subject: [PATCH 3/6] Sort array before serialize it --- library/Requests.php | 1 + 1 file changed, 1 insertion(+) diff --git a/library/Requests.php b/library/Requests.php index 3cee4f80e..b08848e37 100755 --- a/library/Requests.php +++ b/library/Requests.php @@ -151,6 +151,7 @@ protected static function get_transport($capabilities = array()) { // Caching code, don't bother testing coverage // @codeCoverageIgnoreStart // array of capabilities as a string to be used as an array key + ksort($capabilities); $cap_string = serialize($capabilities); // Don't search for a transport if it's already been done for these $capabilities From d2cb625c95acf8a111eb27f4fbd18d3730a34a7c Mon Sep 17 00:00:00 2001 From: ozh Date: Fri, 7 Feb 2014 17:04:39 +0100 Subject: [PATCH 4/6] Remove superflous `else` block --- library/Requests.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Requests.php b/library/Requests.php index b08848e37..d197f0e92 100755 --- a/library/Requests.php +++ b/library/Requests.php @@ -491,10 +491,10 @@ protected static function get_default_options($multirequest = false) { protected static function set_defaults(&$url, &$headers, &$data, &$type, &$options) { if (!preg_match('/^http(s)?:\/\//i', $url, $matches)) { throw new Requests_Exception('Only HTTP requests are handled.', 'nonhttp', $url); - } else { - if (empty($options['needs_ssl'])) { - $options['needs_ssl'] = ($matches[0] == 'https://'); - } + } + + if (empty($options['needs_ssl'])) { + $options['needs_ssl'] = ($matches[0] == 'https://'); } if (empty($options['hooks'])) { From 1de4657c14d0060a56aabeaf9eab0a99b8abd762 Mon Sep 17 00:00:00 2001 From: ozh Date: Sun, 9 Feb 2014 11:07:06 +0100 Subject: [PATCH 5/6] Auto-detect need for SSL capability --- library/Requests.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/library/Requests.php b/library/Requests.php index d197f0e92..d1c444d4d 100755 --- a/library/Requests.php +++ b/library/Requests.php @@ -321,9 +321,9 @@ public static function request($url, $headers = array(), $data = array(), $type if (is_string($options['transport'])) { $transport = new $transport(); } - } - else { - $capabilities = array('ssl' => $options['needs_ssl']); + } else { + $need_ssl = (0 === stripos($url, 'https://')); + $capabilities = array('ssl' => $need_ssl); $transport = self::get_transport($capabilities); } $response = $transport->request($url, $headers, $data, $options); @@ -493,10 +493,6 @@ protected static function set_defaults(&$url, &$headers, &$data, &$type, &$optio throw new Requests_Exception('Only HTTP requests are handled.', 'nonhttp', $url); } - if (empty($options['needs_ssl'])) { - $options['needs_ssl'] = ($matches[0] == 'https://'); - } - if (empty($options['hooks'])) { $options['hooks'] = new Requests_Hooks(); } From 82651ea52572413e38f1a60b43613432dee72ff4 Mon Sep 17 00:00:00 2001 From: ozh Date: Mon, 10 Feb 2014 21:07:50 +0100 Subject: [PATCH 6/6] Deprecated option in phpdoc block --- library/Requests.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/Requests.php b/library/Requests.php index d1c444d4d..0f231df0d 100755 --- a/library/Requests.php +++ b/library/Requests.php @@ -282,10 +282,6 @@ public static function patch($url, $headers, $data = array(), $options = array() * transport object. Defaults to the first working transport from * {@see getTransport()} * (string|Requests_Transport, default: {@see getTransport()}) - * - `needs_ssl`: whether the chosen transport will need to be able to perform HTTPS - * requests. If unset, this option automatically sets to True when the requested - * URL starts with 'https://' - * (boolean, default: false if $url is HTTP, true if $url is HTTPS) * - `hooks`: Hooks handler. * (Requests_Hooker, default: new Requests_Hooks()) * - `verify`: Should we verify SSL certificates? Allows passing in a custom