Browse Source

Switch from pecl_http to the cURL extension to make requests against Webdis.

The cURL extension is easily found already packaged for various Linux
distributions, it provides everything needed and it seems to have a lower
overhead compared to pecl_http.
Daniele Alessandri 13 năm trước cách đây
mục cha
commit
e7d2717ee1
1 tập tin đã thay đổi với 54 bổ sung34 xóa
  1. 54 34
      lib/Predis/Network/WebdisConnection.php

+ 54 - 34
lib/Predis/Network/WebdisConnection.php

@@ -16,19 +16,18 @@ implemented yet (or they simply cannot be implemented at all). Here is a list:
 
 namespace Predis\Network;
 
-use HttpRequest;
 use Predis\IConnectionParameters;
 use Predis\ResponseError;
 use Predis\ClientException;
 use Predis\ServerException;
-use Predis\CommunicationException;
 use Predis\Commands\ICommand;
+use Predis\Protocol\ProtocolException;
 
 const ERR_MSG_EXTENSION = 'The %s extension must be loaded in order to be able to use this connection class';
 
 class WebdisConnection implements IConnectionSingle {
     private $_parameters;
-    private $_webdisUrl;
+    private $_resource;
     private $_reader;
 
     private static function throwNotImplementedException($class, $function) {
@@ -36,33 +35,51 @@ class WebdisConnection implements IConnectionSingle {
     }
 
     public function __construct(IConnectionParameters $parameters) {
-        $this->checkExtensions();
+        $this->_parameters = $parameters;
         if ($parameters->scheme !== 'http') {
             throw new \InvalidArgumentException("Invalid scheme: {$parameters->scheme}");
         }
-        $this->_parameters = $parameters;
-        $this->_webdisUrl = "{$parameters->scheme}://{$parameters->host}:{$parameters->port}";
+        $this->checkExtensions();
+        $this->_resource = $this->initializeCurl($parameters);
         $this->_reader = $this->initializeReader($parameters);
     }
 
     public function __destruct() {
+        curl_close($this->_resource);
         phpiredis_reader_destroy($this->_reader);
     }
 
     private function checkExtensions() {
-        if (!class_exists("HttpRequest")) {
-            throw new ClientException(sprintf(ERR_MSG_EXTENSION, 'http'));
+        if (!function_exists('curl_init')) {
+            throw new ClientException(sprintf(ERR_MSG_EXTENSION, 'curl'));
         }
         if (!function_exists('phpiredis_reader_create')) {
             throw new ClientException(sprintf(ERR_MSG_EXTENSION, 'phpiredis'));
         }
     }
 
+    private function initializeCurl(IConnectionParameters $parameters) {
+        $options = array(
+            CURLOPT_URL => "{$parameters->scheme}://{$parameters->host}:{$parameters->port}",
+            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
+            CURLOPT_POST => true,
+            CURLOPT_WRITEFUNCTION => array($this, 'feedReader'),
+        );
+
+        if (isset($parameters->user, $parameters->pass)) {
+            $options[CURLOPT_USERPWD] = "{$parameters->user}:{$parameters->pass}";
+        }
+
+        $resource = curl_init();
+        curl_setopt_array($resource, $options);
+
+        return $resource;
+    }
+
     private function initializeReader(IConnectionParameters $parameters) {
-        $throwErrors = $parameters->throw_errors;
         $reader = phpiredis_reader_create();
         phpiredis_reader_set_status_handler($reader, $this->getStatusHandler());
-        phpiredis_reader_set_error_handler($reader, $this->getErrorHandler($throwErrors));
+        phpiredis_reader_set_error_handler($reader, $this->getErrorHandler($parameters->throw_errors));
         return $reader;
     }
 
@@ -83,6 +100,11 @@ class WebdisConnection implements IConnectionSingle {
         };
     }
 
+    protected function feedReader($resource, $buffer) {
+        phpiredis_reader_feed($this->_reader, $buffer);
+        return strlen($buffer);
+    }
+
     public function connect() {
         // NOOP
     }
@@ -118,43 +140,41 @@ class WebdisConnection implements IConnectionSingle {
         }
     }
 
-    protected function getHttpOptions() {
-        $options = array();
-        $parameters = $this->_parameters;
-        if (isset($parameters->user, $parameters->pass)) {
-            $options['httpauth'] = "{$parameters->user}:{$parameters->pass}";
-            $options['httpauthtype'] = HTTP_AUTH_BASIC;
-        }
-        return $options;
-    }
-
     public function executeCommand(ICommand $command) {
-        $request = new HttpRequest($this->_webdisUrl, HttpRequest::METH_POST);
-        if ($options = $this->getHttpOptions()) {
-            $request->setOptions($options);
-        }
-
+        $resource = $this->_resource;
         $commandId = $this->getCommandId($command);
+
         if ($arguments = $command->getArguments()) {
             $arguments = implode('/', array_map('urlencode', $arguments));
-            $request->setBody("$commandId/$arguments.raw");
+            $serializedCommand = "$commandId/$arguments.raw";
         }
         else {
-            $request->setBody("$commandId.raw");
+            $serializedCommand = "$commandId.raw";
         }
 
-        $response = $request->send();
-        phpiredis_reader_feed($this->_reader, $response->getBody());
+        curl_setopt($resource, CURLOPT_POSTFIELDS, $serializedCommand);
+        if (curl_exec($resource) === false) {
+            $error = curl_error($resource);
+            $errno = curl_errno($resource);
+            throw new ConnectionException($this, trim($error), $errno);
+        }
 
-        $reply = phpiredis_reader_get_reply($this->_reader);
-        if ($reply instanceof IReplyObject) {
-            return $reply;
+        $readerState = phpiredis_reader_get_state($this->_reader);
+        if ($readerState === PHPIREDIS_READER_STATE_COMPLETE) {
+            $reply = phpiredis_reader_get_reply($this->_reader);
+            if ($reply instanceof IReplyObject) {
+                return $reply;
+            }
+            return $command->parseResponse($reply);
+        }
+        else {
+            $error = phpiredis_reader_get_error($this->_reader);
+            throw new ProtocolException($this, $error);
         }
-        return $command->parseResponse($reply);
     }
 
     public function getResource() {
-        self::throwNotImplementedException(__CLASS__, __FUNCTION__);
+        return $this->_resource;
     }
 
     public function getParameters() {