diff options
Diffstat (limited to 'zend/library/Zend/Http/Client')
| -rw-r--r-- | zend/library/Zend/Http/Client/Adapter/Curl.php | 510 | ||||
| -rw-r--r-- | zend/library/Zend/Http/Client/Adapter/Exception.php | 38 | ||||
| -rw-r--r-- | zend/library/Zend/Http/Client/Adapter/Interface.php | 78 | ||||
| -rw-r--r-- | zend/library/Zend/Http/Client/Adapter/Proxy.php | 343 | ||||
| -rw-r--r-- | zend/library/Zend/Http/Client/Adapter/Socket.php | 543 | ||||
| -rwxr-xr-x | zend/library/Zend/Http/Client/Adapter/Stream.php | 46 | ||||
| -rw-r--r-- | zend/library/Zend/Http/Client/Adapter/Test.php | 248 | ||||
| -rw-r--r-- | zend/library/Zend/Http/Client/Exception.php | 36 |
8 files changed, 1842 insertions, 0 deletions
diff --git a/zend/library/Zend/Http/Client/Adapter/Curl.php b/zend/library/Zend/Http/Client/Adapter/Curl.php new file mode 100644 index 0000000..a66b386 --- /dev/null +++ b/zend/library/Zend/Http/Client/Adapter/Curl.php @@ -0,0 +1,510 @@ +<?php + +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @version $Id: Curl.php 24593 2012-01-05 20:35:02Z matthew $ + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Uri_Http + */ +require_once 'Zend/Uri/Http.php'; + +/** + * @see Zend_Http_Client_Adapter_Interface + */ +require_once 'Zend/Http/Client/Adapter/Interface.php'; +/** + * @see Zend_Http_Client_Adapter_Stream + */ +require_once 'Zend/Http/Client/Adapter/Stream.php'; + +/** + * An adapter class for Zend_Http_Client based on the curl extension. + * Curl requires libcurl. See for full requirements the PHP manual: http://php.net/curl + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Http_Client_Adapter_Curl implements Zend_Http_Client_Adapter_Interface, Zend_Http_Client_Adapter_Stream +{ + /** + * Parameters array + * + * @var array + */ + protected $_config = array(); + + /** + * What host/port are we connected to? + * + * @var array + */ + protected $_connected_to = array(null, null); + + /** + * The curl session handle + * + * @var resource|null + */ + protected $_curl = null; + + /** + * List of cURL options that should never be overwritten + * + * @var array + */ + protected $_invalidOverwritableCurlOptions; + + /** + * Response gotten from server + * + * @var string + */ + protected $_response = null; + + /** + * Stream for storing output + * + * @var resource + */ + protected $out_stream; + + /** + * Adapter constructor + * + * Config is set using setConfig() + * + * @return void + * @throws Zend_Http_Client_Adapter_Exception + */ + public function __construct() + { + if (!extension_loaded('curl')) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('cURL extension has to be loaded to use this Zend_Http_Client adapter.'); + } + $this->_invalidOverwritableCurlOptions = array( + CURLOPT_HTTPGET, + CURLOPT_POST, + CURLOPT_PUT, + CURLOPT_CUSTOMREQUEST, + CURLOPT_HEADER, + CURLOPT_RETURNTRANSFER, + CURLOPT_HTTPHEADER, + CURLOPT_POSTFIELDS, + CURLOPT_INFILE, + CURLOPT_INFILESIZE, + CURLOPT_PORT, + CURLOPT_MAXREDIRS, + CURLOPT_CONNECTTIMEOUT, + CURL_HTTP_VERSION_1_1, + CURL_HTTP_VERSION_1_0, + ); + } + + /** + * Set the configuration array for the adapter + * + * @throws Zend_Http_Client_Adapter_Exception + * @param Zend_Config | array $config + * @return Zend_Http_Client_Adapter_Curl + */ + public function setConfig($config = array()) + { + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + + } elseif (! is_array($config)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Array or Zend_Config object expected, got ' . gettype($config) + ); + } + + if(isset($config['proxy_user']) && isset($config['proxy_pass'])) { + $this->setCurlOption(CURLOPT_PROXYUSERPWD, $config['proxy_user'].":".$config['proxy_pass']); + unset($config['proxy_user'], $config['proxy_pass']); + } + + foreach ($config as $k => $v) { + $option = strtolower($k); + switch($option) { + case 'proxy_host': + $this->setCurlOption(CURLOPT_PROXY, $v); + break; + case 'proxy_port': + $this->setCurlOption(CURLOPT_PROXYPORT, $v); + break; + default: + $this->_config[$option] = $v; + break; + } + } + + return $this; + } + + /** + * Retrieve the array of all configuration options + * + * @return array + */ + public function getConfig() + { + return $this->_config; + } + + /** + * Direct setter for cURL adapter related options. + * + * @param string|int $option + * @param mixed $value + * @return Zend_Http_Adapter_Curl + */ + public function setCurlOption($option, $value) + { + if (!isset($this->_config['curloptions'])) { + $this->_config['curloptions'] = array(); + } + $this->_config['curloptions'][$option] = $value; + return $this; + } + + /** + * Initialize curl + * + * @param string $host + * @param int $port + * @param boolean $secure + * @return void + * @throws Zend_Http_Client_Adapter_Exception if unable to connect + */ + public function connect($host, $port = 80, $secure = false) + { + // If we're already connected, disconnect first + if ($this->_curl) { + $this->close(); + } + + // If we are connected to a different server or port, disconnect first + if ($this->_curl + && is_array($this->_connected_to) + && ($this->_connected_to[0] != $host + || $this->_connected_to[1] != $port) + ) { + $this->close(); + } + + // Do the actual connection + $this->_curl = curl_init(); + if ($port != 80) { + curl_setopt($this->_curl, CURLOPT_PORT, intval($port)); + } + + // Set timeout + curl_setopt($this->_curl, CURLOPT_CONNECTTIMEOUT, $this->_config['timeout']); + + // Set Max redirects + curl_setopt($this->_curl, CURLOPT_MAXREDIRS, $this->_config['maxredirects']); + + if (!$this->_curl) { + $this->close(); + + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Unable to Connect to ' . $host . ':' . $port); + } + + if ($secure !== false) { + // Behave the same like Zend_Http_Adapter_Socket on SSL options. + if (isset($this->_config['sslcert'])) { + curl_setopt($this->_curl, CURLOPT_SSLCERT, $this->_config['sslcert']); + } + if (isset($this->_config['sslpassphrase'])) { + curl_setopt($this->_curl, CURLOPT_SSLCERTPASSWD, $this->_config['sslpassphrase']); + } + } + + // Update connected_to + $this->_connected_to = array($host, $port); + } + + /** + * Send request to the remote server + * + * @param string $method + * @param Zend_Uri_Http $uri + * @param float $http_ver + * @param array $headers + * @param string $body + * @return string $request + * @throws Zend_Http_Client_Adapter_Exception If connection fails, connected to wrong host, no PUT file defined, unsupported method, or unsupported cURL option + */ + public function write($method, $uri, $httpVersion = 1.1, $headers = array(), $body = '') + { + // Make sure we're properly connected + if (!$this->_curl) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Trying to write but we are not connected"); + } + + if ($this->_connected_to[0] != $uri->getHost() || $this->_connected_to[1] != $uri->getPort()) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Trying to write but we are connected to the wrong host"); + } + + // set URL + curl_setopt($this->_curl, CURLOPT_URL, $uri->__toString()); + + // ensure correct curl call + $curlValue = true; + switch ($method) { + case Zend_Http_Client::GET: + $curlMethod = CURLOPT_HTTPGET; + break; + + case Zend_Http_Client::POST: + $curlMethod = CURLOPT_POST; + break; + + case Zend_Http_Client::PUT: + // There are two different types of PUT request, either a Raw Data string has been set + // or CURLOPT_INFILE and CURLOPT_INFILESIZE are used. + if(is_resource($body)) { + $this->_config['curloptions'][CURLOPT_INFILE] = $body; + } + if (isset($this->_config['curloptions'][CURLOPT_INFILE])) { + // Now we will probably already have Content-Length set, so that we have to delete it + // from $headers at this point: + foreach ($headers AS $k => $header) { + if (preg_match('/Content-Length:\s*(\d+)/i', $header, $m)) { + if(is_resource($body)) { + $this->_config['curloptions'][CURLOPT_INFILESIZE] = (int)$m[1]; + } + unset($headers[$k]); + } + } + + if (!isset($this->_config['curloptions'][CURLOPT_INFILESIZE])) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Cannot set a file-handle for cURL option CURLOPT_INFILE without also setting its size in CURLOPT_INFILESIZE."); + } + + if(is_resource($body)) { + $body = ''; + } + + $curlMethod = CURLOPT_PUT; + } else { + $curlMethod = CURLOPT_CUSTOMREQUEST; + $curlValue = "PUT"; + } + break; + + case Zend_Http_Client::DELETE: + $curlMethod = CURLOPT_CUSTOMREQUEST; + $curlValue = "DELETE"; + break; + + case Zend_Http_Client::OPTIONS: + $curlMethod = CURLOPT_CUSTOMREQUEST; + $curlValue = "OPTIONS"; + break; + + case Zend_Http_Client::TRACE: + $curlMethod = CURLOPT_CUSTOMREQUEST; + $curlValue = "TRACE"; + break; + + case Zend_Http_Client::HEAD: + $curlMethod = CURLOPT_CUSTOMREQUEST; + $curlValue = "HEAD"; + break; + + default: + // For now, through an exception for unsupported request methods + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Method currently not supported"); + } + + if(is_resource($body) && $curlMethod != CURLOPT_PUT) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception("Streaming requests are allowed only with PUT"); + } + + // get http version to use + $curlHttp = ($httpVersion == 1.1) ? CURL_HTTP_VERSION_1_1 : CURL_HTTP_VERSION_1_0; + + // mark as HTTP request and set HTTP method + curl_setopt($this->_curl, $curlHttp, true); + curl_setopt($this->_curl, $curlMethod, $curlValue); + + if($this->out_stream) { + // headers will be read into the response + curl_setopt($this->_curl, CURLOPT_HEADER, false); + curl_setopt($this->_curl, CURLOPT_HEADERFUNCTION, array($this, "readHeader")); + // and data will be written into the file + curl_setopt($this->_curl, CURLOPT_FILE, $this->out_stream); + } else { + // ensure headers are also returned + curl_setopt($this->_curl, CURLOPT_HEADER, true); + + // ensure actual response is returned + curl_setopt($this->_curl, CURLOPT_RETURNTRANSFER, true); + } + + // set additional headers + $headers['Accept'] = ''; + curl_setopt($this->_curl, CURLOPT_HTTPHEADER, $headers); + + /** + * Make sure POSTFIELDS is set after $curlMethod is set: + * @link http://de2.php.net/manual/en/function.curl-setopt.php#81161 + */ + if ($method == Zend_Http_Client::POST) { + curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $body); + } elseif ($curlMethod == CURLOPT_PUT) { + // this covers a PUT by file-handle: + // Make the setting of this options explicit (rather than setting it through the loop following a bit lower) + // to group common functionality together. + curl_setopt($this->_curl, CURLOPT_INFILE, $this->_config['curloptions'][CURLOPT_INFILE]); + curl_setopt($this->_curl, CURLOPT_INFILESIZE, $this->_config['curloptions'][CURLOPT_INFILESIZE]); + unset($this->_config['curloptions'][CURLOPT_INFILE]); + unset($this->_config['curloptions'][CURLOPT_INFILESIZE]); + } elseif ($method == Zend_Http_Client::PUT) { + // This is a PUT by a setRawData string, not by file-handle + curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $body); + } elseif ($method == Zend_Http_Client::DELETE) { + // This is a DELETE by a setRawData string + curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $body); + } + + // set additional curl options + if (isset($this->_config['curloptions'])) { + foreach ((array)$this->_config['curloptions'] as $k => $v) { + if (!in_array($k, $this->_invalidOverwritableCurlOptions)) { + if (curl_setopt($this->_curl, $k, $v) == false) { + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception(sprintf("Unknown or erroreous cURL option '%s' set", $k)); + } + } + } + } + + // send the request + $response = curl_exec($this->_curl); + + // if we used streaming, headers are already there + if(!is_resource($this->out_stream)) { + $this->_response = $response; + } + + $request = curl_getinfo($this->_curl, CURLINFO_HEADER_OUT); + $request .= $body; + + if (empty($this->_response)) { + require_once 'Zend/Http/Client/Exception.php'; + throw new Zend_Http_Client_Exception("Error in cURL request: " . curl_error($this->_curl)); + } + + // cURL automatically decodes chunked-messages, this means we have to disallow the Zend_Http_Response to do it again + if (stripos($this->_response, "Transfer-Encoding: chunked\r\n")) { + $this->_response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $this->_response); + } + + // Eliminate multiple HTTP responses. + do { + $parts = preg_split('|(?:\r?\n){2}|m', $this->_response, 2); + $again = false; + + if (isset($parts[1]) && preg_match("|^HTTP/1\.[01](.*?)\r\n|mi", $parts[1])) { + $this->_response = $parts[1]; + $again = true; + } + } while ($again); + + // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string: + if (stripos($this->_response, "HTTP/1.0 200 Connection established\r\n\r\n") !== false) { + $this->_response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $this->_response); + } + + return $request; + } + + /** + * Return read response from server + * + * @return string + */ + public function read() + { + return $this->_response; + } + + /** + * Close the connection to the server + * + */ + public function close() + { + if(is_resource($this->_curl)) { + curl_close($this->_curl); + } + $this->_curl = null; + $this->_connected_to = array(null, null); + } + + /** + * Get cUrl Handle + * + * @return resource + */ + public function getHandle() + { + return $this->_curl; + } + + /** + * Set output stream for the response + * + * @param resource $stream + * @return Zend_Http_Client_Adapter_Socket + */ + public function setOutputStream($stream) + { + $this->out_stream = $stream; + return $this; + } + + /** + * Header reader function for CURL + * + * @param resource $curl + * @param string $header + * @return int + */ + public function readHeader($curl, $header) + { + $this->_response .= $header; + return strlen($header); + } +} diff --git a/zend/library/Zend/Http/Client/Adapter/Exception.php b/zend/library/Zend/Http/Client/Adapter/Exception.php new file mode 100644 index 0000000..6416175 --- /dev/null +++ b/zend/library/Zend/Http/Client/Adapter/Exception.php @@ -0,0 +1,38 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter_Exception + * @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $ + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Http_Client_Exception + */ +require_once 'Zend/Http/Client/Exception.php'; + +/** + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Http_Client_Adapter_Exception extends Zend_Http_Client_Exception +{ + const READ_TIMEOUT = 1000; +} diff --git a/zend/library/Zend/Http/Client/Adapter/Interface.php b/zend/library/Zend/Http/Client/Adapter/Interface.php new file mode 100644 index 0000000..1a0eddd --- /dev/null +++ b/zend/library/Zend/Http/Client/Adapter/Interface.php @@ -0,0 +1,78 @@ +<?php + +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @version $Id: Interface.php 24593 2012-01-05 20:35:02Z matthew $ + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * An interface description for Zend_Http_Client_Adapter classes. + * + * These classes are used as connectors for Zend_Http_Client, performing the + * tasks of connecting, writing, reading and closing connection to the server. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +interface Zend_Http_Client_Adapter_Interface +{ + /** + * Set the configuration array for the adapter + * + * @param array $config + */ + public function setConfig($config = array()); + + /** + * Connect to the remote server + * + * @param string $host + * @param int $port + * @param boolean $secure + */ + public function connect($host, $port = 80, $secure = false); + + /** + * Send request to the remote server + * + * @param string $method + * @param Zend_Uri_Http $url + * @param string $http_ver + * @param array $headers + * @param string $body + * @return string Request as text + */ + public function write($method, $url, $http_ver = '1.1', $headers = array(), $body = ''); + + /** + * Read response from server + * + * @return string + */ + public function read(); + + /** + * Close the connection to the server + * + */ + public function close(); +} diff --git a/zend/library/Zend/Http/Client/Adapter/Proxy.php b/zend/library/Zend/Http/Client/Adapter/Proxy.php new file mode 100644 index 0000000..2ca3012 --- /dev/null +++ b/zend/library/Zend/Http/Client/Adapter/Proxy.php @@ -0,0 +1,343 @@ +<?php + +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @version $Id: Proxy.php 25273 2013-03-06 08:02:21Z frosch $ + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Uri_Http + */ +require_once 'Zend/Uri/Http.php'; +/** + * @see Zend_Http_Client + */ +require_once 'Zend/Http/Client.php'; +/** + * @see Zend_Http_Client_Adapter_Socket + */ +require_once 'Zend/Http/Client/Adapter/Socket.php'; + +/** + * HTTP Proxy-supporting Zend_Http_Client adapter class, based on the default + * socket based adapter. + * + * Should be used if proxy HTTP access is required. If no proxy is set, will + * fall back to Zend_Http_Client_Adapter_Socket behavior. Just like the + * default Socket adapter, this adapter does not require any special extensions + * installed. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Http_Client_Adapter_Proxy extends Zend_Http_Client_Adapter_Socket +{ + /** + * Parameters array + * + * @var array + */ + protected $config = array( + 'ssltransport' => 'ssl', + 'sslcert' => null, + 'sslpassphrase' => null, + 'sslusecontext' => false, + 'proxy_host' => '', + 'proxy_port' => 8080, + 'proxy_user' => '', + 'proxy_pass' => '', + 'proxy_auth' => Zend_Http_Client::AUTH_BASIC, + 'persistent' => false, + ); + + /** + * Whether HTTPS CONNECT was already negotiated with the proxy or not + * + * @var boolean + */ + protected $negotiated = false; + + /** + * Stores the last CONNECT handshake request + * + * @var string + */ + protected $connectHandshakeRequest; + + /** + * Connect to the remote server + * + * Will try to connect to the proxy server. If no proxy was set, will + * fall back to the target server (behave like regular Socket adapter) + * + * @param string $host + * @param int $port + * @param boolean $secure + */ + public function connect($host, $port = 80, $secure = false) + { + // If no proxy is set, fall back to Socket adapter + if (!$this->config['proxy_host']) { + return parent::connect($host, $port, $secure); + } + + /* Url might require stream context even if proxy connection doesn't */ + if ($secure) { + $this->config['sslusecontext'] = true; + } + + // Connect (a non-secure connection) to the proxy server + return parent::connect( + $this->config['proxy_host'], + $this->config['proxy_port'], + false + ); + } + + /** + * Send request to the proxy server + * + * @param string $method + * @param Zend_Uri_Http $uri + * @param string $http_ver + * @param array $headers + * @param string $body + * @return string Request as string + * @throws Zend_Http_Client_Adapter_Exception + */ + public function write( + $method, $uri, $http_ver = '1.1', $headers = array(), $body = '' + ) + { + // If no proxy is set, fall back to default Socket adapter + if (!$this->config['proxy_host']) { + return parent::write($method, $uri, $http_ver, $headers, $body); + } + + // Make sure we're properly connected + if (!$this->socket) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Trying to write but we are not connected' + ); + } + + $host = $this->config['proxy_host']; + $port = $this->config['proxy_port']; + + if ($this->connected_to[0] != "tcp://$host" + || $this->connected_to[1] != $port + ) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Trying to write but we are connected to the wrong proxy server' + ); + } + + // Add Proxy-Authorization header + if ($this->config['proxy_user']) { + // Check to see if one already exists + $hasProxyAuthHeader = false; + foreach ($headers as $k => $v) { + if ((string) $k == 'proxy-authorization' + || preg_match("/^proxy-authorization:/i", $v) + ) { + $hasProxyAuthHeader = true; + break; + } + } + if (!$hasProxyAuthHeader) { + $headers[] = 'Proxy-authorization: ' + . Zend_Http_Client::encodeAuthHeader( + $this->config['proxy_user'], + $this->config['proxy_pass'], $this->config['proxy_auth'] + ); + } + } + + // if we are proxying HTTPS, preform CONNECT handshake with the proxy + if ($uri->getScheme() == 'https' && (!$this->negotiated)) { + $this->connectHandshake( + $uri->getHost(), $uri->getPort(), $http_ver, $headers + ); + $this->negotiated = true; + } + + // Save request method for later + $this->method = $method; + + // Build request headers + if ($this->negotiated) { + $path = $uri->getPath(); + if ($uri->getQuery()) { + $path .= '?' . $uri->getQuery(); + } + $request = "$method $path HTTP/$http_ver\r\n"; + } else { + $request = "$method $uri HTTP/$http_ver\r\n"; + } + + // Add all headers to the request string + foreach ($headers as $k => $v) { + if (is_string($k)) $v = "$k: $v"; + $request .= "$v\r\n"; + } + + if(is_resource($body)) { + $request .= "\r\n"; + } else { + // Add the request body + $request .= "\r\n" . $body; + } + + // Send the request + if (!@fwrite($this->socket, $request)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Error writing request to proxy server' + ); + } + + if(is_resource($body)) { + if(stream_copy_to_stream($body, $this->socket) == 0) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Error writing request to server' + ); + } + } + + return $request; + } + + /** + * Preform handshaking with HTTPS proxy using CONNECT method + * + * @param string $host + * @param integer $port + * @param string $http_ver + * @param array $headers + * @return void + * @throws Zend_Http_Client_Adapter_Exception + */ + protected function connectHandshake( + $host, $port = 443, $http_ver = '1.1', array &$headers = array() + ) + { + $request = "CONNECT $host:$port HTTP/$http_ver\r\n" . + "Host: " . $this->config['proxy_host'] . "\r\n"; + + // Process provided headers, including important ones to CONNECT request + foreach ($headers as $k => $v) { + switch (strtolower(substr($v,0,strpos($v,':')))) { + case 'proxy-authorization': + // break intentionally omitted + + case 'user-agent': + $request .= $v . "\r\n"; + break; + + default: + break; + } + } + $request .= "\r\n"; + + // @see ZF-3189 + $this->connectHandshakeRequest = $request; + + // Send the request + if (!@fwrite($this->socket, $request)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Error writing request to proxy server' + ); + } + + // Read response headers only + $response = ''; + $gotStatus = false; + while ($line = @fgets($this->socket)) { + $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false); + if ($gotStatus) { + $response .= $line; + if (!chop($line)) { + break; + } + } + } + + // Check that the response from the proxy is 200 + if (Zend_Http_Response::extractCode($response) != 200) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Unable to connect to HTTPS proxy. Server response: ' . $response + ); + } + + // If all is good, switch socket to secure mode. We have to fall back + // through the different modes + $modes = array( + STREAM_CRYPTO_METHOD_TLS_CLIENT, + STREAM_CRYPTO_METHOD_SSLv3_CLIENT, + STREAM_CRYPTO_METHOD_SSLv23_CLIENT, + STREAM_CRYPTO_METHOD_SSLv2_CLIENT + ); + + $success = false; + foreach($modes as $mode) { + $success = stream_socket_enable_crypto($this->socket, true, $mode); + if ($success) { + break; + } + } + + if (!$success) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Unable to connect to HTTPS server through proxy: could not ' + . 'negotiate secure connection.' + ); + } + } + + /** + * Close the connection to the server + * + */ + public function close() + { + parent::close(); + $this->negotiated = false; + } + + /** + * Destructor: make sure the socket is disconnected + * + */ + public function __destruct() + { + if ($this->socket) { + $this->close(); + } + } +} diff --git a/zend/library/Zend/Http/Client/Adapter/Socket.php b/zend/library/Zend/Http/Client/Adapter/Socket.php new file mode 100644 index 0000000..b2a0e9b --- /dev/null +++ b/zend/library/Zend/Http/Client/Adapter/Socket.php @@ -0,0 +1,543 @@ +<?php + +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @version $Id: Socket.php 24593 2012-01-05 20:35:02Z matthew $ + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Uri_Http + */ +require_once 'Zend/Uri/Http.php'; +/** + * @see Zend_Http_Client_Adapter_Interface + */ +require_once 'Zend/Http/Client/Adapter/Interface.php'; +/** + * @see Zend_Http_Client_Adapter_Stream + */ +require_once 'Zend/Http/Client/Adapter/Stream.php'; + +/** + * A sockets based (stream_socket_client) adapter class for Zend_Http_Client. Can be used + * on almost every PHP environment, and does not require any special extensions. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Http_Client_Adapter_Socket implements Zend_Http_Client_Adapter_Interface, Zend_Http_Client_Adapter_Stream +{ + /** + * The socket for server connection + * + * @var resource|null + */ + protected $socket = null; + + /** + * What host/port are we connected to? + * + * @var array + */ + protected $connected_to = array(null, null); + + /** + * Stream for storing output + * + * @var resource + */ + protected $out_stream = null; + + /** + * Parameters array + * + * @var array + */ + protected $config = array( + 'persistent' => false, + 'ssltransport' => 'ssl', + 'sslcert' => null, + 'sslpassphrase' => null, + 'sslusecontext' => false + ); + + /** + * Request method - will be set by write() and might be used by read() + * + * @var string + */ + protected $method = null; + + /** + * Stream context + * + * @var resource + */ + protected $_context = null; + + /** + * Adapter constructor, currently empty. Config is set using setConfig() + * + */ + public function __construct() + { + } + + /** + * Set the configuration array for the adapter + * + * @param Zend_Config | array $config + */ + public function setConfig($config = array()) + { + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + + } elseif (! is_array($config)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Array or Zend_Config object expected, got ' . gettype($config) + ); + } + + foreach ($config as $k => $v) { + $this->config[strtolower($k)] = $v; + } + } + + /** + * Retrieve the array of all configuration options + * + * @return array + */ + public function getConfig() + { + return $this->config; + } + + /** + * Set the stream context for the TCP connection to the server + * + * Can accept either a pre-existing stream context resource, or an array + * of stream options, similar to the options array passed to the + * stream_context_create() PHP function. In such case a new stream context + * will be created using the passed options. + * + * @since Zend Framework 1.9 + * + * @param mixed $context Stream context or array of context options + * @return Zend_Http_Client_Adapter_Socket + */ + public function setStreamContext($context) + { + if (is_resource($context) && get_resource_type($context) == 'stream-context') { + $this->_context = $context; + + } elseif (is_array($context)) { + $this->_context = stream_context_create($context); + + } else { + // Invalid parameter + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + "Expecting either a stream context resource or array, got " . gettype($context) + ); + } + + return $this; + } + + /** + * Get the stream context for the TCP connection to the server. + * + * If no stream context is set, will create a default one. + * + * @return resource + */ + public function getStreamContext() + { + if (! $this->_context) { + $this->_context = stream_context_create(); + } + + return $this->_context; + } + + /** + * Connect to the remote server + * + * @param string $host + * @param int $port + * @param boolean $secure + */ + public function connect($host, $port = 80, $secure = false) + { + // If the URI should be accessed via SSL, prepend the Hostname with ssl:// + $host = ($secure ? $this->config['ssltransport'] : 'tcp') . '://' . $host; + + // If we are connected to the wrong host, disconnect first + if (($this->connected_to[0] != $host || $this->connected_to[1] != $port)) { + if (is_resource($this->socket)) $this->close(); + } + + // Now, if we are not connected, connect + if (! is_resource($this->socket) || ! $this->config['keepalive']) { + $context = $this->getStreamContext(); + if ($secure || $this->config['sslusecontext']) { + if ($this->config['sslcert'] !== null) { + if (! stream_context_set_option($context, 'ssl', 'local_cert', + $this->config['sslcert'])) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Unable to set sslcert option'); + } + } + if ($this->config['sslpassphrase'] !== null) { + if (! stream_context_set_option($context, 'ssl', 'passphrase', + $this->config['sslpassphrase'])) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Unable to set sslpassphrase option'); + } + } + } + + $flags = STREAM_CLIENT_CONNECT; + if ($this->config['persistent']) $flags |= STREAM_CLIENT_PERSISTENT; + + $this->socket = @stream_socket_client($host . ':' . $port, + $errno, + $errstr, + (int) $this->config['timeout'], + $flags, + $context); + + if (! $this->socket) { + $this->close(); + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Unable to Connect to ' . $host . ':' . $port . '. Error #' . $errno . ': ' . $errstr); + } + + // Set the stream timeout + if (! stream_set_timeout($this->socket, (int) $this->config['timeout'])) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Unable to set the connection timeout'); + } + + // Update connected_to + $this->connected_to = array($host, $port); + } + } + + /** + * Send request to the remote server + * + * @param string $method + * @param Zend_Uri_Http $uri + * @param string $http_ver + * @param array $headers + * @param string $body + * @return string Request as string + */ + public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') + { + // Make sure we're properly connected + if (! $this->socket) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Trying to write but we are not connected'); + } + + $host = $uri->getHost(); + $host = (strtolower($uri->getScheme()) == 'https' ? $this->config['ssltransport'] : 'tcp') . '://' . $host; + if ($this->connected_to[0] != $host || $this->connected_to[1] != $uri->getPort()) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Trying to write but we are connected to the wrong host'); + } + + // Save request method for later + $this->method = $method; + + // Build request headers + $path = $uri->getPath(); + if ($uri->getQuery()) $path .= '?' . $uri->getQuery(); + $request = "{$method} {$path} HTTP/{$http_ver}\r\n"; + foreach ($headers as $k => $v) { + if (is_string($k)) $v = ucfirst($k) . ": $v"; + $request .= "$v\r\n"; + } + + if(is_resource($body)) { + $request .= "\r\n"; + } else { + // Add the request body + $request .= "\r\n" . $body; + } + + // Send the request + if (! @fwrite($this->socket, $request)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Error writing request to server'); + } + + if(is_resource($body)) { + if(stream_copy_to_stream($body, $this->socket) == 0) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Error writing request to server'); + } + } + + return $request; + } + + /** + * Read response from server + * + * @return string + */ + public function read() + { + // First, read headers only + $response = ''; + $gotStatus = false; + + while (($line = @fgets($this->socket)) !== false) { + $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false); + if ($gotStatus) { + $response .= $line; + if (rtrim($line) === '') break; + } + } + + $this->_checkSocketReadTimeout(); + + $statusCode = Zend_Http_Response::extractCode($response); + + // Handle 100 and 101 responses internally by restarting the read again + if ($statusCode == 100 || $statusCode == 101) return $this->read(); + + // Check headers to see what kind of connection / transfer encoding we have + $headers = Zend_Http_Response::extractHeaders($response); + + /** + * Responses to HEAD requests and 204 or 304 responses are not expected + * to have a body - stop reading here + */ + if ($statusCode == 304 || $statusCode == 204 || + $this->method == Zend_Http_Client::HEAD) { + + // Close the connection if requested to do so by the server + if (isset($headers['connection']) && $headers['connection'] == 'close') { + $this->close(); + } + return $response; + } + + // If we got a 'transfer-encoding: chunked' header + if (isset($headers['transfer-encoding'])) { + + if (strtolower($headers['transfer-encoding']) == 'chunked') { + + do { + $line = @fgets($this->socket); + $this->_checkSocketReadTimeout(); + + $chunk = $line; + + // Figure out the next chunk size + $chunksize = trim($line); + if (! ctype_xdigit($chunksize)) { + $this->close(); + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Invalid chunk size "' . + $chunksize . '" unable to read chunked body'); + } + + // Convert the hexadecimal value to plain integer + $chunksize = hexdec($chunksize); + + // Read next chunk + $read_to = ftell($this->socket) + $chunksize; + + do { + $current_pos = ftell($this->socket); + if ($current_pos >= $read_to) break; + + if($this->out_stream) { + if(stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) { + $this->_checkSocketReadTimeout(); + break; + } + } else { + $line = @fread($this->socket, $read_to - $current_pos); + if ($line === false || strlen($line) === 0) { + $this->_checkSocketReadTimeout(); + break; + } + $chunk .= $line; + } + } while (! feof($this->socket)); + + $chunk .= @fgets($this->socket); + $this->_checkSocketReadTimeout(); + + if(!$this->out_stream) { + $response .= $chunk; + } + } while ($chunksize > 0); + } else { + $this->close(); + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Cannot handle "' . + $headers['transfer-encoding'] . '" transfer encoding'); + } + + // We automatically decode chunked-messages when writing to a stream + // this means we have to disallow the Zend_Http_Response to do it again + if ($this->out_stream) { + $response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $response); + } + // Else, if we got the content-length header, read this number of bytes + } elseif (isset($headers['content-length'])) { + + // If we got more than one Content-Length header (see ZF-9404) use + // the last value sent + if (is_array($headers['content-length'])) { + $contentLength = $headers['content-length'][count($headers['content-length']) - 1]; + } else { + $contentLength = $headers['content-length']; + } + + $current_pos = ftell($this->socket); + $chunk = ''; + + for ($read_to = $current_pos + $contentLength; + $read_to > $current_pos; + $current_pos = ftell($this->socket)) { + + if($this->out_stream) { + if(@stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0) { + $this->_checkSocketReadTimeout(); + break; + } + } else { + $chunk = @fread($this->socket, $read_to - $current_pos); + if ($chunk === false || strlen($chunk) === 0) { + $this->_checkSocketReadTimeout(); + break; + } + + $response .= $chunk; + } + + // Break if the connection ended prematurely + if (feof($this->socket)) break; + } + + // Fallback: just read the response until EOF + } else { + + do { + if($this->out_stream) { + if(@stream_copy_to_stream($this->socket, $this->out_stream) == 0) { + $this->_checkSocketReadTimeout(); + break; + } + } else { + $buff = @fread($this->socket, 8192); + if ($buff === false || strlen($buff) === 0) { + $this->_checkSocketReadTimeout(); + break; + } else { + $response .= $buff; + } + } + + } while (feof($this->socket) === false); + + $this->close(); + } + + // Close the connection if requested to do so by the server + if (isset($headers['connection']) && $headers['connection'] == 'close') { + $this->close(); + } + + return $response; + } + + /** + * Close the connection to the server + * + */ + public function close() + { + if (is_resource($this->socket)) @fclose($this->socket); + $this->socket = null; + $this->connected_to = array(null, null); + } + + /** + * Check if the socket has timed out - if so close connection and throw + * an exception + * + * @throws Zend_Http_Client_Adapter_Exception with READ_TIMEOUT code + */ + protected function _checkSocketReadTimeout() + { + if ($this->socket) { + $info = stream_get_meta_data($this->socket); + $timedout = $info['timed_out']; + if ($timedout) { + $this->close(); + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + "Read timed out after {$this->config['timeout']} seconds", + Zend_Http_Client_Adapter_Exception::READ_TIMEOUT + ); + } + } + } + + /** + * Set output stream for the response + * + * @param resource $stream + * @return Zend_Http_Client_Adapter_Socket + */ + public function setOutputStream($stream) + { + $this->out_stream = $stream; + return $this; + } + + /** + * Destructor: make sure the socket is disconnected + * + * If we are in persistent TCP mode, will not close the connection + * + */ + public function __destruct() + { + if (! $this->config['persistent']) { + if ($this->socket) $this->close(); + } + } +} diff --git a/zend/library/Zend/Http/Client/Adapter/Stream.php b/zend/library/Zend/Http/Client/Adapter/Stream.php new file mode 100755 index 0000000..98f4410 --- /dev/null +++ b/zend/library/Zend/Http/Client/Adapter/Stream.php @@ -0,0 +1,46 @@ +<?php + +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @version $Id: Stream.php 24593 2012-01-05 20:35:02Z matthew $ + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * An interface description for Zend_Http_Client_Adapter_Stream classes. + * + * This interface decribes Zend_Http_Client_Adapter which supports streaming. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +interface Zend_Http_Client_Adapter_Stream +{ + /** + * Set output stream + * + * This function sets output stream where the result will be stored. + * + * @param resource $stream Stream to write the output to + * + */ + public function setOutputStream($stream); +} diff --git a/zend/library/Zend/Http/Client/Adapter/Test.php b/zend/library/Zend/Http/Client/Adapter/Test.php new file mode 100644 index 0000000..aa041af --- /dev/null +++ b/zend/library/Zend/Http/Client/Adapter/Test.php @@ -0,0 +1,248 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @version $Id: Test.php 24593 2012-01-05 20:35:02Z matthew $ + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Uri_Http + */ +require_once 'Zend/Uri/Http.php'; +/** + * @see Zend_Http_Response + */ +require_once 'Zend/Http/Response.php'; +/** + * @see Zend_Http_Client_Adapter_Interface + */ +require_once 'Zend/Http/Client/Adapter/Interface.php'; + +/** + * A testing-purposes adapter. + * + * Should be used to test all components that rely on Zend_Http_Client, + * without actually performing an HTTP request. You should instantiate this + * object manually, and then set it as the client's adapter. Then, you can + * set the expected response using the setResponse() method. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Adapter + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Http_Client_Adapter_Test implements Zend_Http_Client_Adapter_Interface +{ + /** + * Parameters array + * + * @var array + */ + protected $config = array(); + + /** + * Buffer of responses to be returned by the read() method. Can be + * set using setResponse() and addResponse(). + * + * @var array + */ + protected $responses = array("HTTP/1.1 400 Bad Request\r\n\r\n"); + + /** + * Current position in the response buffer + * + * @var integer + */ + protected $responseIndex = 0; + + /** + * Wether or not the next request will fail with an exception + * + * @var boolean + */ + protected $_nextRequestWillFail = false; + + /** + * Adapter constructor, currently empty. Config is set using setConfig() + * + */ + public function __construct() + { } + + /** + * Set the nextRequestWillFail flag + * + * @param boolean $flag + * @return Zend_Http_Client_Adapter_Test + */ + public function setNextRequestWillFail($flag) + { + $this->_nextRequestWillFail = (bool) $flag; + + return $this; + } + + /** + * Set the configuration array for the adapter + * + * @param Zend_Config | array $config + */ + public function setConfig($config = array()) + { + if ($config instanceof Zend_Config) { + $config = $config->toArray(); + + } elseif (! is_array($config)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Array or Zend_Config object expected, got ' . gettype($config) + ); + } + + foreach ($config as $k => $v) { + $this->config[strtolower($k)] = $v; + } + } + + + /** + * Connect to the remote server + * + * @param string $host + * @param int $port + * @param boolean $secure + * @param int $timeout + * @throws Zend_Http_Client_Adapter_Exception + */ + public function connect($host, $port = 80, $secure = false) + { + if ($this->_nextRequestWillFail) { + $this->_nextRequestWillFail = false; + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception('Request failed'); + } + } + + /** + * Send request to the remote server + * + * @param string $method + * @param Zend_Uri_Http $uri + * @param string $http_ver + * @param array $headers + * @param string $body + * @return string Request as string + */ + public function write($method, $uri, $http_ver = '1.1', $headers = array(), $body = '') + { + $host = $uri->getHost(); + $host = (strtolower($uri->getScheme()) == 'https' ? 'sslv2://' . $host : $host); + + // Build request headers + $path = $uri->getPath(); + if ($uri->getQuery()) $path .= '?' . $uri->getQuery(); + $request = "{$method} {$path} HTTP/{$http_ver}\r\n"; + foreach ($headers as $k => $v) { + if (is_string($k)) $v = ucfirst($k) . ": $v"; + $request .= "$v\r\n"; + } + + // Add the request body + $request .= "\r\n" . $body; + + // Do nothing - just return the request as string + + return $request; + } + + /** + * Return the response set in $this->setResponse() + * + * @return string + */ + public function read() + { + if ($this->responseIndex >= count($this->responses)) { + $this->responseIndex = 0; + } + return $this->responses[$this->responseIndex++]; + } + + /** + * Close the connection (dummy) + * + */ + public function close() + { } + + /** + * Set the HTTP response(s) to be returned by this adapter + * + * @param Zend_Http_Response|array|string $response + */ + public function setResponse($response) + { + if ($response instanceof Zend_Http_Response) { + $response = $response->asString("\r\n"); + } + + $this->responses = (array)$response; + $this->responseIndex = 0; + } + + /** + * Add another response to the response buffer. + * + * @param string Zend_Http_Response|$response + */ + public function addResponse($response) + { + if ($response instanceof Zend_Http_Response) { + $response = $response->asString("\r\n"); + } + + $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)) { + require_once 'Zend/Http/Client/Adapter/Exception.php'; + throw new Zend_Http_Client_Adapter_Exception( + 'Index out of range of response buffer size'); + } + $this->responseIndex = $index; + } + + /** + * Retrieve the array of all configuration options + * + * @return array + */ + public function getConfig() + { + return $this->config; + } +} diff --git a/zend/library/Zend/Http/Client/Exception.php b/zend/library/Zend/Http/Client/Exception.php new file mode 100644 index 0000000..278b90b --- /dev/null +++ b/zend/library/Zend/Http/Client/Exception.php @@ -0,0 +1,36 @@ +<?php +/** + * Zend Framework + * + * LICENSE + * + * This source file is subject to the new BSD license that is bundled + * with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://framework.zend.com/license/new-bsd + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@zend.com so we can send you a copy immediately. + * + * @category Zend + * @package Zend_Http + * @subpackage Client_Exception + * @version $Id: Exception.php 24593 2012-01-05 20:35:02Z matthew $ + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +/** + * @see Zend_Http_Exception + */ +require_once 'Zend/Http/Exception.php'; + +/** + * @category Zend + * @package Zend_Http + * @subpackage Client + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Http_Client_Exception extends Zend_Http_Exception +{} |
