*\r
* LICENSE:\r
*\r
- * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
+ * Copyright (c) 2008-2012, Alexey Borzov <avb@php.net>\r
* All rights reserved.\r
*\r
* Redistribution and use in source and binary forms, with or without\r
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
- * @version SVN: $Id: Curl.php 310800 2011-05-06 07:29:56Z avb $\r
- * @link http://pear.php.net/package/HTTP_Request2\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version SVN: $Id: Curl.php 324746 2012-04-03 15:09:16Z avb $\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
\r
/**\r
/**\r
* Adapter for HTTP_Request2 wrapping around cURL extension\r
*\r
- * @category HTTP\r
- * @package HTTP_Request2\r
- * @author Alexey Borzov <avb@php.net>\r
- * @version Release: 2.0.0RC1\r
+ * @category HTTP\r
+ * @package HTTP_Request2\r
+ * @author Alexey Borzov <avb@php.net>\r
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version Release: 2.1.1\r
+ * @link http://pear.php.net/package/HTTP_Request2\r
*/\r
class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter\r
{\r
- /**\r
- * Mapping of header names to cURL options\r
- * @var array\r
- */\r
+ /**\r
+ * Mapping of header names to cURL options\r
+ * @var array\r
+ */\r
protected static $headerMap = array(\r
'accept-encoding' => CURLOPT_ENCODING,\r
'cookie' => CURLOPT_COOKIE,\r
'user-agent' => CURLOPT_USERAGENT\r
);\r
\r
- /**\r
- * Mapping of SSL context options to cURL options\r
- * @var array\r
- */\r
+ /**\r
+ * Mapping of SSL context options to cURL options\r
+ * @var array\r
+ */\r
protected static $sslContextMap = array(\r
'ssl_verify_peer' => CURLOPT_SSL_VERIFYPEER,\r
'ssl_cafile' => CURLOPT_CAINFO,\r
'ssl_capath' => CURLOPT_CAPATH,\r
'ssl_local_cert' => CURLOPT_SSLCERT,\r
'ssl_passphrase' => CURLOPT_SSLCERTPASSWD\r
- );\r
+ );\r
\r
- /**\r
- * Mapping of CURLE_* constants to Exception subclasses and error codes\r
- * @var array\r
- */\r
+ /**\r
+ * Mapping of CURLE_* constants to Exception subclasses and error codes\r
+ * @var array\r
+ */\r
protected static $errorMap = array(\r
CURLE_UNSUPPORTED_PROTOCOL => array('HTTP_Request2_MessageException',\r
HTTP_Request2_Exception::NON_HTTP_REDIRECT),\r
CURLE_BAD_CONTENT_ENCODING => array('HTTP_Request2_MessageException'),\r
);\r
\r
- /**\r
- * Response being received\r
- * @var HTTP_Request2_Response\r
- */\r
+ /**\r
+ * Response being received\r
+ * @var HTTP_Request2_Response\r
+ */\r
protected $response;\r
\r
- /**\r
- * Whether 'sentHeaders' event was sent to observers\r
- * @var boolean\r
- */\r
+ /**\r
+ * Whether 'sentHeaders' event was sent to observers\r
+ * @var boolean\r
+ */\r
protected $eventSentHeaders = false;\r
\r
- /**\r
- * Whether 'receivedHeaders' event was sent to observers\r
- * @var boolean\r
- */\r
+ /**\r
+ * Whether 'receivedHeaders' event was sent to observers\r
+ * @var boolean\r
+ */\r
protected $eventReceivedHeaders = false;\r
\r
- /**\r
- * Position within request body\r
- * @var integer\r
- * @see callbackReadBody()\r
- */\r
+ /**\r
+ * Position within request body\r
+ * @var integer\r
+ * @see callbackReadBody()\r
+ */\r
protected $position = 0;\r
\r
- /**\r
- * Information about last transfer, as returned by curl_getinfo()\r
- * @var array\r
- */\r
+ /**\r
+ * Information about last transfer, as returned by curl_getinfo()\r
+ * @var array\r
+ */\r
protected $lastInfo;\r
\r
- /**\r
- * Creates a subclass of HTTP_Request2_Exception from curl error data\r
- *\r
- * @param resource curl handle\r
- * @return HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Creates a subclass of HTTP_Request2_Exception from curl error data\r
+ *\r
+ * @param resource $ch curl handle\r
+ *\r
+ * @return HTTP_Request2_Exception\r
+ */\r
protected static function wrapCurlError($ch)\r
{\r
$nativeCode = curl_errno($ch);\r
}\r
}\r
\r
- /**\r
- * Sends request to the remote server and returns its response\r
- *\r
- * @param HTTP_Request2\r
- * @return HTTP_Request2_Response\r
- * @throws HTTP_Request2_Exception\r
- */\r
+ /**\r
+ * Sends request to the remote server and returns its response\r
+ *\r
+ * @param HTTP_Request2 $request HTTP request message\r
+ *\r
+ * @return HTTP_Request2_Response\r
+ * @throws HTTP_Request2_Exception\r
+ */\r
public function sendRequest(HTTP_Request2 $request)\r
{\r
if (!extension_loaded('curl')) {\r
return $response;\r
}\r
\r
- /**\r
- * Returns information about last transfer\r
- *\r
- * @return array associative array as returned by curl_getinfo()\r
- */\r
+ /**\r
+ * Returns information about last transfer\r
+ *\r
+ * @return array associative array as returned by curl_getinfo()\r
+ */\r
public function getInfo()\r
{\r
return $this->lastInfo;\r
}\r
\r
- /**\r
- * Creates a new cURL handle and populates it with data from the request\r
- *\r
- * @return resource a cURL handle, as created by curl_init()\r
- * @throws HTTP_Request2_LogicException\r
- */\r
+ /**\r
+ * Creates a new cURL handle and populates it with data from the request\r
+ *\r
+ * @return resource a cURL handle, as created by curl_init()\r
+ * @throws HTTP_Request2_LogicException\r
+ */\r
protected function createCurlHandle()\r
{\r
$ch = curl_init();\r
\r
// set HTTP version\r
switch ($this->request->getConfig('protocol_version')) {\r
- case '1.0':\r
- curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);\r
- break;\r
- case '1.1':\r
- curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);\r
+ case '1.0':\r
+ curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);\r
+ break;\r
+ case '1.1':\r
+ curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);\r
}\r
\r
// set request method\r
switch ($this->request->getMethod()) {\r
- case HTTP_Request2::METHOD_GET:\r
- curl_setopt($ch, CURLOPT_HTTPGET, true);\r
- break;\r
- case HTTP_Request2::METHOD_POST:\r
- curl_setopt($ch, CURLOPT_POST, true);\r
- break;\r
- case HTTP_Request2::METHOD_HEAD:\r
- curl_setopt($ch, CURLOPT_NOBODY, true);\r
- break;\r
- case HTTP_Request2::METHOD_PUT:\r
- curl_setopt($ch, CURLOPT_UPLOAD, true);\r
- break;\r
- default:\r
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod());\r
+ case HTTP_Request2::METHOD_GET:\r
+ curl_setopt($ch, CURLOPT_HTTPGET, true);\r
+ break;\r
+ case HTTP_Request2::METHOD_POST:\r
+ curl_setopt($ch, CURLOPT_POST, true);\r
+ break;\r
+ case HTTP_Request2::METHOD_HEAD:\r
+ curl_setopt($ch, CURLOPT_NOBODY, true);\r
+ break;\r
+ case HTTP_Request2::METHOD_PUT:\r
+ curl_setopt($ch, CURLOPT_UPLOAD, true);\r
+ break;\r
+ default:\r
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->request->getMethod());\r
}\r
\r
// set proxy, if needed\r
}\r
curl_setopt($ch, CURLOPT_PROXY, $host . ':' . $port);\r
if ($user = $this->request->getConfig('proxy_user')) {\r
- curl_setopt($ch, CURLOPT_PROXYUSERPWD, $user . ':' .\r
- $this->request->getConfig('proxy_password'));\r
+ curl_setopt(\r
+ $ch, CURLOPT_PROXYUSERPWD,\r
+ $user . ':' . $this->request->getConfig('proxy_password')\r
+ );\r
switch ($this->request->getConfig('proxy_auth_scheme')) {\r
- case HTTP_Request2::AUTH_BASIC:\r
- curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);\r
- break;\r
- case HTTP_Request2::AUTH_DIGEST:\r
- curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);\r
+ case HTTP_Request2::AUTH_BASIC:\r
+ curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);\r
+ break;\r
+ case HTTP_Request2::AUTH_DIGEST:\r
+ curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);\r
+ }\r
+ }\r
+ if ($type = $this->request->getConfig('proxy_type')) {\r
+ switch ($type) {\r
+ case 'http':\r
+ curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);\r
+ break;\r
+ case 'socks5':\r
+ curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);\r
+ break;\r
+ default:\r
+ throw new HTTP_Request2_NotImplementedException(\r
+ "Proxy type '{$type}' is not supported"\r
+ );\r
}\r
}\r
}\r
if ($auth = $this->request->getAuth()) {\r
curl_setopt($ch, CURLOPT_USERPWD, $auth['user'] . ':' . $auth['password']);\r
switch ($auth['scheme']) {\r
- case HTTP_Request2::AUTH_BASIC:\r
- curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);\r
- break;\r
- case HTTP_Request2::AUTH_DIGEST:\r
- curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);\r
+ case HTTP_Request2::AUTH_BASIC:\r
+ curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);\r
+ break;\r
+ case HTTP_Request2::AUTH_DIGEST:\r
+ curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);\r
}\r
}\r
\r
return $ch;\r
}\r
\r
- /**\r
- * Workaround for PHP bug #47204 that prevents rewinding request body\r
- *\r
- * The workaround consists of reading the entire request body into memory\r
- * and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large\r
- * file uploads, use Socket adapter instead.\r
- *\r
- * @param resource cURL handle\r
- * @param array Request headers\r
- */\r
+ /**\r
+ * Workaround for PHP bug #47204 that prevents rewinding request body\r
+ *\r
+ * The workaround consists of reading the entire request body into memory\r
+ * and setting it as CURLOPT_POSTFIELDS, so it isn't recommended for large\r
+ * file uploads, use Socket adapter instead.\r
+ *\r
+ * @param resource $ch cURL handle\r
+ * @param array &$headers Request headers\r
+ */\r
protected function workaroundPhpBug47204($ch, &$headers)\r
{\r
// no redirects, no digest auth -> probably no rewind needed\r
) {\r
curl_setopt($ch, CURLOPT_READFUNCTION, array($this, 'callbackReadBody'));\r
\r
- // rewind may be needed, read the whole body into memory\r
} else {\r
+ // rewind may be needed, read the whole body into memory\r
if ($this->requestBody instanceof HTTP_Request2_MultipartBody) {\r
$this->requestBody = $this->requestBody->__toString();\r
\r
}\r
}\r
\r
- /**\r
- * Callback function called by cURL for reading the request body\r
- *\r
- * @param resource cURL handle\r
- * @param resource file descriptor (not used)\r
- * @param integer maximum length of data to return\r
- * @return string part of the request body, up to $length bytes\r
- */\r
+ /**\r
+ * Callback function called by cURL for reading the request body\r
+ *\r
+ * @param resource $ch cURL handle\r
+ * @param resource $fd file descriptor (not used)\r
+ * @param integer $length maximum length of data to return\r
+ *\r
+ * @return string part of the request body, up to $length bytes\r
+ */\r
protected function callbackReadBody($ch, $fd, $length)\r
{\r
if (!$this->eventSentHeaders) {\r
);\r
$this->eventSentHeaders = true;\r
}\r
- if (in_array($this->request->getMethod(), self::$bodyDisallowed) ||\r
- 0 == $this->contentLength || $this->position >= $this->contentLength\r
+ if (in_array($this->request->getMethod(), self::$bodyDisallowed)\r
+ || 0 == $this->contentLength || $this->position >= $this->contentLength\r
) {\r
return '';\r
}\r
return $string;\r
}\r
\r
- /**\r
- * Callback function called by cURL for saving the response headers\r
- *\r
- * @param resource cURL handle\r
- * @param string response header (with trailing CRLF)\r
- * @return integer number of bytes saved\r
- * @see HTTP_Request2_Response::parseHeaderLine()\r
- */\r
+ /**\r
+ * Callback function called by cURL for saving the response headers\r
+ *\r
+ * @param resource $ch cURL handle\r
+ * @param string $string response header (with trailing CRLF)\r
+ *\r
+ * @return integer number of bytes saved\r
+ * @see HTTP_Request2_Response::parseHeaderLine()\r
+ */\r
protected function callbackWriteHeader($ch, $string)\r
{\r
// we may receive a second set of headers if doing e.g. digest auth\r
if ($this->eventReceivedHeaders || !$this->eventSentHeaders) {\r
// don't bother with 100-Continue responses (bug #15785)\r
- if (!$this->eventSentHeaders ||\r
- $this->response->getStatus() >= 200\r
+ if (!$this->eventSentHeaders\r
+ || $this->response->getStatus() >= 200\r
) {\r
$this->request->setLastEvent(\r
'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)\r
return strlen($string);\r
}\r
\r
- /**\r
- * Callback function called by cURL for saving the response body\r
- *\r
- * @param resource cURL handle (not used)\r
- * @param string part of the response body\r
- * @return integer number of bytes saved\r
- * @see HTTP_Request2_Response::appendBody()\r
- */\r
+ /**\r
+ * Callback function called by cURL for saving the response body\r
+ *\r
+ * @param resource $ch cURL handle (not used)\r
+ * @param string $string part of the response body\r
+ *\r
+ * @return integer number of bytes saved\r
+ * @throws HTTP_Request2_MessageException\r
+ * @see HTTP_Request2_Response::appendBody()\r
+ */\r
protected function callbackWriteBody($ch, $string)\r
{\r
// cURL calls WRITEFUNCTION callback without calling HEADERFUNCTION if\r