]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Updating HTTP_Request2 to 2.3.0
authorMikael Nordfeldth <mmn@hethane.se>
Sun, 9 Jul 2017 20:17:52 +0000 (22:17 +0200)
committerMikael Nordfeldth <mmn@hethane.se>
Sun, 9 Jul 2017 20:17:52 +0000 (22:17 +0200)
Source: https://pear.php.net/package/HTTP_Request2
Release date: 2016-02-13 15:24 UTC

13 files changed:
extlib/HTTP/Request2.php
extlib/HTTP/Request2/Adapter.php
extlib/HTTP/Request2/Adapter/Curl.php
extlib/HTTP/Request2/Adapter/Mock.php
extlib/HTTP/Request2/Adapter/Socket.php
extlib/HTTP/Request2/CookieJar.php
extlib/HTTP/Request2/Exception.php
extlib/HTTP/Request2/MultipartBody.php
extlib/HTTP/Request2/Observer/Log.php
extlib/HTTP/Request2/Observer/UncompressingDownload.php [new file with mode: 0644]
extlib/HTTP/Request2/Response.php
extlib/HTTP/Request2/SOCKS5.php
extlib/HTTP/Request2/SocketWrapper.php

index d2f36e17b9cbdacc2275dedc4c8a1b97b55d85f6..b835822e04745f905b6de4894341118132e7e3ab 100644 (file)
@@ -13,7 +13,7 @@
  * @category  HTTP\r
  * @package   HTTP_Request2\r
  * @author    Alexey Borzov <avb@php.net>\r
- * @copyright 2008-2014 Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
  * @link      http://pear.php.net/package/HTTP_Request2\r
  */\r
@@ -21,7 +21,9 @@
 /**\r
  * A class representing an URL as per RFC 3986.\r
  */\r
-require_once 'Net/URL2.php';\r
+if (!class_exists('Net_URL2', true)) {\r
+    require_once 'Net/URL2.php';\r
+}\r
 \r
 /**\r
  * Exception class for HTTP_Request2 package\r
@@ -35,7 +37,7 @@ require_once 'HTTP/Request2/Exception.php';
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  * @link     http://tools.ietf.org/html/rfc2616#section-5\r
  */\r
@@ -213,7 +215,7 @@ class HTTP_Request2 implements SplSubject
             $this->setMethod($method);\r
         }\r
         $this->setHeader(\r
-            'user-agent', 'HTTP_Request2/2.2.1 ' .\r
+            'user-agent', 'HTTP_Request2/2.3.0 ' .\r
             '(http://pear.php.net/package/http_request2) PHP/' . phpversion()\r
         );\r
     }\r
@@ -794,6 +796,11 @@ class HTTP_Request2 implements SplSubject
      *                                   encoded by Content-Encoding</li>\r
      *   <li>'receivedBody'            - after receiving the complete response\r
      *                                   body, data is HTTP_Request2_Response object</li>\r
+     *   <li>'warning'                 - a problem arose during the request\r
+     *                                   that is not severe enough to throw\r
+     *                                   an Exception, data is the warning\r
+     *                                   message (string). Currently dispatched if\r
+     *                                   response body was received incompletely.</li>\r
      * </ul>\r
      * Different adapters may not send all the event types. Mock adapter does\r
      * not send any events to the observers.\r
@@ -1022,7 +1029,7 @@ class HTTP_Request2 implements SplSubject
         }\r
         // (deprecated) mime_content_type function available\r
         if (empty($info) && function_exists('mime_content_type')) {\r
-            return mime_content_type($filename);\r
+            $info = mime_content_type($filename);\r
         }\r
         return empty($info)? 'application/octet-stream': $info;\r
     }\r
index 4e4b0b10a3a3e660422ea7d8dc6775502e8fac82..035632792c82e92d4ec7e6230e297b905828abb5 100644 (file)
@@ -13,7 +13,7 @@
  * @category  HTTP\r
  * @package   HTTP_Request2\r
  * @author    Alexey Borzov <avb@php.net>\r
- * @copyright 2008-2014 Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
  * @link      http://pear.php.net/package/HTTP_Request2\r
  */\r
@@ -34,7 +34,7 @@ require_once 'HTTP/Request2/Response.php';
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  */\r
 abstract class HTTP_Request2_Adapter\r
index ef75b8c9576215eb4dfb27345df6fc4c72e232dd..13d4a2994ed033ab5a48f8f89358ce6a0ab6ee28 100644 (file)
@@ -13,7 +13,7 @@
  * @category  HTTP\r
  * @package   HTTP_Request2\r
  * @author    Alexey Borzov <avb@php.net>\r
- * @copyright 2008-2014 Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
  * @link      http://pear.php.net/package/HTTP_Request2\r
  */\r
@@ -30,7 +30,7 @@ require_once 'HTTP/Request2/Adapter.php';
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  */\r
 class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter\r
@@ -116,6 +116,12 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
      */\r
     protected $eventReceivedHeaders = false;\r
 \r
+    /**\r
+     * Whether 'sentBoody' event was sent to observers\r
+     * @var boolean\r
+     */\r
+    protected $eventSentBody = false;\r
+\r
     /**\r
      * Position within request body\r
      * @var  integer\r
@@ -171,6 +177,7 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
         $this->position             = 0;\r
         $this->eventSentHeaders     = false;\r
         $this->eventReceivedHeaders = false;\r
+        $this->eventSentBody        = false;\r
 \r
         try {\r
             if (false === curl_exec($ch = $this->createCurlHandle())) {\r
@@ -180,6 +187,9 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
         }\r
         if (isset($ch)) {\r
             $this->lastInfo = curl_getinfo($ch);\r
+            if (CURLE_OK !== curl_errno($ch)) {\r
+                $this->request->setLastEvent('warning', curl_error($ch));\r
+            }\r
             curl_close($ch);\r
         }\r
 \r
@@ -191,7 +201,7 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
         }\r
 \r
         if ($jar = $request->getCookieJar()) {\r
-            $jar->addCookiesFromResponse($response, $request->getUrl());\r
+            $jar->addCookiesFromResponse($response);\r
         }\r
 \r
         if (0 < $this->lastInfo['size_download']) {\r
@@ -400,9 +410,12 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
     protected function workaroundPhpBug47204($ch, &$headers)\r
     {\r
         // no redirects, no digest auth -> probably no rewind needed\r
+        // also apply workaround only for POSTs, othrerwise we get\r
+        // https://pear.php.net/bugs/bug.php?id=20440 for PUTs\r
         if (!$this->request->getConfig('follow_redirects')\r
             && (!($auth = $this->request->getAuth())\r
                 || HTTP_Request2::AUTH_DIGEST != $auth['scheme'])\r
+            || HTTP_Request2::METHOD_POST !== $this->request->getMethod()\r
         ) {\r
             curl_setopt($ch, CURLOPT_READFUNCTION, array($this, 'callbackReadBody'));\r
 \r
@@ -469,40 +482,36 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
      */\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
-            ) {\r
-                $this->request->setLastEvent(\r
-                    'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)\r
-                );\r
-            }\r
+        if (!$this->eventSentHeaders\r
+            // we may receive a second set of headers if doing e.g. digest auth\r
+            // but don't bother with 100-Continue responses (bug #15785)\r
+            || $this->eventReceivedHeaders && $this->response->getStatus() >= 200\r
+        ) {\r
+            $this->request->setLastEvent(\r
+                'sentHeaders', curl_getinfo($ch, CURLINFO_HEADER_OUT)\r
+            );\r
+        }\r
+        if (!$this->eventSentBody) {\r
             $upload = curl_getinfo($ch, CURLINFO_SIZE_UPLOAD);\r
-            // if body wasn't read by a callback, send event with total body size\r
+            // if body wasn't read by the callback, send event with total body size\r
             if ($upload > $this->position) {\r
                 $this->request->setLastEvent(\r
                     'sentBodyPart', $upload - $this->position\r
                 );\r
-                $this->position = $upload;\r
             }\r
-            if ($upload && (!$this->eventSentHeaders\r
-                            || $this->response->getStatus() >= 200)\r
-            ) {\r
+            if ($upload > 0) {\r
                 $this->request->setLastEvent('sentBody', $upload);\r
             }\r
-            $this->eventSentHeaders = true;\r
-            // we'll need a new response object\r
-            if ($this->eventReceivedHeaders) {\r
-                $this->eventReceivedHeaders = false;\r
-                $this->response             = null;\r
-            }\r
         }\r
-        if (empty($this->response)) {\r
-            $this->response = new HTTP_Request2_Response(\r
+        $this->eventSentHeaders = true;\r
+        $this->eventSentBody    = true;\r
+\r
+        if ($this->eventReceivedHeaders || empty($this->response)) {\r
+            $this->eventReceivedHeaders = false;\r
+            $this->response             = new HTTP_Request2_Response(\r
                 $string, false, curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)\r
             );\r
+\r
         } else {\r
             $this->response->parseHeaderLine($string);\r
             if ('' == trim($string)) {\r
@@ -522,7 +531,7 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
                     }\r
 \r
                     if ($jar = $this->request->getCookieJar()) {\r
-                        $jar->addCookiesFromResponse($this->response, $this->request->getUrl());\r
+                        $jar->addCookiesFromResponse($this->response);\r
                         if (!$redirectUrl->isAbsolute()) {\r
                             $redirectUrl = $this->request->getUrl()->resolve($redirectUrl);\r
                         }\r
@@ -532,6 +541,7 @@ class HTTP_Request2_Adapter_Curl extends HTTP_Request2_Adapter
                     }\r
                 }\r
                 $this->eventReceivedHeaders = true;\r
+                $this->eventSentBody        = false;\r
             }\r
         }\r
         return strlen($string);\r
index d6e274ab9a1dc05b6a0d9c22fe4e5079d5cfb52c..22b428244410e82e18e31b98fa4c98d57521490a 100644 (file)
@@ -13,7 +13,7 @@
  * @category  HTTP\r
  * @package   HTTP_Request2\r
  * @author    Alexey Borzov <avb@php.net>\r
- * @copyright 2008-2014 Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
  * @link      http://pear.php.net/package/HTTP_Request2\r
  */\r
@@ -44,7 +44,7 @@ require_once 'HTTP/Request2/Adapter.php';
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  */\r
 class HTTP_Request2_Adapter_Mock extends HTTP_Request2_Adapter\r
index 7946b0a37410cb8af78078431813dbc97017cb1a..3a1d18606b69dd9897277750606d29879053c6a7 100644 (file)
@@ -13,7 +13,7 @@
  * @category  HTTP\r
  * @package   HTTP_Request2\r
  * @author    Alexey Borzov <avb@php.net>\r
- * @copyright 2008-2014 Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
  * @link      http://pear.php.net/package/HTTP_Request2\r
  */\r
@@ -34,7 +34,7 @@ require_once 'HTTP/Request2/SocketWrapper.php';
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  */\r
 class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter\r
@@ -147,7 +147,7 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
 \r
 \r
             if ($jar = $request->getCookieJar()) {\r
-                $jar->addCookiesFromResponse($response, $request->getUrl());\r
+                $jar->addCookiesFromResponse($response);\r
             }\r
 \r
             if (!$this->canKeepAlive($keepAlive, $response)) {\r
@@ -261,9 +261,16 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
             foreach ($this->request->getConfig() as $name => $value) {\r
                 if ('ssl_' == substr($name, 0, 4) && null !== $value) {\r
                     if ('ssl_verify_host' == $name) {\r
-                        if ($value) {\r
-                            $options['ssl']['CN_match'] = $reqHost;\r
+                        if (version_compare(phpversion(), '5.6', '<')) {\r
+                            if ($value) {\r
+                                $options['ssl']['CN_match'] = $reqHost;\r
+                            }\r
+\r
+                        } else {\r
+                            $options['ssl']['verify_peer_name'] = $value;\r
+                            $options['ssl']['peer_name']        = $reqHost;\r
                         }\r
+\r
                     } else {\r
                         $options['ssl'][substr($name, 4)] = $value;\r
                     }\r
@@ -281,7 +288,7 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
 \r
         // Changing SSL context options after connection is established does *not*\r
         // work, we need a new connection if options change\r
-        $remote    = ((!$secure || $httpProxy || $socksProxy)? 'tcp://': 'ssl://')\r
+        $remote    = ((!$secure || $httpProxy || $socksProxy)? 'tcp://': 'tls://')\r
                      . $host . ':' . $port;\r
         $socketKey = $remote . (\r
                         ($secure && $httpProxy || $socksProxy)\r
@@ -312,12 +319,12 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
                     $conninfo = "tcp://{$reqHost}:{$reqPort} via {$remote}";\r
                 } else {\r
                     $this->socket->enableCrypto();\r
-                    $conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";\r
+                    $conninfo = "tls://{$reqHost}:{$reqPort} via {$remote}";\r
                 }\r
 \r
             } elseif ($secure && $httpProxy && !$tunnel) {\r
                 $this->establishTunnel();\r
-                $conninfo = "ssl://{$reqHost}:{$reqPort} via {$remote}";\r
+                $conninfo = "tls://{$reqHost}:{$reqPort} via {$remote}";\r
 \r
             } else {\r
                 $this->socket = new HTTP_Request2_SocketWrapper(\r
@@ -1043,14 +1050,14 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
         $chunked = 'chunked' == $response->getHeader('transfer-encoding');\r
         $length  = $response->getHeader('content-length');\r
         $hasBody = false;\r
-        if ($chunked || null === $length || 0 < intval($length)) {\r
-            // RFC 2616, section 4.4:\r
-            // 3. ... If a message is received with both a\r
-            // Transfer-Encoding header field and a Content-Length header field,\r
-            // the latter MUST be ignored.\r
-            $toRead = ($chunked || null === $length)? null: $length;\r
-            $this->chunkLength = 0;\r
+        // RFC 2616, section 4.4:\r
+        // 3. ... If a message is received with both a\r
+        // Transfer-Encoding header field and a Content-Length header field,\r
+        // the latter MUST be ignored.\r
+        $toRead  = ($chunked || null === $length)? null: $length;\r
+        $this->chunkLength = 0;\r
 \r
+        if ($chunked || null === $length || 0 < intval($length)) {\r
             while (!$this->socket->eof() && (is_null($toRead) || 0 < $toRead)) {\r
                 if ($chunked) {\r
                     $data = $this->readChunked($bufferSize);\r
@@ -1075,6 +1082,11 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
                 }\r
             }\r
         }\r
+        if (0 !== $this->chunkLength || null !== $toRead && $toRead > 0) {\r
+            $this->request->setLastEvent(\r
+                'warning', 'transfer closed with outstanding read data remaining'\r
+            );\r
+        }\r
 \r
         if ($hasBody) {\r
             $this->request->setLastEvent('receivedBody', $response);\r
@@ -1095,11 +1107,16 @@ class HTTP_Request2_Adapter_Socket extends HTTP_Request2_Adapter
         // at start of the next chunk?\r
         if (0 == $this->chunkLength) {\r
             $line = $this->socket->readLine($bufferSize);\r
-            if (!preg_match('/^([0-9a-f]+)/i', $line, $matches)) {\r
+            if ('' === $line && $this->socket->eof()) {\r
+                $this->chunkLength = -1; // indicate missing chunk\r
+                return '';\r
+\r
+            } elseif (!preg_match('/^([0-9a-f]+)/i', $line, $matches)) {\r
                 throw new HTTP_Request2_MessageException(\r
                     "Cannot decode chunked response, invalid chunk length '{$line}'",\r
                     HTTP_Request2_Exception::DECODE_ERROR\r
                 );\r
+\r
             } else {\r
                 $this->chunkLength = hexdec($matches[1]);\r
                 // Chunk with zero length indicates the end\r
index 79ac08bb7578073967e19c27ec8762eb4415d299..f191e2551fe5a8ef34c31282f82f11c4ccdf4329 100644 (file)
@@ -13,7 +13,7 @@
  * @category  HTTP\r
  * @package   HTTP_Request2\r
  * @author    Alexey Borzov <avb@php.net>\r
- * @copyright 2008-2014 Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
  * @link      http://pear.php.net/package/HTTP_Request2\r
  */\r
@@ -61,6 +61,12 @@ class HTTP_Request2_CookieJar implements Serializable
      */\r
     protected $useList = true;\r
 \r
+    /**\r
+     * Whether an attempt to store an invalid cookie should be ignored, rather than cause an Exception\r
+     * @var bool\r
+     */\r
+    protected $ignoreInvalid = false;\r
+\r
     /**\r
      * Array with Public Suffix List data\r
      * @var  array\r
@@ -75,12 +81,16 @@ class HTTP_Request2_CookieJar implements Serializable
      *                                      see {@link serializeSessionCookies()}\r
      * @param bool $usePublicSuffixList     Controls using Public Suffix List,\r
      *                                      see {@link usePublicSuffixList()}\r
+     * @param bool $ignoreInvalidCookies    Whether invalid cookies should be ignored,\r
+     *                                      see {@link ignoreInvalidCookies()}\r
      */\r
     public function __construct(\r
-        $serializeSessionCookies = false, $usePublicSuffixList = true\r
+        $serializeSessionCookies = false, $usePublicSuffixList = true,\r
+        $ignoreInvalidCookies = false\r
     ) {\r
         $this->serializeSessionCookies($serializeSessionCookies);\r
         $this->usePublicSuffixList($usePublicSuffixList);\r
+        $this->ignoreInvalidCookies($ignoreInvalidCookies);\r
     }\r
 \r
     /**\r
@@ -194,11 +204,20 @@ class HTTP_Request2_CookieJar implements Serializable
      *                         {@link HTTP_Request2_Response::getCookies()}\r
      * @param Net_URL2 $setter URL of the document that sent Set-Cookie header\r
      *\r
-     * @throws   HTTP_Request2_Exception\r
+     * @return bool whether the cookie was successfully stored\r
+     * @throws HTTP_Request2_Exception\r
      */\r
     public function store(array $cookie, Net_URL2 $setter = null)\r
     {\r
-        $cookie = $this->checkAndUpdateFields($cookie, $setter);\r
+        try {\r
+            $cookie = $this->checkAndUpdateFields($cookie, $setter);\r
+        } catch (HTTP_Request2_Exception $e) {\r
+            if ($this->ignoreInvalid) {\r
+                return false;\r
+            } else {\r
+                throw $e;\r
+            }\r
+        }\r
 \r
         if (strlen($cookie['value'])\r
             && (is_null($cookie['expires']) || $cookie['expires'] > $this->now())\r
@@ -214,6 +233,8 @@ class HTTP_Request2_CookieJar implements Serializable
         } elseif (isset($this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']])) {\r
             unset($this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']]);\r
         }\r
+\r
+        return true;\r
     }\r
 \r
     /**\r
@@ -221,13 +242,29 @@ class HTTP_Request2_CookieJar implements Serializable
      *\r
      * @param HTTP_Request2_Response $response HTTP response message\r
      * @param Net_URL2               $setter   original request URL, needed for\r
-     *                               setting default domain/path\r
+     *                               setting default domain/path. If not given,\r
+     *                               effective URL from response will be used.\r
+     *\r
+     * @return bool whether all cookies were successfully stored\r
+     * @throws HTTP_Request2_LogicException\r
      */\r
-    public function addCookiesFromResponse(HTTP_Request2_Response $response, Net_URL2 $setter)\r
+    public function addCookiesFromResponse(HTTP_Request2_Response $response, Net_URL2 $setter = null)\r
     {\r
+        if (null === $setter) {\r
+            if (!($effectiveUrl = $response->getEffectiveUrl())) {\r
+                throw new HTTP_Request2_LogicException(\r
+                    'Response URL required for adding cookies from response',\r
+                    HTTP_Request2_Exception::MISSING_VALUE\r
+                );\r
+            }\r
+            $setter = new Net_URL2($effectiveUrl);\r
+        }\r
+\r
+        $success = true;\r
         foreach ($response->getCookies() as $cookie) {\r
-            $this->store($cookie, $setter);\r
+            $success = $this->store($cookie, $setter) && $success;\r
         }\r
+        return $success;\r
     }\r
 \r
     /**\r
@@ -306,6 +343,18 @@ class HTTP_Request2_CookieJar implements Serializable
         $this->serializeSession = (bool)$serialize;\r
     }\r
 \r
+    /**\r
+     * Sets whether invalid cookies should be silently ignored or cause an Exception\r
+     *\r
+     * @param boolean $ignore ignore?\r
+     * @link http://pear.php.net/bugs/bug.php?id=19937\r
+     * @link http://pear.php.net/bugs/bug.php?id=20401\r
+     */\r
+    public function ignoreInvalidCookies($ignore)\r
+    {\r
+        $this->ignoreInvalid = (bool)$ignore;\r
+    }\r
+\r
     /**\r
      * Sets whether Public Suffix List should be used for restricting cookie-setting\r
      *\r
@@ -352,7 +401,8 @@ class HTTP_Request2_CookieJar implements Serializable
         return serialize(array(\r
             'cookies'          => $cookies,\r
             'serializeSession' => $this->serializeSession,\r
-            'useList'          => $this->useList\r
+            'useList'          => $this->useList,\r
+            'ignoreInvalid'    => $this->ignoreInvalid\r
         ));\r
     }\r
 \r
@@ -369,6 +419,9 @@ class HTTP_Request2_CookieJar implements Serializable
         $now  = $this->now();\r
         $this->serializeSessionCookies($data['serializeSession']);\r
         $this->usePublicSuffixList($data['useList']);\r
+        if (array_key_exists('ignoreInvalid', $data)) {\r
+            $this->ignoreInvalidCookies($data['ignoreInvalid']);\r
+        }\r
         foreach ($data['cookies'] as $cookie) {\r
             if (!empty($cookie['expires']) && $cookie['expires'] <= $now) {\r
                 continue;\r
index d0b5d4ee099acd3af2a1f0009fa14836aee95689..de9432df8c9f075989b36a75ac55f7b38e8d2673 100644 (file)
@@ -13,7 +13,7 @@
  * @category  HTTP\r
  * @package   HTTP_Request2\r
  * @author    Alexey Borzov <avb@php.net>\r
- * @copyright 2008-2014 Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
  * @link      http://pear.php.net/package/HTTP_Request2\r
  */\r
@@ -30,7 +30,7 @@ require_once 'PEAR/Exception.php';
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  * @link     http://pear.php.net/pepr/pepr-proposal-show.php?id=132\r
  */\r
@@ -97,7 +97,7 @@ class HTTP_Request2_Exception extends PEAR_Exception
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  */\r
 class HTTP_Request2_NotImplementedException extends HTTP_Request2_Exception\r
@@ -118,7 +118,7 @@ class HTTP_Request2_NotImplementedException extends HTTP_Request2_Exception
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  */\r
 class HTTP_Request2_LogicException extends HTTP_Request2_Exception\r
@@ -135,7 +135,7 @@ class HTTP_Request2_LogicException extends HTTP_Request2_Exception
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  */\r
 class HTTP_Request2_ConnectionException extends HTTP_Request2_Exception\r
@@ -151,7 +151,7 @@ class HTTP_Request2_ConnectionException extends HTTP_Request2_Exception
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  */\r
 class HTTP_Request2_MessageException extends HTTP_Request2_Exception\r
index c68b6602b8ab0634d68f25f49653ed42e82dd9df..e5a3845952a7b25316becd7954e1b6858eb739ef 100644 (file)
@@ -13,7 +13,7 @@
  * @category  HTTP\r
  * @package   HTTP_Request2\r
  * @author    Alexey Borzov <avb@php.net>\r
- * @copyright 2008-2014 Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
  * @link      http://pear.php.net/package/HTTP_Request2\r
  */\r
@@ -31,7 +31,7 @@ require_once 'HTTP/Request2/Exception.php';
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  * @link     http://tools.ietf.org/html/rfc1867\r
  */\r
index 341e29907ee5fca0739afb99e99fef45bf17bb28..069baf8e951b30d19428c8f90fc68f7fc75dcafc 100644 (file)
@@ -14,7 +14,7 @@
  * @package   HTTP_Request2\r
  * @author    David Jean Louis <izi@php.net>\r
  * @author    Alexey Borzov <avb@php.net>\r
- * @copyright 2008-2014 Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
  * @link      http://pear.php.net/package/HTTP_Request2\r
  */\r
@@ -64,7 +64,7 @@ require_once 'HTTP/Request2/Exception.php';
  * @author   David Jean Louis <izi@php.net>\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  */\r
 class HTTP_Request2_Observer_Log implements SplObserver\r
diff --git a/extlib/HTTP/Request2/Observer/UncompressingDownload.php b/extlib/HTTP/Request2/Observer/UncompressingDownload.php
new file mode 100644 (file)
index 0000000..8a3430a
--- /dev/null
@@ -0,0 +1,265 @@
+<?php\r
+/**\r
+ * An observer that saves response body to stream, possibly uncompressing it\r
+ *\r
+ * PHP version 5\r
+ *\r
+ * LICENSE\r
+ *\r
+ * This source file is subject to BSD 3-Clause License that is bundled\r
+ * with this package in the file LICENSE and available at the URL\r
+ * https://raw.github.com/pear/HTTP_Request2/trunk/docs/LICENSE\r
+ *\r
+ * @category  HTTP\r
+ * @package   HTTP_Request2\r
+ * @author    Delian Krustev <krustev@krustev.net>\r
+ * @author    Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
+ * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
+ * @link      http://pear.php.net/package/HTTP_Request2\r
+ */\r
+\r
+require_once 'HTTP/Request2/Response.php';\r
+\r
+/**\r
+ * An observer that saves response body to stream, possibly uncompressing it\r
+ *\r
+ * This Observer is written in compliment to pear's HTTP_Request2 in order to\r
+ * avoid reading the whole response body in memory. Instead it writes the body\r
+ * to a stream. If the body is transferred with content-encoding set to\r
+ * "deflate" or "gzip" it is decoded on the fly.\r
+ *\r
+ * The constructor accepts an already opened (for write) stream (file_descriptor).\r
+ * If the response is deflate/gzip encoded a "zlib.inflate" filter is applied\r
+ * to the stream. When the body has been read from the request and written to\r
+ * the stream ("receivedBody" event) the filter is removed from the stream.\r
+ *\r
+ * The "zlib.inflate" filter works fine with pure "deflate" encoding. It does\r
+ * not understand the "deflate+zlib" and "gzip" headers though, so they have to\r
+ * be removed prior to being passed to the stream. This is done in the "update"\r
+ * method.\r
+ *\r
+ * It is also possible to limit the size of written extracted bytes by passing\r
+ * "max_bytes" to the constructor. This is important because e.g. 1GB of\r
+ * zeroes take about a MB when compressed.\r
+ *\r
+ * Exceptions are being thrown if data could not be written to the stream or\r
+ * the written bytes have already exceeded the requested maximum. If the "gzip"\r
+ * header is malformed or could not be parsed an exception will be thrown too.\r
+ *\r
+ * Example usage follows:\r
+ *\r
+ * <code>\r
+ * require_once 'HTTP/Request2.php';\r
+ * require_once 'HTTP/Request2/Observer/UncompressingDownload.php';\r
+ *\r
+ * #$inPath = 'http://carsten.codimi.de/gzip.yaws/daniels.html';\r
+ * #$inPath = 'http://carsten.codimi.de/gzip.yaws/daniels.html?deflate=on';\r
+ * $inPath = 'http://carsten.codimi.de/gzip.yaws/daniels.html?deflate=on&zlib=on';\r
+ * #$outPath = "/dev/null";\r
+ * $outPath = "delme";\r
+ *\r
+ * $stream = fopen($outPath, 'wb');\r
+ * if (!$stream) {\r
+ *     throw new Exception('fopen failed');\r
+ * }\r
+ *\r
+ * $request = new HTTP_Request2(\r
+ *     $inPath,\r
+ *     HTTP_Request2::METHOD_GET,\r
+ *     array(\r
+ *         'store_body'        => false,\r
+ *         'connect_timeout'   => 5,\r
+ *         'timeout'           => 10,\r
+ *         'ssl_verify_peer'   => true,\r
+ *         'ssl_verify_host'   => true,\r
+ *         'ssl_cafile'        => null,\r
+ *         'ssl_capath'        => '/etc/ssl/certs',\r
+ *         'max_redirects'     => 10,\r
+ *         'follow_redirects'  => true,\r
+ *         'strict_redirects'  => false\r
+ *     )\r
+ * );\r
+ *\r
+ * $observer = new HTTP_Request2_Observer_UncompressingDownload($stream, 9999999);\r
+ * $request->attach($observer);\r
+ *\r
+ * $response = $request->send();\r
+ *\r
+ * fclose($stream);\r
+ * echo "OK\n";\r
+ * </code>\r
+ *\r
+ * @category HTTP\r
+ * @package  HTTP_Request2\r
+ * @author   Delian Krustev <krustev@krustev.net>\r
+ * @author   Alexey Borzov <avb@php.net>\r
+ * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
+ * @version  Release: 2.3.0\r
+ * @link     http://pear.php.net/package/HTTP_Request2\r
+ */\r
+class HTTP_Request2_Observer_UncompressingDownload implements SplObserver\r
+{\r
+    /**\r
+     * The stream to write response body to\r
+     * @var resource\r
+     */\r
+    private $_stream;\r
+\r
+    /**\r
+     * zlib.inflate filter possibly added to stream\r
+     * @var resource\r
+     */\r
+    private $_streamFilter;\r
+\r
+    /**\r
+     * The value of response's Content-Encoding header\r
+     * @var string\r
+     */\r
+    private $_encoding;\r
+\r
+    /**\r
+     * Whether the observer is still waiting for gzip/deflate header\r
+     * @var bool\r
+     */\r
+    private $_processingHeader = true;\r
+\r
+    /**\r
+     * Starting position in the stream observer writes to\r
+     * @var int\r
+     */\r
+    private $_startPosition = 0;\r
+\r
+    /**\r
+     * Maximum bytes to write\r
+     * @var int|null\r
+     */\r
+    private $_maxDownloadSize;\r
+\r
+    /**\r
+     * Whether response being received is a redirect\r
+     * @var bool\r
+     */\r
+    private $_redirect = false;\r
+\r
+    /**\r
+     * Accumulated body chunks that may contain (gzip) header\r
+     * @var string\r
+     */\r
+    private $_possibleHeader = '';\r
+\r
+    /**\r
+     * Class constructor\r
+     *\r
+     * Note that there might be problems with max_bytes and files bigger\r
+     * than 2 GB on 32bit platforms\r
+     *\r
+     * @param resource $stream          a stream (or file descriptor) opened for writing.\r
+     * @param int      $maxDownloadSize maximum bytes to write\r
+     */\r
+    public function __construct($stream, $maxDownloadSize = null)\r
+    {\r
+        $this->_stream = $stream;\r
+        if ($maxDownloadSize) {\r
+            $this->_maxDownloadSize = $maxDownloadSize;\r
+            $this->_startPosition   = ftell($this->_stream);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Called when the request notifies us of an event.\r
+     *\r
+     * @param SplSubject $request The HTTP_Request2 instance\r
+     *\r
+     * @return void\r
+     * @throws HTTP_Request2_MessageException\r
+     */\r
+    public function update(SplSubject $request)\r
+    {\r
+        /* @var $request HTTP_Request2 */\r
+        $event   = $request->getLastEvent();\r
+        $encoded = false;\r
+\r
+        /* @var $event['data'] HTTP_Request2_Response */\r
+        switch ($event['name']) {\r
+        case 'receivedHeaders':\r
+            $this->_processingHeader = true;\r
+            $this->_redirect = $event['data']->isRedirect();\r
+            $this->_encoding = strtolower($event['data']->getHeader('content-encoding'));\r
+            $this->_possibleHeader = '';\r
+            break;\r
+\r
+        case 'receivedEncodedBodyPart':\r
+            if (!$this->_streamFilter\r
+                && ($this->_encoding === 'deflate' || $this->_encoding === 'gzip')\r
+            ) {\r
+                $this->_streamFilter = stream_filter_append(\r
+                    $this->_stream, 'zlib.inflate', STREAM_FILTER_WRITE\r
+                );\r
+            }\r
+            $encoded = true;\r
+            // fall-through is intentional\r
+\r
+        case 'receivedBodyPart':\r
+            if ($this->_redirect) {\r
+                break;\r
+            }\r
+\r
+            if (!$encoded || !$this->_processingHeader) {\r
+                $bytes = fwrite($this->_stream, $event['data']);\r
+\r
+            } else {\r
+                $offset = 0;\r
+                $this->_possibleHeader .= $event['data'];\r
+                if ('deflate' === $this->_encoding) {\r
+                    if (2 > strlen($this->_possibleHeader)) {\r
+                        break;\r
+                    }\r
+                    $header = unpack('n', substr($this->_possibleHeader, 0, 2));\r
+                    if (0 == $header[1] % 31) {\r
+                        $offset = 2;\r
+                    }\r
+\r
+                } elseif ('gzip' === $this->_encoding) {\r
+                    if (10 > strlen($this->_possibleHeader)) {\r
+                        break;\r
+                    }\r
+                    try {\r
+                        $offset = HTTP_Request2_Response::parseGzipHeader($this->_possibleHeader, false);\r
+\r
+                    } catch (HTTP_Request2_MessageException $e) {\r
+                        // need more data?\r
+                        if (false !== strpos($e->getMessage(), 'data too short')) {\r
+                            break;\r
+                        }\r
+                        throw $e;\r
+                    }\r
+                }\r
+\r
+                $this->_processingHeader = false;\r
+                $bytes = fwrite($this->_stream, substr($this->_possibleHeader, $offset));\r
+            }\r
+\r
+            if (false === $bytes) {\r
+                throw new HTTP_Request2_MessageException('fwrite failed.');\r
+            }\r
+\r
+            if ($this->_maxDownloadSize\r
+                && ftell($this->_stream) - $this->_startPosition > $this->_maxDownloadSize\r
+            ) {\r
+                throw new HTTP_Request2_MessageException(sprintf(\r
+                    'Body length limit (%d bytes) reached',\r
+                    $this->_maxDownloadSize\r
+                ));\r
+            }\r
+            break;\r
+\r
+        case 'receivedBody':\r
+            if ($this->_streamFilter) {\r
+                stream_filter_remove($this->_streamFilter);\r
+                $this->_streamFilter = null;\r
+            }\r
+            break;\r
+        }\r
+    }\r
+}\r
index d2f414cf6c3518ff567c81ee6c4315b45ea940cf..b144fdae09cc4ab1e3ecdd241599a8a6db23d8d5 100644 (file)
@@ -13,7 +13,7 @@
  * @category  HTTP\r
  * @package   HTTP_Request2\r
  * @author    Alexey Borzov <avb@php.net>\r
- * @copyright 2008-2014 Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
  * @link      http://pear.php.net/package/HTTP_Request2\r
  */\r
@@ -47,7 +47,7 @@ require_once 'HTTP/Request2/Exception.php';
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  * @link     http://tools.ietf.org/html/rfc2616#section-6\r
  */\r
@@ -465,32 +465,46 @@ class HTTP_Request2_Response
     }\r
 \r
     /**\r
-     * Decodes the message-body encoded by gzip\r
+     * Checks whether data starts with GZIP format identification bytes from RFC 1952\r
      *\r
-     * The real decoding work is done by gzinflate() built-in function, this\r
-     * method only parses the header and checks data for compliance with\r
-     * RFC 1952\r
+     * @param string $data gzip-encoded (presumably) data\r
      *\r
-     * @param string $data gzip-encoded data\r
+     * @return bool\r
+     */\r
+    public static function hasGzipIdentification($data)\r
+    {\r
+        return 0 === strcmp(substr($data, 0, 2), "\x1f\x8b");\r
+    }\r
+\r
+    /**\r
+     * Tries to parse GZIP format header in the given string\r
      *\r
-     * @return   string  decoded data\r
-     * @throws   HTTP_Request2_LogicException\r
-     * @throws   HTTP_Request2_MessageException\r
-     * @link     http://tools.ietf.org/html/rfc1952\r
+     * If the header conforms to RFC 1952, its length is returned. If any\r
+     * sanity check fails, HTTP_Request2_MessageException is thrown.\r
+     *\r
+     * Note: This function might be usable outside of HTTP_Request2 so it might\r
+     * be good idea to be moved to some common package. (Delian Krustev)\r
+     *\r
+     * @param string  $data         Either the complete response body or\r
+     *                              the leading part of it\r
+     * @param boolean $dataComplete Whether $data contains complete response body\r
+     *\r
+     * @return int  gzip header length in bytes\r
+     * @throws HTTP_Request2_MessageException\r
+     * @link   http://tools.ietf.org/html/rfc1952\r
      */\r
-    public static function decodeGzip($data)\r
+    public static function parseGzipHeader($data, $dataComplete = false)\r
     {\r
-        $length = strlen($data);\r
-        // If it doesn't look like gzip-encoded data, don't bother\r
-        if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) {\r
-            return $data;\r
-        }\r
-        if (!function_exists('gzinflate')) {\r
-            throw new HTTP_Request2_LogicException(\r
-                'Unable to decode body: gzip extension not available',\r
-                HTTP_Request2_Exception::MISCONFIGURATION\r
+        // if data is complete, trailing 8 bytes should be present for size and crc32\r
+        $length = strlen($data) - ($dataComplete ? 8 : 0);\r
+\r
+        if ($length < 10 || !self::hasGzipIdentification($data)) {\r
+            throw new HTTP_Request2_MessageException(\r
+                'The data does not seem to contain a valid gzip header',\r
+                HTTP_Request2_Exception::DECODE_ERROR\r
             );\r
         }\r
+\r
         $method = ord(substr($data, 2, 1));\r
         if (8 != $method) {\r
             throw new HTTP_Request2_MessageException(\r
@@ -510,14 +524,14 @@ class HTTP_Request2_Response
         $headerLength = 10;\r
         // extra fields, need to skip 'em\r
         if ($flags & 4) {\r
-            if ($length - $headerLength - 2 < 8) {\r
+            if ($length - $headerLength - 2 < 0) {\r
                 throw new HTTP_Request2_MessageException(\r
                     'Error parsing gzip header: data too short',\r
                     HTTP_Request2_Exception::DECODE_ERROR\r
                 );\r
             }\r
             $extraLength = unpack('v', substr($data, 10, 2));\r
-            if ($length - $headerLength - 2 - $extraLength[1] < 8) {\r
+            if ($length - $headerLength - 2 - $extraLength[1] < 0) {\r
                 throw new HTTP_Request2_MessageException(\r
                     'Error parsing gzip header: data too short',\r
                     HTTP_Request2_Exception::DECODE_ERROR\r
@@ -527,14 +541,16 @@ class HTTP_Request2_Response
         }\r
         // file name, need to skip that\r
         if ($flags & 8) {\r
-            if ($length - $headerLength - 1 < 8) {\r
+            if ($length - $headerLength - 1 < 0) {\r
                 throw new HTTP_Request2_MessageException(\r
                     'Error parsing gzip header: data too short',\r
                     HTTP_Request2_Exception::DECODE_ERROR\r
                 );\r
             }\r
             $filenameLength = strpos(substr($data, $headerLength), chr(0));\r
-            if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) {\r
+            if (false === $filenameLength\r
+                || $length - $headerLength - $filenameLength - 1 < 0\r
+            ) {\r
                 throw new HTTP_Request2_MessageException(\r
                     'Error parsing gzip header: data too short',\r
                     HTTP_Request2_Exception::DECODE_ERROR\r
@@ -544,14 +560,16 @@ class HTTP_Request2_Response
         }\r
         // comment, need to skip that also\r
         if ($flags & 16) {\r
-            if ($length - $headerLength - 1 < 8) {\r
+            if ($length - $headerLength - 1 < 0) {\r
                 throw new HTTP_Request2_MessageException(\r
                     'Error parsing gzip header: data too short',\r
                     HTTP_Request2_Exception::DECODE_ERROR\r
                 );\r
             }\r
             $commentLength = strpos(substr($data, $headerLength), chr(0));\r
-            if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) {\r
+            if (false === $commentLength\r
+                || $length - $headerLength - $commentLength - 1 < 0\r
+            ) {\r
                 throw new HTTP_Request2_MessageException(\r
                     'Error parsing gzip header: data too short',\r
                     HTTP_Request2_Exception::DECODE_ERROR\r
@@ -561,7 +579,7 @@ class HTTP_Request2_Response
         }\r
         // have a CRC for header. let's check\r
         if ($flags & 2) {\r
-            if ($length - $headerLength - 2 < 8) {\r
+            if ($length - $headerLength - 2 < 0) {\r
                 throw new HTTP_Request2_MessageException(\r
                     'Error parsing gzip header: data too short',\r
                     HTTP_Request2_Exception::DECODE_ERROR\r
@@ -577,12 +595,43 @@ class HTTP_Request2_Response
             }\r
             $headerLength += 2;\r
         }\r
+        return $headerLength;\r
+    }\r
+\r
+    /**\r
+     * Decodes the message-body encoded by gzip\r
+     *\r
+     * The real decoding work is done by gzinflate() built-in function, this\r
+     * method only parses the header and checks data for compliance with\r
+     * RFC 1952\r
+     *\r
+     * @param string $data gzip-encoded data\r
+     *\r
+     * @return   string  decoded data\r
+     * @throws   HTTP_Request2_LogicException\r
+     * @throws   HTTP_Request2_MessageException\r
+     * @link     http://tools.ietf.org/html/rfc1952\r
+     */\r
+    public static function decodeGzip($data)\r
+    {\r
+        // If it doesn't look like gzip-encoded data, don't bother\r
+        if (!self::hasGzipIdentification($data)) {\r
+            return $data;\r
+        }\r
+        if (!function_exists('gzinflate')) {\r
+            throw new HTTP_Request2_LogicException(\r
+                'Unable to decode body: gzip extension not available',\r
+                HTTP_Request2_Exception::MISCONFIGURATION\r
+            );\r
+        }\r
+\r
         // unpacked data CRC and size at the end of encoded data\r
         $tmp = unpack('V2', substr($data, -8));\r
         $dataCrc  = $tmp[1];\r
         $dataSize = $tmp[2];\r
 \r
-        // finally, call the gzinflate() function\r
+        $headerLength = self::parseGzipHeader($data, true);\r
+\r
         // don't pass $dataSize to gzinflate, see bugs #13135, #14370\r
         $unpacked = gzinflate(substr($data, $headerLength, -8));\r
         if (false === $unpacked) {\r
@@ -596,7 +645,7 @@ class HTTP_Request2_Response
                 HTTP_Request2_Exception::DECODE_ERROR\r
             );\r
         } elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) {\r
-            throw new HTTP_Request2_Exception(\r
+            throw new HTTP_Request2_MessageException(\r
                 'Data CRC check failed',\r
                 HTTP_Request2_Exception::DECODE_ERROR\r
             );\r
index d54049585946ac90e49d58a63ef8c4d6130ee262..2a782ceda1279481b7b5a9e9aa58c8c8b15b3c39 100644 (file)
@@ -13,7 +13,7 @@
  * @category  HTTP\r
  * @package   HTTP_Request2\r
  * @author    Alexey Borzov <avb@php.net>\r
- * @copyright 2008-2014 Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
  * @link      http://pear.php.net/package/HTTP_Request2\r
  */\r
@@ -28,7 +28,7 @@ require_once 'HTTP/Request2/SocketWrapper.php';
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  * @link     http://pear.php.net/bugs/bug.php?id=19332\r
  * @link     http://tools.ietf.org/html/rfc1928\r
index 43081a19663db1943a7423339888b88b566e8820..2cf4257db2e26a45b7b4afa8f397a23a17fdf721 100644 (file)
@@ -13,7 +13,7 @@
  * @category  HTTP\r
  * @package   HTTP_Request2\r
  * @author    Alexey Borzov <avb@php.net>\r
- * @copyright 2008-2014 Alexey Borzov <avb@php.net>\r
+ * @copyright 2008-2016 Alexey Borzov <avb@php.net>\r
  * @license   http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
  * @link      http://pear.php.net/package/HTTP_Request2\r
  */\r
@@ -31,7 +31,7 @@ require_once 'HTTP/Request2/Exception.php';
  * @package  HTTP_Request2\r
  * @author   Alexey Borzov <avb@php.net>\r
  * @license  http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License\r
- * @version  Release: 2.2.1\r
+ * @version  Release: 2.3.0\r
  * @link     http://pear.php.net/package/HTTP_Request2\r
  * @link     http://pear.php.net/bugs/bug.php?id=19332\r
  * @link     http://tools.ietf.org/html/rfc1928\r
@@ -81,6 +81,32 @@ class HTTP_Request2_SocketWrapper
             // Backwards compatibility with 2.1.0 and 2.1.1 releases\r
             $contextOptions = array('ssl' => $contextOptions);\r
         }\r
+        if (isset($contextOptions['ssl'])) {\r
+            $contextOptions['ssl'] += array(\r
+                // Using "Intermediate compatibility" cipher bundle from\r
+                // https://wiki.mozilla.org/Security/Server_Side_TLS\r
+                'ciphers' => 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:'\r
+                             . 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:'\r
+                             . 'DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:'\r
+                             . 'ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:'\r
+                             . 'ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:'\r
+                             . 'ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:'\r
+                             . 'ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:'\r
+                             . 'DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:'\r
+                             . 'DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:'\r
+                             . 'ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:'\r
+                             . 'AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:'\r
+                             . 'AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:'\r
+                             . '!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'\r
+            );\r
+            if (version_compare(phpversion(), '5.4.13', '>=')) {\r
+                $contextOptions['ssl']['disable_compression'] = true;\r
+                if (version_compare(phpversion(), '5.6', '>=')) {\r
+                    $contextOptions['ssl']['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT\r
+                                                              | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;\r
+                }\r
+            }\r
+        }\r
         $context = stream_context_create();\r
         foreach ($contextOptions as $wrapper => $options) {\r
             foreach ($options as $name => $value) {\r
@@ -239,21 +265,18 @@ class HTTP_Request2_SocketWrapper
      */\r
     public function enableCrypto()\r
     {\r
-        $modes = array(\r
-            STREAM_CRYPTO_METHOD_TLS_CLIENT,\r
-            STREAM_CRYPTO_METHOD_SSLv3_CLIENT,\r
-            STREAM_CRYPTO_METHOD_SSLv23_CLIENT,\r
-            STREAM_CRYPTO_METHOD_SSLv2_CLIENT\r
-        );\r
+        if (version_compare(phpversion(), '5.6', '<')) {\r
+            $cryptoMethod = STREAM_CRYPTO_METHOD_TLS_CLIENT;\r
+        } else {\r
+            $cryptoMethod = STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT\r
+                            | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;\r
+        }\r
 \r
-        foreach ($modes as $mode) {\r
-            if (stream_socket_enable_crypto($this->socket, true, $mode)) {\r
-                return;\r
-            }\r
+        if (!stream_socket_enable_crypto($this->socket, true, $cryptoMethod)) {\r
+            throw new HTTP_Request2_ConnectionException(\r
+                'Failed to enable secure connection when connecting through proxy'\r
+            );\r
         }\r
-        throw new HTTP_Request2_ConnectionException(\r
-            'Failed to enable secure connection when connecting through proxy'\r
-        );\r
     }\r
 \r
     /**\r