Initial refactoring to split backends based on request/response objects
authorChuck Hagenbuch <chuck@horde.org>
Fri, 4 Sep 2009 15:40:48 +0000 (11:40 -0400)
committerChuck Hagenbuch <chuck@horde.org>
Fri, 4 Sep 2009 15:40:48 +0000 (11:40 -0400)
28 files changed:
framework/Http/examples/Horde/Http/get-example-dot-com.php [new file with mode: 0644]
framework/Http/lib/Horde/Http/Client.php [new file with mode: 0644]
framework/Http/lib/Horde/Http/Exception.php [new file with mode: 0644]
framework/Http/lib/Horde/Http/Request/Base.php [new file with mode: 0644]
framework/Http/lib/Horde/Http/Request/Curl.php [new file with mode: 0644]
framework/Http/lib/Horde/Http/Request/Fopen.php [new file with mode: 0644]
framework/Http/lib/Horde/Http/Request/Mock.php [new file with mode: 0644]
framework/Http/lib/Horde/Http/Request/Peclhttp.php [new file with mode: 0644]
framework/Http/lib/Horde/Http/Response/Base.php [new file with mode: 0644]
framework/Http/lib/Horde/Http/Response/Curl.php [new file with mode: 0644]
framework/Http/lib/Horde/Http/Response/Fopen.php [new file with mode: 0644]
framework/Http/lib/Horde/Http/Response/Peclhttp.php [new file with mode: 0644]
framework/Http/package.xml [new file with mode: 0644]
framework/Http/test/Horde/Http/AllTests.php [new file with mode: 0644]
framework/Http/test/Horde/Http/FopenTest.php [new file with mode: 0644]
framework/Http_Client/examples/Horde/Http/Client/get-example-dot-com.php [deleted file]
framework/Http_Client/lib/Horde/Http/Client.php [deleted file]
framework/Http_Client/lib/Horde/Http/Client/Adapter/Base.php [deleted file]
framework/Http_Client/lib/Horde/Http/Client/Adapter/Curl.php [deleted file]
framework/Http_Client/lib/Horde/Http/Client/Adapter/Fopen.php [deleted file]
framework/Http_Client/lib/Horde/Http/Client/Adapter/Peclhttp.php [deleted file]
framework/Http_Client/lib/Horde/Http/Client/Exception.php [deleted file]
framework/Http_Client/lib/Horde/Http/Client/Mock.php [deleted file]
framework/Http_Client/lib/Horde/Http/Client/Request.php [deleted file]
framework/Http_Client/lib/Horde/Http/Client/Response.php [deleted file]
framework/Http_Client/package.xml [deleted file]
framework/Http_Client/test/Horde/Http/Client/Adapter/FopenTest.php [deleted file]
framework/Http_Client/test/Horde/Http/Client/AllTests.php [deleted file]

diff --git a/framework/Http/examples/Horde/Http/get-example-dot-com.php b/framework/Http/examples/Horde/Http/get-example-dot-com.php
new file mode 100644 (file)
index 0000000..96f4515
--- /dev/null
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Basic example for fetching a page with Horde_Http_Client
+ *
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+
+require 'Horde/Autoloader.php';
+
+$client = new Horde_Http_Client();
+$response = $client->get('http://www.example.com/');
+var_dump($response);
+echo $response->getBody();
diff --git a/framework/Http/lib/Horde/Http/Client.php b/framework/Http/lib/Horde/Http/Client.php
new file mode 100644 (file)
index 0000000..dea2a2f
--- /dev/null
@@ -0,0 +1,193 @@
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+
+/**
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+class Horde_Http_Client
+{
+    /**
+     * The current HTTP request
+     * @var Horde_Http_Request_Base
+     */
+    protected $_request;
+
+    /**
+     * The previous HTTP request
+     * @var Horde_Http_Request_Base
+     */
+    protected $_lastRequest;
+
+    /**
+     * The most recent HTTP response
+     * @var Horde_Http_Response_Base
+     */
+    protected $_lastResponse;
+
+    /**
+     * Horde_Http_Client constructor.
+     *
+     * @param array $args Any Http_Client settings to initialize in the
+     * constructor. Available settings are:
+     *     client.proxyServer
+     *     client.proxyUser
+     *     client.proxyPass
+     *     client.timeout
+     *     request
+     *     request.uri
+     *     request.headers
+     *     request.method
+     *     request.data
+     */
+    public function __construct($args = array())
+    {
+        // Set or create request object
+        if (isset($args['request'])) {
+            $this->_request = $args['request'];
+            unset($args['request']);
+        } else {
+            $this->_request = $this->_createBestAvailableRequest();
+        }
+
+        foreach ($args as $key => $val) {
+            list($object, $objectkey) = explode('.', $key, 2);
+            $this->$object->$objectkey = $val;
+        }
+    }
+
+    /**
+     * Send a GET request
+     *
+     * @return Horde_Http_Response_Base
+     */
+    public function get($uri = null, $headers = array())
+    {
+        return $this->request('GET', $uri, null, $headers);
+    }
+
+    /**
+     * Send a POST request
+     *
+     * @return Horde_Http_Response_Base
+     */
+    public function post($uri = null, $data = null, $headers = array())
+    {
+        return $this->request('POST', $uri, $data, $headers);
+    }
+
+    /**
+     * Send a PUT request
+     *
+     * @return Horde_Http_Response_Base
+     */
+    public function put($uri = null, $data = null, $headers = array())
+    {
+        /* @TODO suport method override (X-Method-Override: PUT). */
+        return $this->request('PUT', $uri, $data, $headers);
+    }
+
+    /**
+     * Send a DELETE request
+     *
+     * @return Horde_Http_Response_Base
+     */
+    public function delete($uri = null, $headers = array())
+    {
+        /* @TODO suport method override (X-Method-Override: DELETE). */
+        return $this->request('DELETE', $uri, null, $headers);
+    }
+
+    /**
+     * Send a HEAD request
+     * @TODO
+     *
+     * @return  ? Probably just the status
+     */
+    public function head($uri = null, $headers = array())
+    {
+        return $this->request('HEAD', $uri, null, $headers);
+    }
+
+    /**
+     * Send an HTTP request
+     *
+     * @param string $method HTTP request method (GET, PUT, etc.)
+     * @param string $uri URI to request, if different from $this->uri
+     * @param mixed $data Request data. Can be an array of form data that will be
+     *                    encoded automatically, or a raw string.
+     * @param array $headers Any headers specific to this request. They will
+     *                       be combined with $this->_headers, and override
+     *                       headers of the same name for this request only.
+     *
+     * @return Horde_Http_Response_Base
+     */
+    public function request($method, $uri = null, $data = null, $headers = array())
+    {
+        if ($method !== null) {
+            $this->request->method = $method;
+        }
+        if ($uri !== null) {
+            $this->request->uri = $uri;
+        }
+        if ($data !== null) {
+            $this->request->data = $data;
+        }
+        if (count($headers)) {
+            $this->request->setHeaders($headers);
+        }
+
+        $this->_lastRequest = $this->_request;
+        $this->_lastResponse = $this->_adapter->send($this->_lastRequest);
+        return $this->_lastResponse;
+    }
+
+    /**
+     * Get a client parameter
+     *
+     * @param string $name  The parameter to get.
+     * @return mixed        Parameter value.
+     */
+    public function __get($name)
+    {
+        return isset($this->{'_' . $name}) ? $this->{'_' . $name} : null;
+    }
+
+    /**
+     * Set a client parameter
+     *
+     * @param string $name   The parameter to set.
+     * @param mixed  $value  Parameter value.
+     */
+    public function __set($name, $value)
+    {
+        $this->{'_' . $name} = $value;
+    }
+
+    /**
+     * Find the best available request backend
+     *
+     * @return Horde_Http_Request_Base
+     */
+    public function _createBestAvailableRequest()
+    {
+        if (class_exists('HttpRequest', false)) {
+            return new Horde_Http_Request_Peclhttp();
+        } elseif (extension_loaded('curl')) {
+            return new Horde_Http_Request_Curl();
+        } elseif (ini_get('allow_url_fopen')) {
+            return new Horde_Http_Request_Fopen();
+        } else {
+            throw new Horde_Http_Exception('No HTTP request backends are available. You must install pecl_http, curl, or enable allow_url_fopen.');
+        }
+    }
+}
diff --git a/framework/Http/lib/Horde/Http/Exception.php b/framework/Http/lib/Horde/Http/Exception.php
new file mode 100644 (file)
index 0000000..d4a6df0
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+
+/**
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+class Horde_Http_Exception extends Exception
+{
+    /**
+     * Constructor
+     */
+    public function __construct($message = null, $code_or_lasterror = 0)
+    {
+        if (is_array($code_or_lasterror)) {
+            if ($message) {
+                $message .= $code_or_lasterror['message'];
+            } else {
+                $message = $code_or_lasterror['message'];
+            }
+
+            $this->file = $code_or_lasterror['file'];
+            $this->line = $code_or_lasterror['line'];
+            $code = $code_or_lasterror['type'];
+        } else {
+            $code = $code_or_lasterror;
+        }
+
+        parent::__construct($message, $code);
+    }
+
+}
diff --git a/framework/Http/lib/Horde/Http/Request/Base.php b/framework/Http/lib/Horde/Http/Request/Base.php
new file mode 100644 (file)
index 0000000..b566524
--- /dev/null
@@ -0,0 +1,133 @@
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+
+/**
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+abstract class Horde_Http_Request_Base
+{
+    /**
+     * URI
+     * @var string
+     */
+    protected $_uri;
+
+    /**
+     * Request method
+     * @var string
+     */
+    protected $_method = 'GET';
+
+    /**
+     * Request headers
+     * @var array
+     */
+    protected $_headers = array();
+
+    /**
+     * Request data. Can be an array of form data that will be encoded
+     * automatically, or a raw string
+     * @var mixed
+     */
+    protected $_data;
+
+    /**
+     * Proxy server
+     * @var string
+     */
+    protected $_proxyServer = null;
+
+    /**
+     * Proxy username
+     * @var string
+     */
+    protected $_proxyUser = null;
+
+    /**
+     * Proxy password
+     * @var string
+     */
+    protected $_proxyPass = null;
+
+    /**
+     * HTTP timeout
+     * @var float
+     */
+    protected $_timeout = 5;
+
+    /**
+     * Constructor
+     */
+    public function __construct($args = array())
+    {
+        foreach ($args as $key => $value) {
+            $this->$key = $value;
+        }
+    }
+
+    /**
+     * Get an adapter parameter
+     *
+     * @param string $name  The parameter to get.
+     * @return mixed        Parameter value.
+     */
+    public function __get($name)
+    {
+        return isset($this->{'_' . $name}) ? $this->{'_' . $name} : null;
+    }
+
+    /**
+     * Set a request parameter
+     *
+     * @param string $name   The parameter to set.
+     * @param mixed  $value  Parameter value.
+     */
+    public function __set($name, $value)
+    {
+        switch ($name) {
+        case 'headers':
+            $this->setHeaders($value);
+            break;
+        }
+
+        $this->{'_' . $name} = $value;
+    }
+
+    /**
+     * Set one or more headers
+     *
+     * @param mixed $headers A hash of header + value pairs, or a single header name
+     * @param string $value  A header value
+     */
+    public function setHeaders($headers, $value = null)
+    {
+        if (!is_array($headers)) {
+            $headers = array($headers => $value);
+        }
+
+        foreach ($headers as $header => $value) {
+            $this->_headers[$header] = $value;
+        }
+    }
+
+    /**
+     * Get the current value of $header
+     *
+     * @param string $header Header name to get
+     * @return string $header's current value
+     */
+    public function getHeader($header)
+    {
+        return isset($this->_headers[$header]) ? $this->_headers[$header] : null;
+    }
+}
diff --git a/framework/Http/lib/Horde/Http/Request/Curl.php b/framework/Http/lib/Horde/Http/Request/Curl.php
new file mode 100644 (file)
index 0000000..c13d779
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+
+/**
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+class Horde_Http_Request_Curl extends Horde_Http_Request_Base
+{
+    public function __construct()
+    {
+        if (!extension_loaded('curl')) {
+            throw new Horde_Http_Exception('The curl extension is not installed. See http://php.net/curl.installation');
+        }
+    }
+
+    /**
+     * Send this HTTP request
+     *
+     * @return Horde_Http_Response_Base
+     */
+    public function send()
+    {
+        $body = tmpfile();
+        $headers = tmpfile();
+
+        $curl = curl_init();
+        curl_setopt($curl, CURLOPT_URL, $this->uri);
+        curl_setopt($curl, CURLOPT_FILE, $body);
+        curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data);
+        curl_setopt($curl, CURLOPT_WRITEHEADER, $headers);
+
+        $result = curl_exec($curl);
+
+        rewind($body);
+        rewind($headers);
+
+        return new Horde_Http_Response_Curl($this->uri, $body, stream_get_contents($headers));
+    }
+}
diff --git a/framework/Http/lib/Horde/Http/Request/Fopen.php b/framework/Http/lib/Horde/Http/Request/Fopen.php
new file mode 100644 (file)
index 0000000..06febb7
--- /dev/null
@@ -0,0 +1,82 @@
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+
+/**
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+class Horde_Http_Request_Fopen extends Horde_Http_Request_Base
+{
+    public function __construct()
+    {
+        if (!ini_get('allow_url_fopen')) {
+            throw new Horde_Http_Exception('allow_url_fopen must be enabled');
+        }
+    }
+
+    /**
+     * Send this HTTP request
+     *
+     * @return Horde_Http_Response_Base
+     */
+    public function send()
+    {
+        $method = $this->method;
+        $uri = $this->uri;
+        $headers = $this->headers;
+        $data = $this->data;
+        if (is_array($data)) {
+            $data = http_build_query($data, '', '&');
+        }
+
+        $opts = array('http' => array());
+
+        // Proxy settings - check first, so we can include the correct headers
+        if ($this->proxyServer) {
+            $opts['http']['proxy'] = 'tcp://' . $this->proxyServer;
+            $opts['http']['request_fulluri'] = true;
+            if ($this->proxyUser && $this->proxyPass) {
+                $headers['Proxy-Authorization'] = 'Basic ' . base64_encode($this->proxyUser . ':' . $this->proxyPass);
+            }
+        }
+
+        // Concatenate the headers
+        $hdr = array();
+        foreach ($headers as $header => $value) {
+            $hdr[] = $header . ': ' . $value;
+        }
+
+        // Stream context config.
+        $opts['http']['method'] = $method;
+        $opts['http']['header'] = implode("\n", $hdr);
+        $opts['http']['content'] = $data;
+        $opts['http']['timeout'] = $this->timeout;
+
+        $context = stream_context_create($opts);
+        $stream = @fopen($uri, 'rb', false, $context);
+        if (!$stream) {
+            $error = error_get_last();
+            if (preg_match('/HTTP\/(\d+\.\d+) (\d{3}) (.*)$/', $error['message'], $matches)) {
+                // Create a Response for the HTTP error code
+                return new Horde_Http_Response_Fopen($uri, null, $matches[0]);
+            } else {
+                throw new Horde_Http_Exception('Problem with ' . $uri . ': ', $error);
+            }
+        }
+
+        $meta = stream_get_meta_data($stream);
+        $headers = isset($meta['wrapper_data']) ? $meta['wrapper_data'] : array();
+
+        return new Horde_Http_Response_Fopen($uri, $stream, $headers);
+    }
+
+}
diff --git a/framework/Http/lib/Horde/Http/Request/Mock.php b/framework/Http/lib/Horde/Http/Request/Mock.php
new file mode 100644 (file)
index 0000000..e247046
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+
+/**
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+class Horde_Http_Request_Mock extends Horde_Http_Request_Base
+{
+    /**
+     * Array of mock responses
+     * @var array
+     */
+    protected $_responses = array();
+
+    /**
+     * Current mock response
+     * @var integer
+     */
+    protected $_responseIndex = 0;
+
+    /**
+     * Send this HTTP request
+     *
+     * @return Horde_Http_Response_Base
+     *
+     * @TODO make lastRequest work somehow - not sure if this is still an issue.
+     */
+    public function send()
+    {
+        if ($this->_responseIndex >= count($this->_responses)) {
+            $this->_responseIndex = 0;
+        }
+        return $this->_responses[$this->_responseIndex++];
+    }
+
+    /**
+     * Set the HTTP response(s) to be returned by this adapter
+     *
+     * @param Horde_Http_Response_Base $response
+     */
+    public function setResponse($response)
+    {
+        $this->_responses = array($response);
+        $this->_responseIndex = 0;
+    }
+
+    /**
+     * Add another response to the response buffer.
+     *
+     * @param string $response
+     */
+    public function addResponse($response)
+    {
+        $this->_responses[] = $response;
+    }
+
+    /**
+     * Sets the position of the response buffer.  Selects which
+     * response will be returned on the next call to read().
+     *
+     * @param integer $index
+     */
+    public function setResponseIndex($index)
+    {
+        if ($index < 0 || $index >= count($this->_responses)) {
+            throw new OutOfBoundsException;
+        }
+        $this->_responseIndex = $index;
+    }
+
+}
diff --git a/framework/Http/lib/Horde/Http/Request/Peclhttp.php b/framework/Http/lib/Horde/Http/Request/Peclhttp.php
new file mode 100644 (file)
index 0000000..5547e5a
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+
+/**
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+class Horde_Http_Request_Peclhttp extends Horde_Http_Request_Base
+{
+    public static $methods = array(
+        'GET' => HTTP_METH_GET,
+        'HEAD' => HTTP_METH_HEAD,
+        'POST' => HTTP_METH_POST,
+        'PUT' => HTTP_METH_PUT,
+        'DELETE' => HTTP_METH_DELETE,
+    );
+
+    public function __construct()
+    {
+        if (!class_exists('HttpRequest', false)) {
+            throw new Horde_Http_Exception('The pecl_http extension is not installed. See http://php.net/http.install');
+        }
+    }
+
+    /**
+     * Send this HTTP request
+     *
+     * @return Horde_Http_Response_Base
+     */
+    public function send()
+    {
+        $httpRequest = new HttpRequest($this->uri, self::$methods[$this->method]);
+        $httpRequest->setHeaders($this->headers);
+
+        $data = $this->data;
+        if (is_array($data)) {
+            $httpRequest->setPostFields($data);
+        } else {
+            $httpRequest->setRawPostData($data);
+        }
+
+        try {
+            $httpResponse = $httpRequest->send();
+        } catch (HttpException $e) {
+            throw new Horde_Http_Exception($e->getMessage(), $e->getCode(), $e);
+        }
+
+        return new Horde_Http_Response_Peclhttp($httpResponse);
+    }
+}
diff --git a/framework/Http/lib/Horde/Http/Response/Base.php b/framework/Http/lib/Horde/Http/Response/Base.php
new file mode 100644 (file)
index 0000000..1826d4f
--- /dev/null
@@ -0,0 +1,150 @@
+<?php
+/**
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+
+/**
+ * @author   Chuck Hagenbuch <chuck@horde.org>
+ * @license  http://opensource.org/licenses/bsd-license.php BSD
+ * @category Horde
+ * @package  Horde_Http
+ */
+class Horde_Http_Response_Base
+{
+    /**
+     * Fetched URI
+     * @var string
+     */
+    public $uri;
+
+    /**
+     * HTTP protocol version that was used
+     * @var float
+     */
+    public $httpVersion;
+
+    /**
+     * HTTP response code
+     * @var integer
+     */
+    public $code;
+
+    /**
+     * Response headers
+     * @var array
+     */
+    public $headers;
+
+    /**
+     * Response body
+     * @var stream
+     */
+    protected $_stream;
+
+    /**
+     * Constructor
+     */
+    public function __construct($uri, $stream, $headers = array())
+    {
+        $this->uri = $uri;
+        $this->_stream = $stream;
+        $this->_parseHeaders($headers);
+    }
+
+    /**
+     * Parse an array of response headers, mindful of line
+     * continuations, etc.
+     *
+     * @param array $headers
+     * @return array
+     */
+    protected function _parseHeaders($headers)
+    {
+        if (!is_array($headers)) {
+            $headers = explode("\n", $headers);
+        }
+
+        $lastHeader = null;
+        foreach ($headers as $headerLine) {
+            // stream_get_meta returns all headers generated while processing a
+            // request, including ones for redirects before an eventually successful
+            // request. We just want the last one, so whenever we hit a new HTTP
+            // header, throw out anything parsed previously and start over.
+            if (preg_match('/^HTTP\/(\d.\d) (\d{3})/', $headerLine, $httpMatches)) {
+                $this->httpVersion = $httpMatches[1];
+                $this->code = (int)$httpMatches[2];
+                $this->headers = array();
+                $lastHeader = null;
+            }
+
+            $headerLine = trim($headerLine, "\r\n");
+            if ($headerLine == '') {
+                break;
+            }
+            if (preg_match('|^([\w-]+):\s+(.+)|', $headerLine, $m)) {
+                unset($lastHeader);
+                $headerName = strtolower($m[1]);
+                $headerValue = $m[2];
+
+                if (isset($this->headers[$headerName])) {
+                    if (!is_array($this->headers[$headerName])) {
+                        $this->headers[$headerName] = array($this->headers[$headerName]);
+                    }
+
+                    $this->headers[$headerName][] = $headerValue;
+                } else {
+                    $this->headers[$headerName] = $headerValue;
+                }
+                $lastHeader = $headerName;
+            } elseif (preg_match("|^\s+(.+)$|", $headerLine, $m) && !is_null($lastHeader)) {
+                if (is_array($this->headers[$lastHeader])) {
+                    end($this->headers[$lastHeader]);
+                    $this->headers[$lastHeader][key($this->headers[$lastHeader])] .= $m[1];
+                } else {
+                    $this->headers[$lastHeader] .= $m[1];
+                }
+            }
+        }
+    }
+
+    /**
+     * Return the body of the HTTP response.
+     *
+     * @return string HTTP response body.
+     */
+    public function getBody()
+    {
+        $content = @stream_get_contents($this->_stream);
+        if ($content === false) {
+            throw new Horde_Http_Exception('Problem reading data from ' . $this->uri . ': ' . $php_errormsg);
+        }
+        return $content;
+    }
+
+    /**
+     * Return a stream pointing to the response body that can be used
+     * with all standard PHP stream functions.
+     */
+    public function getStream()
+    {
+        return $this->_stream;
+    }
+
+    /**
+     * Get the value of a single response header.
+     *
+     * @param string $header Header name to get ('Content-Type', 'Content-Length', etc.). This is case sensitive.
+     *
+     * @return string HTTP header value.
+     */
+    public function getHeader($header)
+    {
+        return isset($this->headers[$header]) ? $this->headers[$header] : null;
+    }
+
+}
diff --git a/framework/Http/lib/Horde/Http/Response/Curl.php b/framework/Http/lib/Horde/Http/Response/Curl.php
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/framework/Http/lib/Horde/Http/Response/Fopen.php b/framework/Http/lib/Horde/Http/Response/Fopen.php
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/framework/Http/lib/Horde/Http/Response/Peclhttp.php b/framework/Http/lib/Horde/Http/Response/Peclhttp.php
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/framework/Http/package.xml b/framework/Http/package.xml
new file mode 100644 (file)
index 0000000..42fe622
--- /dev/null
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.9" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>Http</name>
+ <channel>pear.horde.org</channel>
+ <summary>Horde HTTP libraries</summary>
+ <description>This package provides a set of classes for making HTTP requests.
+ </description>
+ <lead>
+  <name>Chuck Hagenbuch</name>
+  <user>chuck</user>
+  <email>chuck@horde.org</email>
+  <active>yes</active>
+ </lead>
+ <date>2009-09-04</date>
+ <version>
+  <release>0.5.0</release>
+  <api>0.5.0</api>
+ </version>
+ <stability>
+  <release>beta</release>
+  <api>beta</api>
+ </stability>
+ <license uri="http://opensource.org/licenses/bsd-license.php">BSD</license>
+ <notes>* Refactor to support multiple request transports, including Curl and the PECL http extension.</notes>
+ <contents>
+  <dir name="/">
+   <dir name="lib">
+    <dir name="Horde">
+     <dir name="Http">
+      <file name="Exception.php" role="php" />
+      <file name="Client.php" role="php" />
+      <dir name="Request">
+       <file name="Base.php" role="php" />
+       <file name="Curl.php" role="php" />
+       <file name="Fopen.php" role="php" />
+       <file name="Mock.php" role="php" />
+       <file name="Peclhttp.php" role="php" />
+      </dir> <!-- /lib/Horde/Http/Request -->
+      <dir name="Response">
+      </dir> <!-- /lib/Horde/Http/Response -->
+     </dir> <!-- /lib/Horde/Http -->
+    </dir> <!-- /lib/Horde -->
+   </dir> <!-- /lib/ -->
+  </dir> <!-- / -->
+ </contents>
+ <dependencies>
+  <required>
+   <php>
+    <min>5.2.0</min>
+   </php>
+   <pearinstaller>
+    <min>1.5.0</min>
+   </pearinstaller>
+  </required>
+ </dependencies>
+ <phprelease>
+  <filelist>
+   <install name="lib/Horde/Http/Client.php" as="Horde/Http/Client.php" />
+   <install name="lib/Horde/Http/Exception.php" as="Horde/Http/Exception.php" />
+   <install name="lib/Horde/Http/Request/Base.php" as="Horde/Http/Request/Base.php" />
+   <install name="lib/Horde/Http/Request/Curl.php" as="Horde/Http/Request/Curl.php" />
+   <install name="lib/Horde/Http/Request/Fopen.php" as="Horde/Http/Request/Fopen.php" />
+   <install name="lib/Horde/Http/Request/Mock.php" as="Horde/Http/Request/Mock.php" />
+   <install name="lib/Horde/Http/Request/Peclhttp.php" as="Horde/Http/Request/Peclhttp.php" />
+  </filelist>
+ </phprelease>
+</package>
diff --git a/framework/Http/test/Horde/Http/AllTests.php b/framework/Http/test/Horde/Http/AllTests.php
new file mode 100644 (file)
index 0000000..a49c7b8
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+/**
+ * @category   Horde
+ * @package    Horde_Http
+ * @subpackage UnitTests
+ * @copyright  2008-2009 The Horde Project (http://www.horde.org/)
+ * @license    http://opensource.org/licenses/bsd-license.php
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Horde_Http_AllTests::main');
+}
+
+require_once 'PHPUnit/Framework/TestSuite.php';
+require_once 'PHPUnit/TextUI/TestRunner.php';
+
+class Horde_Http_AllTests {
+
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    public static function suite()
+    {
+        set_include_path(dirname(__FILE__) . '/../../../../lib' . PATH_SEPARATOR . get_include_path());
+        if (!spl_autoload_functions()) {
+            spl_autoload_register(create_function('$class', '$filename = str_replace(array(\'::\', \'_\'), \'/\', $class); include "$filename.php";'));
+        }
+
+        $suite = new PHPUnit_Framework_TestSuite('Horde Framework - Horde_Http');
+
+        $basedir = dirname(__FILE__);
+        $baseregexp = preg_quote($basedir . DIRECTORY_SEPARATOR, '/');
+
+        foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($basedir)) as $file) {
+            if ($file->isFile() && preg_match('/Test.php$/', $file->getFilename())) {
+                $pathname = $file->getPathname();
+                require $pathname;
+
+                $class = str_replace(DIRECTORY_SEPARATOR, '_',
+                                     preg_replace("/^$baseregexp(.*)\.php/", '\\1', $pathname));
+                $suite->addTestSuite('Horde_Http_' . $class);
+            }
+        }
+
+        return $suite;
+    }
+
+}
+
+if (PHPUnit_MAIN_METHOD == 'Horde_Http_AllTests::main') {
+    Horde_Http_AllTests::main();
+}
diff --git a/framework/Http/test/Horde/Http/FopenTest.php b/framework/Http/test/Horde/Http/FopenTest.php
new file mode 100644 (file)
index 0000000..7bb7d4e
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/**
+ * @category   Horde
+ * @package    Horde_Http
+ * @subpackage UnitTests
+ * @copyright  2007-2009 The Horde Project (http://www.horde.org/)
+ * @license    http://opensource.org/licenses/bsd-license.php
+ */
+
+/**
+ * @group      support
+ * @category   Horde
+ * @package    Horde_Http
+ * @subpackage UnitTests
+ * @copyright  2007-2009 The Horde Project (http://www.horde.org/)
+ * @license    http://opensource.org/licenses/bsd-license.php
+ */
+class Horde_Http_FopenTest extends PHPUnit_Framework_TestCase
+{
+    public function testThrowsOnBadUri()
+    {
+        $client = new Horde_Http_Client(array('request' => new Horde_Http_Request_Fopen()));
+        try {
+            $response = $client->get('http://doesntexist.example.com/');
+            $this->fail();
+        } catch (Horde_Http_Exception $e) {
+        }
+    }
+
+    public function testReturnsResponseInsteadOfExceptionOn404()
+    {
+        $client = new Horde_Http_Client(array('request' => new Horde_Http_Request_Fopen()));
+        $response = $client->get('http://example.com/doesntexist');
+        $this->assertEquals(404, $response->code);
+    }
+}
diff --git a/framework/Http_Client/examples/Horde/Http/Client/get-example-dot-com.php b/framework/Http_Client/examples/Horde/Http/Client/get-example-dot-com.php
deleted file mode 100644 (file)
index 1b55e2a..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-/**
- * Basic example for fetching a page with Horde_Http_Client
- *
- * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
- *
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-
-require 'Horde/Http/Client.php';
-require 'Horde/Http/Client/Exception.php';
-require 'Horde/Http/Client/Response.php';
-
-$client = new Horde_Http_Client();
-$response = $client->get('http://www.example.com/');
-var_dump($response);
-echo $response->getBody();
diff --git a/framework/Http_Client/lib/Horde/Http/Client.php b/framework/Http_Client/lib/Horde/Http/Client.php
deleted file mode 100644 (file)
index 0e64cdb..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-<?php
-/**
- * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
- *
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-
-/**
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-class Horde_Http_Client
-{
-    /**
-     * HTTP Adapter to use for transport
-     * @var Horde_Http_Client_Adapter
-     */
-    protected $_adapter;
-
-    /**
-     * The current HTTP request
-     * @var Horde_Http_Client_Request
-     */
-    protected $_request;
-
-    /**
-     * The previous HTTP request
-     * @var Horde_Http_Client_Request
-     */
-    protected $_lastRequest;
-
-    /**
-     * The most recent HTTP response
-     * @var Horde_Http_Client_Response
-     */
-    protected $_lastResponse;
-
-    /**
-     * Horde_Http_Client constructor.
-     *
-     * @param array $args Any Http_Client settings to initialize in the
-     * constructor. Available settings are:
-     *     adapter
-     *     adapter.proxyServer
-     *     adapter.proxyUser
-     *     adapter.proxyPass
-     *     adapter.timeout
-     *     request
-     *     request.uri
-     *     request.headers
-     *     request.method
-     *     request.data
-     */
-    public function __construct($args = array())
-    {
-        // Set or create adapter object
-        if (isset($args['adapter'])) {
-            $this->_adapter = $args['adapter'];
-            unset($args['adapter']);
-        } else {
-            $this->_adapter = $this->_createBestAvailableAdapter();
-        }
-
-        // Set or create request object
-        if (isset($args['request'])) {
-            $this->_request = $args['request'];
-            unset($args['request']);
-        } else {
-            $this->_request = new Horde_Http_Client_Request();
-        }
-
-        foreach ($args as $key => $val) {
-            list($object, $objectkey) = explode('.', $key, 2);
-            $this->$object->$objectkey = $val;
-        }
-    }
-
-    /**
-     * Send a GET request
-     *
-     * @return Horde_Http_Client_Response
-     */
-    public function get($uri = null, $headers = array())
-    {
-        return $this->request('GET', $uri, null, $headers);
-    }
-
-    /**
-     * Send a POST request
-     *
-     * @return Horde_Http_Client_Response
-     */
-    public function post($uri = null, $data = null, $headers = array())
-    {
-        return $this->request('POST', $uri, $data, $headers);
-    }
-
-    /**
-     * Send a PUT request
-     *
-     * @return Horde_Http_Client_Response
-     */
-    public function put($uri = null, $data = null, $headers = array())
-    {
-        /* @TODO suport method override (X-Method-Override: PUT). */
-        return $this->request('PUT', $uri, $data, $headers);
-    }
-
-    /**
-     * Send a DELETE request
-     *
-     * @return Horde_Http_Client_Response
-     */
-    public function delete($uri = null, $headers = array())
-    {
-        /* @TODO suport method override (X-Method-Override: DELETE). */
-        return $this->request('DELETE', $uri, null, $headers);
-    }
-
-    /**
-     * Send a HEAD request
-     * @TODO
-     *
-     * @return  ? Probably just the status
-     */
-    public function head($uri = null, $headers = array())
-    {
-        return $this->request('HEAD', $uri, null, $headers);
-    }
-
-    /**
-     * Send an HTTP request
-     *
-     * @param string $method HTTP request method (GET, PUT, etc.)
-     * @param string $uri URI to request, if different from $this->uri
-     * @param mixed $data Request data. Can be an array of form data that will be
-     *                    encoded automatically, or a raw string.
-     * @param array $headers Any headers specific to this request. They will
-     *                       be combined with $this->_headers, and override
-     *                       headers of the same name for this request only.
-     *
-     * @return Horde_Http_Client_Response
-     */
-    public function request($method, $uri = null, $data = null, $headers = array())
-    {
-        if ($method !== null) {
-            $this->request->method = $method;
-        }
-        if ($uri !== null) {
-            $this->request->uri = $uri;
-        }
-        if ($data !== null) {
-            $this->request->data = $data;
-        }
-        if (count($headers)) {
-            $this->request->setHeaders($headers);
-        }
-
-        $this->_lastRequest = $this->_request;
-        $this->_lastResponse = $this->_adapter->send($this->_lastRequest);
-        return $this->_lastResponse;
-    }
-
-    /**
-     * Get a client parameter
-     *
-     * @param string $name  The parameter to get.
-     * @return mixed        Parameter value.
-     */
-    public function __get($name)
-    {
-        return isset($this->{'_' . $name}) ? $this->{'_' . $name} : null;
-    }
-
-    /**
-     * Set a client parameter
-     *
-     * @param string $name   The parameter to set.
-     * @param mixed  $value  Parameter value.
-     */
-    public function __set($name, $value)
-    {
-        $this->{'_' . $name} = $value;
-    }
-
-    /**
-     * Find the best available adapter
-     *
-     * @return Horde_Http_Client_Adapter
-     */
-    public function _createBestAvailableAdapter()
-    {
-        /*if (class_exists('HttpRequest', false)) {
-            return new Horde_Http_Client_Adapter_Peclhttp();
-        } else*/if (extension_loaded('curl')) {
-            return new Horde_Http_Client_Adapter_Curl();
-        } elseif (ini_get('allow_url_fopen')) {
-            return new Horde_Http_Client_Adapter_Fopen();
-        } else {
-            throw new Horde_Http_Client_Exception('No HTTP adapters are available. You must install pecl_http, curl, or enable allow_url_fopen.');
-        }
-    }
-}
diff --git a/framework/Http_Client/lib/Horde/Http/Client/Adapter/Base.php b/framework/Http_Client/lib/Horde/Http/Client/Adapter/Base.php
deleted file mode 100644 (file)
index 95bf259..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-/**
- * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
- *
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-
-/**
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-class Horde_Http_Client_Adapter_Base
-{
-    /**
-     * Proxy server
-     * @var string
-     */
-    protected $_proxyServer = null;
-
-    /**
-     * Proxy username
-     * @var string
-     */
-    protected $_proxyUser = null;
-
-    /**
-     * Proxy password
-     * @var string
-     */
-    protected $_proxyPass = null;
-
-    /**
-     * HTTP timeout
-     * @var float
-     */
-    protected $_timeout = 5;
-
-    /**
-     * Constructor
-     */
-    public function __construct($args = array())
-    {
-        foreach ($args as $key => $value) {
-            $this->$key = $value;
-        }
-    }
-
-    /**
-     * Get an adapter parameter
-     *
-     * @param string $name  The parameter to get.
-     * @return mixed        Parameter value.
-     */
-    public function __get($name)
-    {
-        return isset($this->{'_' . $name}) ? $this->{'_' . $name} : null;
-    }
-
-    /**
-     * Set an adapter parameter
-     *
-     * @param string $name   The parameter to set.
-     * @param mixed  $value  Parameter value.
-     */
-    public function __set($name, $value)
-    {
-        $this->{'_' . $name} = $value;
-    }
-}
diff --git a/framework/Http_Client/lib/Horde/Http/Client/Adapter/Curl.php b/framework/Http_Client/lib/Horde/Http/Client/Adapter/Curl.php
deleted file mode 100644 (file)
index 1fc720c..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-/**
- * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
- *
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-
-/**
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-class Horde_Http_Client_Adapter_Curl extends Horde_Http_Client_Adapter_Base
-{
-    public function __construct()
-    {
-        if (!extension_loaded('curl')) {
-            throw new Horde_Http_Client_Exception('The curl extension is not installed. See http://php.net/curl.installation');
-        }
-    }
-
-    /**
-     * Send an HTTP request
-     *
-     * @param Horde_Http_Client_Request  HTTP Request object
-     *
-     * @return Horde_Http_Client_Response
-     */
-    public function send($request)
-    {
-        $body = tmpfile();
-        $headers = tmpfile();
-
-        $curl = curl_init();
-        curl_setopt($curl, CURLOPT_URL, $request->uri);
-        curl_setopt($curl, CURLOPT_FILE, $body);
-        curl_setopt($curl, CURLOPT_POSTFIELDS, $request->data);
-        curl_setopt($curl, CURLOPT_WRITEHEADER, $headers);
-
-        $result = curl_exec($curl);
-
-        rewind($body);
-        rewind($headers);
-
-        return new Horde_Http_Client_Response($request->uri, $body, stream_get_contents($headers));
-    }
-}
diff --git a/framework/Http_Client/lib/Horde/Http/Client/Adapter/Fopen.php b/framework/Http_Client/lib/Horde/Http/Client/Adapter/Fopen.php
deleted file mode 100644 (file)
index a735e93..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-/**
- * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
- *
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-
-/**
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-class Horde_Http_Client_Adapter_Fopen extends Horde_Http_Client_Adapter_Base
-{
-    public function __construct()
-    {
-        if (!ini_get('allow_url_fopen')) {
-            throw new Horde_Http_Client_Exception('allow_url_fopen must be enabled');
-        }
-    }
-
-    /**
-     * Send an HTTP request
-     *
-     * @param Horde_Http_Client_Request  HTTP Request object
-     *
-     * @return Horde_Http_Client_Response
-     */
-    public function send($request)
-    {
-        $method = $request->method;
-        $uri = $request->uri;
-        $headers = $request->headers;
-        $data = $request->data;
-        if (is_array($data)) {
-            $data = http_build_query($data, '', '&');
-        }
-
-        $opts = array('http' => array());
-
-        // Proxy settings - check first, so we can include the correct headers
-        if ($this->proxyServer) {
-            $opts['http']['proxy'] = 'tcp://' . $this->proxyServer;
-            $opts['http']['request_fulluri'] = true;
-            if ($this->proxyUser && $this->proxyPass) {
-                $headers['Proxy-Authorization'] = 'Basic ' . base64_encode($this->proxyUser . ':' . $this->proxyPass);
-            }
-        }
-
-        // Concatenate the headers
-        $hdr = array();
-        foreach ($headers as $header => $value) {
-            $hdr[] = $header . ': ' . $value;
-        }
-
-        // Stream context config.
-        $opts['http']['method'] = $method;
-        $opts['http']['header'] = implode("\n", $hdr);
-        $opts['http']['content'] = $data;
-        $opts['http']['timeout'] = $this->timeout;
-
-        $context = stream_context_create($opts);
-        $stream = @fopen($uri, 'rb', false, $context);
-        if (!$stream) {
-            $error = error_get_last();
-            if (preg_match('/HTTP\/(\d+\.\d+) (\d{3}) (.*)$/', $error['message'], $matches)) {
-                // Create a Response for the HTTP error code
-                return new Horde_Http_Client_Response($uri, null, $matches[0]);
-            } else {
-                throw new Horde_Http_Client_Exception('Problem with ' . $uri . ': ', $error);
-            }
-        }
-
-        $meta = stream_get_meta_data($stream);
-        $headers = isset($meta['wrapper_data']) ? $meta['wrapper_data'] : array();
-
-        return new Horde_Http_Client_Response($uri, $stream, $headers);
-    }
-
-}
diff --git a/framework/Http_Client/lib/Horde/Http/Client/Adapter/Peclhttp.php b/framework/Http_Client/lib/Horde/Http/Client/Adapter/Peclhttp.php
deleted file mode 100644 (file)
index ad13739..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-/**
- * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
- *
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-
-/**
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-class Horde_Http_Client_Adapter_Peclhttp extends Horde_Http_Client_Adapter_Base
-{
-    public static $methods = array(
-        'GET' => HTTP_METH_GET,
-        'HEAD' => HTTP_METH_HEAD,
-        'POST' => HTTP_METH_POST,
-        'PUT' => HTTP_METH_PUT,
-        'DELETE' => HTTP_METH_DELETE,
-    );
-
-    public function __construct()
-    {
-        if (!class_exists('HttpRequest', false)) {
-            throw new Horde_Http_Client_Exception('The pecl_http extension is not installed. See http://php.net/http.install');
-        }
-    }
-
-    /**
-     * Send an HTTP request
-     *
-     * @param Horde_Http_Client_Request  HTTP Request object
-     *
-     * @return Horde_Http_Client_Response
-     */
-    public function send($request)
-    {
-        $httpRequest = new HttpRequest($request->uri, self::$methods[$request->method]);
-        $httpRequest->setHeaders($request->headers);
-
-        $data = $request->data;
-        if (is_array($data)) {
-            $httpRequest->setPostFields($data);
-        } else {
-            $httpRequest->setRawPostData($data);
-        }
-
-        try {
-            $httpResponse = $httpRequest->send();
-        } catch (HttpException $e) {
-            throw new Horde_Http_Client_Exception($e->getMessage(), $e->getCode(), $e);
-        }
-
-        /*@TODO build Horde_Http_Client_Response from $httpResponse */
-        return $httpResponse;
-    }
-}
diff --git a/framework/Http_Client/lib/Horde/Http/Client/Exception.php b/framework/Http_Client/lib/Horde/Http/Client/Exception.php
deleted file mode 100644 (file)
index b191463..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-/**
- * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
- *
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-
-/**
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-class Horde_Http_Client_Exception extends Exception
-{
-    /**
-     * Constructor
-     */
-    public function __construct($message = null, $code_or_lasterror = 0)
-    {
-        if (is_array($code_or_lasterror)) {
-            if ($message) {
-                $message .= $code_or_lasterror['message'];
-            } else {
-                $message = $code_or_lasterror['message'];
-            }
-
-            $this->file = $code_or_lasterror['file'];
-            $this->line = $code_or_lasterror['line'];
-            $code = $code_or_lasterror['type'];
-        } else {
-            $code = $code_or_lasterror;
-        }
-
-        parent::__construct($message, $code);
-    }
-
-}
diff --git a/framework/Http_Client/lib/Horde/Http/Client/Mock.php b/framework/Http_Client/lib/Horde/Http/Client/Mock.php
deleted file mode 100644 (file)
index 1f7f57a..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<?php
-/**
- * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
- *
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-
-/**
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-class Horde_Http_Client_Mock extends Horde_Http_Client
-{
-    /**
-     * Array of mock responses
-     * @var array
-     */
-    protected $_responses = array();
-
-    /**
-     * Current mock response
-     * @var integer
-     */
-    protected $_responseIndex = 0;
-
-    /**
-     * Send an HTTP request
-     *
-     * @param string $method HTTP request method (GET, PUT, etc.)
-     * @param string $uri URI to request, if different from $this->uri
-     * @param mixed $data Request data. Can be an array of form data that will be
-     *                    encoded automatically, or a raw string.
-     * @param array $headers Any headers specific to this request. They will
-     *                       be combined with $this->_headers, and override
-     *                       headers of the same name for this request only.
-     *
-     * @return Horde_Http_Client_Response
-     *
-     * @TODO make lastRequest work somehow.
-     */
-    public function request($method, $uri = null, $data = null, $headers = array())
-    {
-        if ($this->_responseIndex >= count($this->_responses)) {
-            $this->_responseIndex = 0;
-        }
-        return $this->_responses[$this->_responseIndex++];
-    }
-
-    /**
-     * Set the HTTP response(s) to be returned by this adapter
-     *
-     * @param Horde_Http_Client_Response $response
-     */
-    public function setResponse($response)
-    {
-        $this->_responses = array($response);
-        $this->_responseIndex = 0;
-    }
-
-    /**
-     * Add another response to the response buffer.
-     *
-     * @param string $response
-     */
-    public function addResponse($response)
-    {
-        $this->_responses[] = $response;
-    }
-
-    /**
-     * Sets the position of the response buffer.  Selects which
-     * response will be returned on the next call to read().
-     *
-     * @param integer $index
-     */
-    public function setResponseIndex($index)
-    {
-        if ($index < 0 || $index >= count($this->_responses)) {
-            throw new OutOfBoundsException;
-        }
-        $this->_responseIndex = $index;
-    }
-
-}
diff --git a/framework/Http_Client/lib/Horde/Http/Client/Request.php b/framework/Http_Client/lib/Horde/Http/Client/Request.php
deleted file mode 100644 (file)
index b5f699a..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-/**
- * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
- *
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-
-/**
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-class Horde_Http_Client_Request
-{
-    /**
-     * URI
-     * @var string
-     */
-    protected $_uri;
-
-    /**
-     * Request method
-     * @var string
-     */
-    protected $_method = 'GET';
-
-    /**
-     * Request headers
-     * @var array
-     */
-    protected $_headers = array();
-
-    /**
-     * Request data. Can be an array of form data that will be encoded
-     * automatically, or a raw string
-     * @var mixed
-     */
-    protected $_data;
-
-    /**
-     * Constructor
-     */
-    public function __construct($args = array())
-    {
-        foreach ($args as $key => $value) {
-            $this->$key = $value;
-        }
-    }
-
-    /**
-     * Get a request parameter
-     *
-     * @param string $name  The parameter to get.
-     * @return mixed        Parameter value.
-     */
-    public function __get($name)
-    {
-        return isset($this->{'_' . $name}) ? $this->{'_' . $name} : null;
-    }
-
-    /**
-     * Set a request parameter
-     *
-     * @param string $name   The parameter to set.
-     * @param mixed  $value  Parameter value.
-     */
-    public function __set($name, $value)
-    {
-        switch ($name) {
-        case 'headers':
-            $this->setHeaders($value);
-            break;
-        }
-
-        $this->{'_' . $name} = $value;
-    }
-
-    /**
-     * Set one or more headers
-     *
-     * @param mixed $headers A hash of header + value pairs, or a single header name
-     * @param string $value  A header value
-     */
-    public function setHeaders($headers, $value = null)
-    {
-        if (!is_array($headers)) {
-            $headers = array($headers => $value);
-        }
-
-        foreach ($headers as $header => $value) {
-            $this->_headers[$header] = $value;
-        }
-    }
-
-    /**
-     * Get the current value of $header
-     *
-     * @param string $header Header name to get
-     * @return string $header's current value
-     */
-    public function getHeader($header)
-    {
-        return isset($this->_headers[$header]) ? $this->_headers[$header] : null;
-    }
-}
diff --git a/framework/Http_Client/lib/Horde/Http/Client/Response.php b/framework/Http_Client/lib/Horde/Http/Client/Response.php
deleted file mode 100644 (file)
index e158e42..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-<?php
-/**
- * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
- *
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-
-/**
- * @author   Chuck Hagenbuch <chuck@horde.org>
- * @license  http://opensource.org/licenses/bsd-license.php BSD
- * @category Horde
- * @package  Horde_Http_Client
- */
-class Horde_Http_Client_Response
-{
-    /**
-     * Fetched URI
-     * @var string
-     */
-    public $uri;
-
-    /**
-     * HTTP protocol version that was used
-     * @var float
-     */
-    public $httpVersion;
-
-    /**
-     * HTTP response code
-     * @var integer
-     */
-    public $code;
-
-    /**
-     * Response headers
-     * @var array
-     */
-    public $headers;
-
-    /**
-     * Response body
-     * @var stream
-     */
-    protected $_stream;
-
-    /**
-     * Constructor
-     */
-    public function __construct($uri, $stream, $headers = array())
-    {
-        $this->uri = $uri;
-        $this->_stream = $stream;
-        $this->_parseHeaders($headers);
-    }
-
-    /**
-     * Parse an array of response headers, mindful of line
-     * continuations, etc.
-     *
-     * @param array $headers
-     * @return array
-     */
-    protected function _parseHeaders($headers)
-    {
-        if (!is_array($headers)) {
-            $headers = explode("\n", $headers);
-        }
-
-        $lastHeader = null;
-        foreach ($headers as $headerLine) {
-            // stream_get_meta returns all headers generated while processing a
-            // request, including ones for redirects before an eventually successful
-            // request. We just want the last one, so whenever we hit a new HTTP
-            // header, throw out anything parsed previously and start over.
-            if (preg_match('/^HTTP\/(\d.\d) (\d{3})/', $headerLine, $httpMatches)) {
-                $this->httpVersion = $httpMatches[1];
-                $this->code = (int)$httpMatches[2];
-                $this->headers = array();
-                $lastHeader = null;
-            }
-
-            $headerLine = trim($headerLine, "\r\n");
-            if ($headerLine == '') {
-                break;
-            }
-            if (preg_match('|^([\w-]+):\s+(.+)|', $headerLine, $m)) {
-                unset($lastHeader);
-                $headerName = strtolower($m[1]);
-                $headerValue = $m[2];
-
-                if (isset($this->headers[$headerName])) {
-                    if (!is_array($this->headers[$headerName])) {
-                        $this->headers[$headerName] = array($this->headers[$headerName]);
-                    }
-
-                    $this->headers[$headerName][] = $headerValue;
-                } else {
-                    $this->headers[$headerName] = $headerValue;
-                }
-                $lastHeader = $headerName;
-            } elseif (preg_match("|^\s+(.+)$|", $headerLine, $m) && !is_null($lastHeader)) {
-                if (is_array($this->headers[$lastHeader])) {
-                    end($this->headers[$lastHeader]);
-                    $this->headers[$lastHeader][key($this->headers[$lastHeader])] .= $m[1];
-                } else {
-                    $this->headers[$lastHeader] .= $m[1];
-                }
-            }
-        }
-    }
-
-    /**
-     * Return the body of the HTTP response.
-     *
-     * @return string HTTP response body.
-     */
-    public function getBody()
-    {
-        $content = @stream_get_contents($this->_stream);
-        if ($content === false) {
-            throw new Horde_Http_Client_Exception('Problem reading data from ' . $this->uri . ': ' . $php_errormsg);
-        }
-        return $content;
-    }
-
-    /**
-     * Return a stream pointing to the response body that can be used
-     * with all standard PHP stream functions.
-     */
-    public function getStream()
-    {
-        return $this->_stream;
-    }
-
-    /**
-     * Get the value of a single response header.
-     *
-     * @param string $header Header name to get ('Content-Type', 'Content-Length', etc.). This is case sensitive.
-     *
-     * @return string HTTP header value.
-     */
-    public function getHeader($header)
-    {
-        return isset($this->headers[$header]) ? $this->headers[$header] : null;
-    }
-
-}
diff --git a/framework/Http_Client/package.xml b/framework/Http_Client/package.xml
deleted file mode 100644 (file)
index fd1c3f2..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<package packagerversion="1.4.9" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
-http://pear.php.net/dtd/tasks-1.0.xsd
-http://pear.php.net/dtd/package-2.0
-http://pear.php.net/dtd/package-2.0.xsd">
- <name>Http_Client</name>
- <channel>pear.horde.org</channel>
- <summary>Horde HTTP client libraries</summary>
- <description>This package provides a light wrapper around PHP's stream support for performing HTTP requests.
- </description>
- <lead>
-  <name>Chuck Hagenbuch</name>
-  <user>chuck</user>
-  <email>chuck@horde.org</email>
-  <active>yes</active>
- </lead>
- <date>2008-09-06</date>
- <version>
-  <release>0.3.0</release>
-  <api>0.3.0</api>
- </version>
- <stability>
-  <release>beta</release>
-  <api>beta</api>
- </stability>
- <license uri="http://opensource.org/licenses/bsd-license.php">BSD</license>
- <notes>* Refactor the constructor and setter/getter methods to be more generic.
-* Add support for proxy servers.</notes>
- <contents>
-  <dir name="/">
-   <dir name="lib">
-    <dir name="Horde">
-     <dir name="Http">
-      <dir name="Client">
-       <dir name="Adapter">
-        <file name="Base.php" role="php" />
-        <file name="Curl.php" role="php" />
-        <file name="Fopen.php" role="php" />
-        <file name="Peclhttp.php" role="php" />
-       </dir>
-       <file name="Exception.php" role="php" />
-       <file name="Mock.php" role="php" />
-       <file name="Request.php" role="php" />
-       <file name="Response.php" role="php" />
-      </dir> <!-- /lib/Horde/Http/Client -->
-      <file name="Client.php" role="php" />
-     </dir> <!-- /lib/Horde/Http -->
-    </dir> <!-- /lib/Horde -->
-   </dir> <!-- /lib/ -->
-  </dir> <!-- / -->
- </contents>
- <dependencies>
-  <required>
-   <php>
-    <min>5.2.0</min>
-   </php>
-   <pearinstaller>
-    <min>1.5.0</min>
-   </pearinstaller>
-  </required>
- </dependencies>
- <phprelease>
-  <filelist>
-   <install name="lib/Horde/Http/Client/Adapter/Base.php" as="Horde/Http/Client/Adapter/Base.php" />
-   <install name="lib/Horde/Http/Client/Adapter/Curl.php" as="Horde/Http/Client/Adapter/Curl.php" />
-   <install name="lib/Horde/Http/Client/Adapter/Fopen.php" as="Horde/Http/Client/Adapter/Fopen.php" />
-   <install name="lib/Horde/Http/Client/Adapter/Peclhttp.php" as="Horde/Http/Client/Adapter/Peclhttp.php" />
-   <install name="lib/Horde/Http/Client/Exception.php" as="Horde/Http/Client/Exception.php" />
-   <install name="lib/Horde/Http/Client/Mock.php" as="Horde/Http/Client/Mock.php" />
-   <install name="lib/Horde/Http/Client/Request.php" as="Horde/Http/Client/Request.php" />
-   <install name="lib/Horde/Http/Client/Response.php" as="Horde/Http/Client/Response.php" />
-   <install name="lib/Horde/Http/Client.php" as="Horde/Http/Client.php" />
-  </filelist>
- </phprelease>
-</package>
diff --git a/framework/Http_Client/test/Horde/Http/Client/Adapter/FopenTest.php b/framework/Http_Client/test/Horde/Http/Client/Adapter/FopenTest.php
deleted file mode 100644 (file)
index f9f5632..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-<?php
-/**
- * @category   Horde
- * @package    Http_Client
- * @subpackage UnitTests
- * @copyright  2007-2009 The Horde Project (http://www.horde.org/)
- * @license    http://opensource.org/licenses/bsd-license.php
- */
-
-/**
- * @group      support
- * @category   Horde
- * @package    Http_Client
- * @subpackage UnitTests
- * @copyright  2007-2009 The Horde Project (http://www.horde.org/)
- * @license    http://opensource.org/licenses/bsd-license.php
- */
-class Horde_Http_Client_Adapter_FopenTest extends PHPUnit_Framework_TestCase
-{
-    public function testThrowsOnBadUri()
-    {
-        $client = new Horde_Http_Client(array('adapter' => new Horde_Http_Client_Adapter_Fopen()));
-        try {
-            $response = $client->get('http://doesntexist.example.com/');
-            $this->fail();
-        } catch (Horde_Http_Client_Exception $e) {
-        }
-    }
-
-    public function testReturnsResponseInsteadOfExceptionOn404()
-    {
-        $client = new Horde_Http_Client(array('adapter' => new Horde_Http_Client_Adapter_Fopen()));
-        $response = $client->get('http://example.com/doesntexist');
-        $this->assertEquals(404, $response->code);
-    }
-}
diff --git a/framework/Http_Client/test/Horde/Http/Client/AllTests.php b/framework/Http_Client/test/Horde/Http/Client/AllTests.php
deleted file mode 100644 (file)
index f2bc7e3..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-/**
- * @category   Horde
- * @package    Http_Client
- * @subpackage UnitTests
- * @copyright  2008-2009 The Horde Project (http://www.horde.org/)
- * @license    http://opensource.org/licenses/bsd-license.php
- */
-
-if (!defined('PHPUnit_MAIN_METHOD')) {
-    define('PHPUnit_MAIN_METHOD', 'Horde_Http_Client_AllTests::main');
-}
-
-require_once 'PHPUnit/Framework/TestSuite.php';
-require_once 'PHPUnit/TextUI/TestRunner.php';
-
-class Horde_Http_Client_AllTests {
-
-    public static function main()
-    {
-        PHPUnit_TextUI_TestRunner::run(self::suite());
-    }
-
-    public static function suite()
-    {
-        set_include_path(dirname(__FILE__) . '/../../../../lib' . PATH_SEPARATOR . get_include_path());
-        if (!spl_autoload_functions()) {
-            spl_autoload_register(create_function('$class', '$filename = str_replace(array(\'::\', \'_\'), \'/\', $class); include "$filename.php";'));
-        }
-
-        $suite = new PHPUnit_Framework_TestSuite('Horde Framework - Horde_Http_Client');
-
-        $basedir = dirname(__FILE__);
-        $baseregexp = preg_quote($basedir . DIRECTORY_SEPARATOR, '/');
-
-        foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($basedir)) as $file) {
-            if ($file->isFile() && preg_match('/Test.php$/', $file->getFilename())) {
-                $pathname = $file->getPathname();
-                require $pathname;
-
-                $class = str_replace(DIRECTORY_SEPARATOR, '_',
-                                     preg_replace("/^$baseregexp(.*)\.php/", '\\1', $pathname));
-                $suite->addTestSuite('Horde_Http_Client_' . $class);
-            }
-        }
-
-        return $suite;
-    }
-
-}
-
-if (PHPUnit_MAIN_METHOD == 'Horde_Http_Client_AllTests::main') {
-    Horde_Http_Client_AllTests::main();
-}