]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - extlib/HTTP/Request2/Response.php
update HTTP_Request2 to 2.0.0RC1
[quix0rs-gnu-social.git] / extlib / HTTP / Request2 / Response.php
index c7c1021fbbd11af81f3da84aaf2ecaf1a2619690..73e9a5dc82c64699c63995426f9615539fd49577 100644 (file)
@@ -6,7 +6,7 @@
  *\r
  * LICENSE:\r
  *\r
- * Copyright (c) 2008, 2009, Alexey Borzov <avb@php.net>\r
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
  * All rights reserved.\r
  *\r
  * Redistribution and use in source and binary forms, with or without\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    CVS: $Id: Response.php 287948 2009-09-01 17:12:18Z avb $\r
+ * @version    SVN: $Id: Response.php 309921 2011-04-03 16:43:02Z avb $\r
  * @link       http://pear.php.net/package/HTTP_Request2\r
  */\r
 \r
 /**\r
  * Exception class for HTTP_Request2 package\r
- */ \r
+ */\r
 require_once 'HTTP/Request2/Exception.php';\r
 \r
 /**\r
@@ -58,11 +58,11 @@ require_once 'HTTP/Request2/Exception.php';
  *     $headerLine = read_header_line();\r
  *     $response->parseHeaderLine($headerLine);\r
  * } while ($headerLine != '');\r
- * \r
+ *\r
  * while ($chunk = read_body()) {\r
  *     $response->appendBody($chunk);\r
  * }\r
- * \r
+ *\r
  * var_dump($response->getHeader(), $response->getCookies(), $response->getBody());\r
  * </code>\r
  *\r
@@ -70,7 +70,7 @@ require_once 'HTTP/Request2/Exception.php';
  * @category   HTTP\r
  * @package    HTTP_Request2\r
  * @author     Alexey Borzov <avb@php.net>\r
- * @version    Release: 0.4.1\r
+ * @version    Release: 2.0.0RC1\r
  * @link       http://tools.ietf.org/html/rfc2616#section-6\r
  */\r
 class HTTP_Request2_Response\r
@@ -95,6 +95,12 @@ class HTTP_Request2_Response
     */\r
     protected $reasonPhrase;\r
 \r
+   /**\r
+    * Effective URL (may be different from original request URL in case of redirects)\r
+    * @var  string\r
+    */\r
+    protected $effectiveUrl;\r
+\r
    /**\r
     * Associative array of response headers\r
     * @var  array\r
@@ -164,7 +170,7 @@ class HTTP_Request2_Response
         305 => 'Use Proxy',\r
         307 => 'Temporary Redirect',\r
 \r
-        // 4xx: Client Error - The request contains bad syntax or cannot be \r
+        // 4xx: Client Error - The request contains bad syntax or cannot be\r
         // fulfilled\r
         400 => 'Bad Request',\r
         401 => 'Unauthorized',\r
@@ -200,14 +206,18 @@ class HTTP_Request2_Response
    /**\r
     * Constructor, parses the response status line\r
     *\r
-    * @param    string  Response status line (e.g. "HTTP/1.1 200 OK")\r
-    * @param    bool    Whether body is still encoded by Content-Encoding\r
-    * @throws   HTTP_Request2_Exception if status line is invalid according to spec\r
+    * @param    string Response status line (e.g. "HTTP/1.1 200 OK")\r
+    * @param    bool   Whether body is still encoded by Content-Encoding\r
+    * @param    string Effective URL of the response\r
+    * @throws   HTTP_Request2_MessageException if status line is invalid according to spec\r
     */\r
-    public function __construct($statusLine, $bodyEncoded = true)\r
+    public function __construct($statusLine, $bodyEncoded = true, $effectiveUrl = null)\r
     {\r
         if (!preg_match('!^HTTP/(\d\.\d) (\d{3})(?: (.+))?!', $statusLine, $m)) {\r
-            throw new HTTP_Request2_Exception("Malformed response: {$statusLine}");\r
+            throw new HTTP_Request2_MessageException(\r
+                "Malformed response: {$statusLine}",\r
+                HTTP_Request2_Exception::MALFORMED_RESPONSE\r
+            );\r
         }\r
         $this->version = $m[1];\r
         $this->code    = intval($m[2]);\r
@@ -216,13 +226,14 @@ class HTTP_Request2_Response
         } elseif (!empty(self::$phrases[$this->code])) {\r
             $this->reasonPhrase = self::$phrases[$this->code];\r
         }\r
-        $this->bodyEncoded = (bool)$bodyEncoded;\r
+        $this->bodyEncoded  = (bool)$bodyEncoded;\r
+        $this->effectiveUrl = (string)$effectiveUrl;\r
     }\r
 \r
    /**\r
     * Parses the line from HTTP response filling $headers array\r
     *\r
-    * The method should be called after reading the line from socket or receiving \r
+    * The method should be called after reading the line from socket or receiving\r
     * it into cURL callback. Passing an empty string here indicates the end of\r
     * response headers and triggers additional processing, so be sure to pass an\r
     * empty string in the end.\r
@@ -264,7 +275,7 @@ class HTTP_Request2_Response
             }\r
             $this->lastHeader = $name;\r
 \r
-        // string \r
+        // continuation of a previous header\r
         } elseif (preg_match('!^\s+(.+)$!', $headerLine, $m) && $this->lastHeader) {\r
             if (!is_array($this->headers[$this->lastHeader])) {\r
                 $this->headers[$this->lastHeader] .= ' ' . trim($m[1]);\r
@@ -273,13 +284,13 @@ class HTTP_Request2_Response
                 $this->headers[$this->lastHeader][$key] .= ' ' . trim($m[1]);\r
             }\r
         }\r
-    } \r
+    }\r
 \r
    /**\r
     * Parses a Set-Cookie header to fill $cookies array\r
     *\r
     * @param    string    value of Set-Cookie header\r
-    * @link     http://cgi.netscape.com/newsref/std/cookie_spec.html\r
+    * @link     http://web.archive.org/web/20080331104521/http://cgi.netscape.com/newsref/std/cookie_spec.html\r
     */\r
     protected function parseCookie($cookieString)\r
     {\r
@@ -334,9 +345,22 @@ class HTTP_Request2_Response
         $this->body .= $bodyChunk;\r
     }\r
 \r
+   /**\r
+    * Returns the effective URL of the response\r
+    *\r
+    * This may be different from the request URL if redirects were followed.\r
+    *\r
+    * @return string\r
+    * @link   http://pear.php.net/bugs/bug.php?id=18412\r
+    */\r
+    public function getEffectiveUrl()\r
+    {\r
+        return $this->effectiveUrl;\r
+    }\r
+\r
    /**\r
     * Returns the status code\r
-    * @return   integer \r
+    * @return   integer\r
     */\r
     public function getStatus()\r
     {\r
@@ -352,6 +376,16 @@ class HTTP_Request2_Response
         return $this->reasonPhrase;\r
     }\r
 \r
+   /**\r
+    * Whether response is a redirect that can be automatically handled by HTTP_Request2\r
+    * @return   bool\r
+    */\r
+    public function isRedirect()\r
+    {\r
+        return in_array($this->code, array(300, 301, 302, 303, 307))\r
+               && isset($this->headers['location']);\r
+    }\r
+\r
    /**\r
     * Returns either the named header or all response headers\r
     *\r
@@ -388,7 +422,7 @@ class HTTP_Request2_Response
     */\r
     public function getBody()\r
     {\r
-        if (!$this->bodyEncoded ||\r
+        if (0 == strlen($this->body) || !$this->bodyEncoded ||\r
             !in_array(strtolower($this->getHeader('content-encoding')), array('gzip', 'deflate'))\r
         ) {\r
             return $this->body;\r
@@ -424,7 +458,7 @@ class HTTP_Request2_Response
     * Get the HTTP version of the response\r
     *\r
     * @return   string\r
-    */ \r
+    */\r
     public function getVersion()\r
     {\r
         return $this->version;\r
@@ -439,7 +473,8 @@ class HTTP_Request2_Response
     *\r
     * @param    string  gzip-encoded data\r
     * @return   string  decoded data\r
-    * @throws   HTTP_Request2_Exception\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
@@ -450,15 +485,24 @@ class HTTP_Request2_Response
             return $data;\r
         }\r
         if (!function_exists('gzinflate')) {\r
-            throw new HTTP_Request2_Exception('Unable to decode body: gzip extension not available');\r
+            throw new HTTP_Request2_LogicException(\r
+                'Unable to decode body: gzip extension not available',\r
+                HTTP_Request2_Exception::MISCONFIGURATION\r
+            );\r
         }\r
         $method = ord(substr($data, 2, 1));\r
         if (8 != $method) {\r
-            throw new HTTP_Request2_Exception('Error parsing gzip header: unknown compression method');\r
+            throw new HTTP_Request2_MessageException(\r
+                'Error parsing gzip header: unknown compression method',\r
+                HTTP_Request2_Exception::DECODE_ERROR\r
+            );\r
         }\r
         $flags = ord(substr($data, 3, 1));\r
         if ($flags & 224) {\r
-            throw new HTTP_Request2_Exception('Error parsing gzip header: reserved bits are set');\r
+            throw new HTTP_Request2_MessageException(\r
+                'Error parsing gzip header: reserved bits are set',\r
+                HTTP_Request2_Exception::DECODE_ERROR\r
+            );\r
         }\r
 \r
         // header is 10 bytes minimum. may be longer, though.\r
@@ -466,45 +510,69 @@ class HTTP_Request2_Response
         // extra fields, need to skip 'em\r
         if ($flags & 4) {\r
             if ($length - $headerLength - 2 < 8) {\r
-                throw new HTTP_Request2_Exception('Error parsing gzip header: data too short');\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
-                throw new HTTP_Request2_Exception('Error parsing gzip header: data too short');\r
+                throw new HTTP_Request2_MessageException(\r
+                    'Error parsing gzip header: data too short',\r
+                    HTTP_Request2_Exception::DECODE_ERROR\r
+                );\r
             }\r
             $headerLength += $extraLength[1] + 2;\r
         }\r
         // file name, need to skip that\r
         if ($flags & 8) {\r
             if ($length - $headerLength - 1 < 8) {\r
-                throw new HTTP_Request2_Exception('Error parsing gzip header: data too short');\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
-                throw new HTTP_Request2_Exception('Error parsing gzip header: data too short');\r
+                throw new HTTP_Request2_MessageException(\r
+                    'Error parsing gzip header: data too short',\r
+                    HTTP_Request2_Exception::DECODE_ERROR\r
+                );\r
             }\r
             $headerLength += $filenameLength + 1;\r
         }\r
         // comment, need to skip that also\r
         if ($flags & 16) {\r
             if ($length - $headerLength - 1 < 8) {\r
-                throw new HTTP_Request2_Exception('Error parsing gzip header: data too short');\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
-                throw new HTTP_Request2_Exception('Error parsing gzip header: data too short');\r
+                throw new HTTP_Request2_MessageException(\r
+                    'Error parsing gzip header: data too short',\r
+                    HTTP_Request2_Exception::DECODE_ERROR\r
+                );\r
             }\r
             $headerLength += $commentLength + 1;\r
         }\r
         // have a CRC for header. let's check\r
         if ($flags & 2) {\r
             if ($length - $headerLength - 2 < 8) {\r
-                throw new HTTP_Request2_Exception('Error parsing gzip header: data too short');\r
+                throw new HTTP_Request2_MessageException(\r
+                    'Error parsing gzip header: data too short',\r
+                    HTTP_Request2_Exception::DECODE_ERROR\r
+                );\r
             }\r
             $crcReal   = 0xffff & crc32(substr($data, 0, $headerLength));\r
             $crcStored = unpack('v', substr($data, $headerLength, 2));\r
             if ($crcReal != $crcStored[1]) {\r
-                throw new HTTP_Request2_Exception('Header CRC check failed');\r
+                throw new HTTP_Request2_MessageException(\r
+                    'Header CRC check failed',\r
+                    HTTP_Request2_Exception::DECODE_ERROR\r
+                );\r
             }\r
             $headerLength += 2;\r
         }\r
@@ -517,11 +585,20 @@ class HTTP_Request2_Response
         // don't pass $dataSize to gzinflate, see bugs #13135, #14370\r
         $unpacked = gzinflate(substr($data, $headerLength, -8));\r
         if (false === $unpacked) {\r
-            throw new HTTP_Request2_Exception('gzinflate() call failed');\r
+            throw new HTTP_Request2_MessageException(\r
+                'gzinflate() call failed',\r
+                HTTP_Request2_Exception::DECODE_ERROR\r
+            );\r
         } elseif ($dataSize != strlen($unpacked)) {\r
-            throw new HTTP_Request2_Exception('Data size check failed');\r
+            throw new HTTP_Request2_MessageException(\r
+                'Data size check failed',\r
+                HTTP_Request2_Exception::DECODE_ERROR\r
+            );\r
         } elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) {\r
-            throw new HTTP_Request2_Exception('Data CRC check failed');\r
+            throw new HTTP_Request2_Exception(\r
+                'Data CRC check failed',\r
+                HTTP_Request2_Exception::DECODE_ERROR\r
+            );\r
         }\r
         return $unpacked;\r
     }\r
@@ -531,12 +608,15 @@ class HTTP_Request2_Response
     *\r
     * @param    string  deflate-encoded data\r
     * @return   string  decoded data\r
-    * @throws   HTTP_Request2_Exception\r
+    * @throws   HTTP_Request2_LogicException\r
     */\r
     public static function decodeDeflate($data)\r
     {\r
         if (!function_exists('gzuncompress')) {\r
-            throw new HTTP_Request2_Exception('Unable to decode body: gzip extension not available');\r
+            throw new HTTP_Request2_LogicException(\r
+                'Unable to decode body: gzip extension not available',\r
+                HTTP_Request2_Exception::MISCONFIGURATION\r
+            );\r
         }\r
         // RFC 2616 defines 'deflate' encoding as zlib format from RFC 1950,\r
         // while many applications send raw deflate stream from RFC 1951.\r