ここの情報は古いです。ご理解頂いた上でお取り扱いください。

Changeset 4926 for OpenPNE/trunk


Ignore:
Timestamp:
Jan 12, 2008, 5:19:46 AM (15 years ago)
Author:
ebihara
Message:

#1754:PEAR::HTTP_Requestのバージョンを1.2から1.4.2に上げた

Location:
OpenPNE/trunk/lib/include/HTTP
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • OpenPNE/trunk/lib/include/HTTP/Request.php

    r2 r4926  
    11<?php
    2 // +-----------------------------------------------------------------------+
    3 // | Copyright (c) 2002-2003, Richard Heyes                                |
    4 // | All rights reserved.                                                  |
    5 // |                                                                       |
    6 // | Redistribution and use in source and binary forms, with or without    |
    7 // | modification, are permitted provided that the following conditions    |
    8 // | are met:                                                              |
    9 // |                                                                       |
    10 // | o Redistributions of source code must retain the above copyright      |
    11 // |   notice, this list of conditions and the following disclaimer.       |
    12 // | o Redistributions in binary form must reproduce the above copyright   |
    13 // |   notice, this list of conditions and the following disclaimer in the |
    14 // |   documentation and/or other materials provided with the distribution.|
    15 // | o The names of the authors may not be used to endorse or promote      |
    16 // |   products derived from this software without specific prior written  |
    17 // |   permission.                                                         |
    18 // |                                                                       |
    19 // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
    20 // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
    21 // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
    22 // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
    23 // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
    24 // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
    25 // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
    26 // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
    27 // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
    28 // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
    29 // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
    30 // |                                                                       |
    31 // +-----------------------------------------------------------------------+
    32 // | Author: Richard Heyes <richard@phpguru.org>                           |
    33 // +-----------------------------------------------------------------------+
    34 //
    35 // $Id: Request.php,v 1.43 2005/11/06 18:29:14 avb Exp $
    36 //
    37 // HTTP_Request Class
    38 //
    39 // Simple example, (Fetches yahoo.com and displays it):
    40 //
    41 // $a = &new HTTP_Request('http://www.yahoo.com/');
    42 // $a->sendRequest();
    43 // echo $a->getResponseBody();
    44 //
    45 
     2/**
     3 * Class for performing HTTP requests
     4 *
     5 * PHP versions 4 and 5
     6 *
     7 * LICENSE:
     8 *
     9 * Copyright (c) 2002-2007, Richard Heyes
     10 * All rights reserved.
     11 *
     12 * Redistribution and use in source and binary forms, with or without
     13 * modification, are permitted provided that the following conditions
     14 * are met:
     15 *
     16 * o Redistributions of source code must retain the above copyright
     17 *   notice, this list of conditions and the following disclaimer.
     18 * o Redistributions in binary form must reproduce the above copyright
     19 *   notice, this list of conditions and the following disclaimer in the
     20 *   documentation and/or other materials provided with the distribution.
     21 * o The names of the authors may not be used to endorse or promote
     22 *   products derived from this software without specific prior written
     23 *   permission.
     24 *
     25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     36 *
     37 * @category    HTTP
     38 * @package     HTTP_Request
     39 * @author      Richard Heyes <richard@phpguru.org>
     40 * @author      Alexey Borzov <avb@php.net>
     41 * @copyright   2002-2007 Richard Heyes
     42 * @license     http://opensource.org/licenses/bsd-license.php New BSD License
     43 * @version     CVS: $Id: Request.php,v 1.58 2007/10/26 13:45:56 avb Exp $
     44 * @link        http://pear.php.net/package/HTTP_Request/
     45 */
     46
     47/**
     48 * PEAR and PEAR_Error classes (for error handling)
     49 */
    4650require_once 'PEAR.php';
     51/**
     52 * Socket class
     53 */
    4754require_once 'Net/Socket.php';
     55/**
     56 * URL handling class
     57 */
    4858require_once 'Net/URL.php';
    4959
     60/**#@+
     61 * Constants for HTTP request methods
     62 */
    5063define('HTTP_REQUEST_METHOD_GET',     'GET',     true);
    5164define('HTTP_REQUEST_METHOD_HEAD',    'HEAD',    true);
     
    5568define('HTTP_REQUEST_METHOD_OPTIONS', 'OPTIONS', true);
    5669define('HTTP_REQUEST_METHOD_TRACE',   'TRACE',   true);
    57 
     70/**#@-*/
     71
     72/**#@+
     73 * Constants for HTTP request error codes
     74 */
     75define('HTTP_REQUEST_ERROR_FILE',             1);
     76define('HTTP_REQUEST_ERROR_URL',              2);
     77define('HTTP_REQUEST_ERROR_PROXY',            4);
     78define('HTTP_REQUEST_ERROR_REDIRECTS',        8);
     79define('HTTP_REQUEST_ERROR_RESPONSE',        16); 
     80define('HTTP_REQUEST_ERROR_GZIP_METHOD',     32);
     81define('HTTP_REQUEST_ERROR_GZIP_READ',       64);
     82define('HTTP_REQUEST_ERROR_GZIP_DATA',      128);
     83define('HTTP_REQUEST_ERROR_GZIP_CRC',       256);
     84/**#@-*/
     85
     86/**#@+
     87 * Constants for HTTP protocol versions
     88 */
    5889define('HTTP_REQUEST_HTTP_VER_1_0', '1.0', true);
    5990define('HTTP_REQUEST_HTTP_VER_1_1', '1.1', true);
    60 
    61 class HTTP_Request {
    62 
     91/**#@-*/
     92
     93if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
     94   /**
     95    * Whether string functions are overloaded by their mbstring equivalents
     96    */
     97    define('HTTP_REQUEST_MBSTRING', true);
     98} else {
     99   /**
     100    * @ignore
     101    */
     102    define('HTTP_REQUEST_MBSTRING', false);
     103}
     104
     105/**
     106 * Class for performing HTTP requests
     107 *
     108 * Simple example (fetches yahoo.com and displays it):
     109 * <code>
     110 * $a = &new HTTP_Request('http://www.yahoo.com/');
     111 * $a->sendRequest();
     112 * echo $a->getResponseBody();
     113 * </code>
     114 *
     115 * @category    HTTP
     116 * @package     HTTP_Request
     117 * @author      Richard Heyes <richard@phpguru.org>
     118 * @author      Alexey Borzov <avb@php.net>
     119 * @version     Release: 1.4.2
     120 */
     121class HTTP_Request
     122{
     123   /**#@+
     124    * @access private
     125    */
    63126    /**
    64127    * Instance of Net_URL
    65     * @var object Net_URL
     128    * @var Net_URL
    66129    */
    67130    var $_url;
     
    99162    /**
    100163    * Socket object
    101     * @var object Net_Socket
     164    * @var Net_Socket
    102165    */
    103166    var $_sock;
     
    159222    /**
    160223    * HTTP_Response object
    161     * @var object HTTP_Response
     224    * @var HTTP_Response
    162225    */
    163226    var $_response;
     
    210273    */
    211274    var $_socketOptions = null;
     275   /**#@-*/
    212276
    213277    /**
     
    238302    function HTTP_Request($url = '', $params = array())
    239303    {
    240         $this->_sock           = &new Net_Socket();
    241304        $this->_method         =  HTTP_REQUEST_METHOD_GET;
    242305        $this->_http           =  HTTP_REQUEST_HTTP_VER_1_1;
     
    271334        $this->addHeader('User-Agent', 'PEAR HTTP_Request class ( http://pear.php.net/ )');
    272335
    273         // Make sure keepalives dont knobble us
     336        // We don't do keep-alives by default
    274337        $this->addHeader('Connection', 'close');
    275338
     
    279342        }
    280343
     344        // Proxy authentication (see bug #5913)
     345        if (!empty($this->_proxy_user)) {
     346            $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($this->_proxy_user . ':' . $this->_proxy_pass));
     347        }
     348
    281349        // Use gzip encoding if possible
    282         // Avoid gzip encoding if using multibyte functions (see #1781)
    283         if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && extension_loaded('zlib') &&
    284             0 == (2 & ini_get('mbstring.func_overload'))) {
    285 
     350        if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && extension_loaded('zlib')) {
    286351            $this->addHeader('Accept-Encoding', 'gzip');
    287352        }
     
    344409            $this->addHeader('Host', $this->_generateHostHeader());
    345410        }
    346     }
    347    
     411
     412        // set '/' instead of empty path rather than check later (see bug #8662)
     413        if (empty($this->_url->path)) {
     414            $this->_url->path = '/';
     415        }
     416    }
     417   
     418   /**
     419    * Returns the current request URL 
     420    *
     421    * @return   string  Current request URL
     422    * @access   public
     423    */
     424    function getUrl()
     425    {
     426        return empty($this->_url)? '': $this->_url->getUrl();
     427    }
     428
    348429    /**
    349430    * Sets a proxy to be used
     
    506587    {
    507588        if (!is_array($fileName) && !is_readable($fileName)) {
    508             return PEAR::raiseError("File '{$fileName}' is not readable");
     589            return PEAR::raiseError("File '{$fileName}' is not readable", HTTP_REQUEST_ERROR_FILE);
    509590        } elseif (is_array($fileName)) {
    510591            foreach ($fileName as $name) {
    511592                if (!is_readable($name)) {
    512                     return PEAR::raiseError("File '{$name}' is not readable");
     593                    return PEAR::raiseError("File '{$name}' is not readable", HTTP_REQUEST_ERROR_FILE);
    513594                }
    514595            }
     
    528609    * @param bool       Whether data is preencoded or not, default = already encoded
    529610    * @access public
    530     * @deprecated       deprecated since 1.3.0, method addBody() should be used instead
     611    * @deprecated       deprecated since 1.3.0, method setBody() should be used instead
    531612    */
    532613    function addRawPostData($postdata, $preencoded = true)
     
    596677    {
    597678        if (!is_a($this->_url, 'Net_URL')) {
    598             return PEAR::raiseError('No URL given.');
     679            return PEAR::raiseError('No URL given', HTTP_REQUEST_ERROR_URL);
    599680        }
    600681
     
    606687        if (strcasecmp($this->_url->protocol, 'https') == 0 AND function_exists('file_get_contents') AND extension_loaded('openssl')) {
    607688            if (isset($this->_proxy_host)) {
    608                 return PEAR::raiseError('HTTPS proxies are not supported.');
     689                return PEAR::raiseError('HTTPS proxies are not supported', HTTP_REQUEST_ERROR_PROXY);
    609690            }
    610691            $host = 'ssl://' . $host;
     
    615696        ini_set('magic_quotes_runtime', false);
    616697
    617         // If this is a second request, we may get away without
    618         // re-connecting if they're on the same server
    619         $err = $this->_sock->connect($host, $port, null, $this->_timeout, $this->_socketOptions);
     698        // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive
     699        // connection token to a proxy server...
     700        if (isset($this->_proxy_host) && !empty($this->_requestHeaders['connection']) &&
     701            'Keep-Alive' == $this->_requestHeaders['connection'])
     702        {
     703            $this->removeHeader('connection');
     704        }
     705
     706        $keepAlive = (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && empty($this->_requestHeaders['connection'])) ||
     707                     (!empty($this->_requestHeaders['connection']) && 'Keep-Alive' == $this->_requestHeaders['connection']);
     708        $sockets   = &PEAR::getStaticProperty('HTTP_Request', 'sockets');
     709        $sockKey   = $host . ':' . $port;
     710        unset($this->_sock);
     711
     712        // There is a connected socket in the "static" property?
     713        if ($keepAlive && !empty($sockets[$sockKey]) &&
     714            !empty($sockets[$sockKey]->fp))
     715        {
     716            $this->_sock =& $sockets[$sockKey];
     717            $err = null;
     718        } else {
     719            $this->_notify('connect');
     720            $this->_sock =& new Net_Socket();
     721            $err = $this->_sock->connect($host, $port, null, $this->_timeout, $this->_socketOptions);
     722        }
    620723        PEAR::isError($err) or $err = $this->_sock->write($this->_buildRequest());
    621724
     
    629732            // Read the response
    630733            $this->_response = &new HTTP_Response($this->_sock, $this->_listeners);
    631             $err = $this->_response->process($this->_saveBody && $saveBody);
     734            $err = $this->_response->process(
     735                $this->_saveBody && $saveBody,
     736                HTTP_REQUEST_METHOD_HEAD != $this->_method
     737            );
     738
     739            if ($keepAlive) {
     740                $keepAlive = (isset($this->_response->_headers['content-length'])
     741                              || (isset($this->_response->_headers['transfer-encoding'])
     742                                  && strtolower($this->_response->_headers['transfer-encoding']) == 'chunked'));
     743                if ($keepAlive) {
     744                    if (isset($this->_response->_headers['connection'])) {
     745                        $keepAlive = strtolower($this->_response->_headers['connection']) == 'keep-alive';
     746                    } else {
     747                        $keepAlive = 'HTTP/'.HTTP_REQUEST_HTTP_VER_1_1 == $this->_response->_protocol;
     748                    }
     749                }
     750            }
    632751        }
    633752
     
    638757        }
    639758
     759        if (!$keepAlive) {
     760            $this->disconnect();
     761        // Store the connected socket in "static" property
     762        } elseif (empty($sockets[$sockKey]) || empty($sockets[$sockKey]->fp)) {
     763            $sockets[$sockKey] =& $this->_sock;
     764        }
    640765
    641766        // Check for redirection
     
    682807        // Too many redirects
    683808        } elseif ($this->_allowRedirects AND $this->_redirects > $this->_maxRedirects) {
    684             return PEAR::raiseError('Too many redirects');
    685         }
    686 
    687         $this->_sock->disconnect();
     809            return PEAR::raiseError('Too many redirects', HTTP_REQUEST_ERROR_REDIRECTS);
     810        }
    688811
    689812        return true;
     813    }
     814
     815    /**
     816     * Disconnect the socket, if connected. Only useful if using Keep-Alive.
     817     *
     818     * @access public
     819     */
     820    function disconnect()
     821    {
     822        if (!empty($this->_sock) && !empty($this->_sock->fp)) {
     823            $this->_notify('disconnect');
     824            $this->_sock->disconnect();
     825        }
    690826    }
    691827
     
    756892        $host = isset($this->_proxy_host) ? $this->_url->protocol . '://' . $this->_url->host : '';
    757893        $port = (isset($this->_proxy_host) AND $this->_url->port != 80) ? ':' . $this->_url->port : '';
    758         $path = (empty($this->_url->path)? '/': $this->_url->path) . $querystring;
     894        $path = $this->_url->path . $querystring;
    759895        $url  = $host . $port . $path;
    760896
     897        if (!strlen($url)) {
     898            $url = '/';
     899        }
     900
    761901        $request = $this->_method . ' ' . $url . ' HTTP/' . $this->_http . "\r\n";
    762902
    763903        if (in_array($this->_method, $this->_bodyDisallowed) ||
    764             (HTTP_REQUEST_METHOD_POST != $this->_method && empty($this->_body)) ||
    765             (HTTP_REQUEST_METHOD_POST != $this->_method && empty($this->_postData) && empty($this->_postFiles))) {
    766 
     904            (0 == strlen($this->_body) && (HTTP_REQUEST_METHOD_POST != $this->_method ||
     905             (empty($this->_postData) && empty($this->_postFiles)))))
     906        {
    767907            $this->removeHeader('Content-Type');
    768908        } else {
     
    786926        // No post data or wrong method, so simply add a final CRLF
    787927        if (in_array($this->_method, $this->_bodyDisallowed) ||
    788             (HTTP_REQUEST_METHOD_POST != $this->_method && empty($this->_body))) {
     928            (HTTP_REQUEST_METHOD_POST != $this->_method && 0 == strlen($this->_body))) {
    789929
    790930            $request .= "\r\n";
     
    834974                $postdata .= '--' . $boundary . "--\r\n";
    835975            }
    836             $request .= 'Content-Length: ' . strlen($postdata) . "\r\n\r\n";
     976            $request .= 'Content-Length: ' .
     977                        (HTTP_REQUEST_MBSTRING? mb_strlen($postdata, 'iso-8859-1'): strlen($postdata)) .
     978                        "\r\n\r\n";
    837979            $request .= $postdata;
    838980
    839981        // Explicitly set request body
    840         } elseif (!empty($this->_body)) {
    841 
    842             $request .= 'Content-Length: ' . strlen($this->_body) . "\r\n\r\n";
     982        } elseif (0 < strlen($this->_body)) {
     983
     984            $request .= 'Content-Length: ' .
     985                        (HTTP_REQUEST_MBSTRING? mb_strlen($this->_body, 'iso-8859-1'): strlen($this->_body)) .
     986                        "\r\n\r\n";
    843987            $request .= $this->_body;
     988
     989        // Terminate headers with CRLF on POST request with no body, too
     990        } else {
     991
     992            $request .= "\r\n";
    844993        }
    845994       
     
    8541003    * @param    mixed   item's values
    8551004    * @return   array   array with the following items: array('item name', 'item value');
     1005    * @access   private
    8561006    */
    8571007    function _flattenArray($name, $values)
     
    8801030    * the object's events
    8811031    *
    882     * @param    object   HTTP_Request_Listener instance to attach
    883     * @return   boolean  whether the listener was successfully attached
     1032    * Events sent by HTTP_Request object
     1033    * - 'connect': on connection to server
     1034    * - 'sentRequest': after the request was sent
     1035    * - 'disconnect': on disconnection from server
     1036    *
     1037    * Events sent by HTTP_Response object
     1038    * - 'gotHeaders': after receiving response headers (headers are passed in $data)
     1039    * - 'tick': on receiving a part of response body (the part is passed in $data)
     1040    * - 'gzTick': on receiving a gzip-encoded part of response body (ditto)
     1041    * - 'gotBody': after receiving the response body (passes the decoded body in $data if it was gzipped)
     1042    *
     1043    * @param    HTTP_Request_Listener   listener to attach
     1044    * @return   boolean                 whether the listener was successfully attached
    8841045    * @access   public
    8851046    */
     
    8971058    * Removes a Listener from the list of listeners
    8981059    *
    899     * @param    object   HTTP_Request_Listener instance to detach
    900     * @return   boolean  whether the listener was successfully detached
     1060    * @param    HTTP_Request_Listener   listener to detach
     1061    * @return   boolean                 whether the listener was successfully detached
    9011062    * @access   public
    9021063    */
     
    9141075   /**
    9151076    * Notifies all registered listeners of an event.
    916     *
    917     * Events sent by HTTP_Request object
    918     * 'sentRequest': after the request was sent
    919     * Events sent by HTTP_Response object
    920     * 'gotHeaders': after receiving response headers (headers are passed in $data)
    921     * 'tick': on receiving a part of response body (the part is passed in $data)
    922     * 'gzTick': on receiving a gzip-encoded part of response body (ditto)
    923     * 'gotBody': after receiving the response body (passes the decoded body in $data if it was gzipped)
    9241077    *
    9251078    * @param    string  Event name
    9261079    * @param    mixed   Additional data
    9271080    * @access   private
     1081    * @see      HTTP_Request::attach()
    9281082    */
    9291083    function _notify($event, $data = null)
     
    9371091
    9381092/**
    939 * Response class to complement the Request class
    940 */
     1093 * Response class to complement the Request class
     1094 *
     1095 * @category    HTTP
     1096 * @package     HTTP_Request
     1097 * @author      Richard Heyes <richard@phpguru.org>
     1098 * @author      Alexey Borzov <avb@php.net>
     1099 * @version     Release: 1.4.2
     1100 */
    9411101class HTTP_Response
    9421102{
    9431103    /**
    9441104    * Socket object
    945     * @var object
     1105    * @var Net_Socket
    9461106    */
    9471107    var $_sock;
     
    9891149    var $_listeners = array();
    9901150
     1151   /**
     1152    * Bytes left to read from message-body
     1153    * @var null|int
     1154    */
     1155    var $_toRead;
     1156
    9911157    /**
    9921158    * Constructor
    9931159    *
    994     * @param  object Net_Socket     socket to read the response from
    995     * @param  array                 listeners attached to request
    996     * @return mixed PEAR Error on error, true otherwise
     1160    * @param  Net_Socket    socket to read the response from
     1161    * @param  array         listeners attached to request
    9971162    */
    9981163    function HTTP_Response(&$sock, &$listeners)
     
    10131178    *                   this to false if downloading a LARGE file and using a Listener.
    10141179    *                   This is assumed to be true if body is gzip-encoded.
     1180    * @param  bool      Whether the response can actually have a message-body.
     1181    *                   Will be set to false for HEAD requests.
    10151182    * @throws PEAR_Error
    10161183    * @return mixed     true on success, PEAR_Error in case of malformed response
    10171184    */
    1018     function process($saveBody = true)
     1185    function process($saveBody = true, $canHaveBody = true)
    10191186    {
    10201187        do {
    10211188            $line = $this->_sock->readLine();
    10221189            if (sscanf($line, 'HTTP/%s %s', $http_version, $returncode) != 2) {
    1023                 return PEAR::raiseError('Malformed response.');
     1190                return PEAR::raiseError('Malformed response', HTTP_REQUEST_ERROR_RESPONSE);
    10241191            } else {
    10251192                $this->_protocol = 'HTTP/' . $http_version;
     
    10321199
    10331200        $this->_notify('gotHeaders', $this->_headers);
     1201
     1202        // RFC 2616, section 4.4:
     1203        // 1. Any response message which "MUST NOT" include a message-body ...
     1204        // is always terminated by the first empty line after the header fields
     1205        // 3. ... If a message is received with both a
     1206        // Transfer-Encoding header field and a Content-Length header field,
     1207        // the latter MUST be ignored.
     1208        $canHaveBody = $canHaveBody && $this->_code >= 200 &&
     1209                       $this->_code != 204 && $this->_code != 304;
    10341210
    10351211        // If response body is present, read it and decode
     
    10371213        $gzipped = isset($this->_headers['content-encoding']) && ('gzip' == $this->_headers['content-encoding']);
    10381214        $hasBody = false;
    1039         if (!isset($this->_headers['content-length']) || 0 != $this->_headers['content-length']) {
    1040             while (!$this->_sock->eof()) {
     1215        if ($canHaveBody && ($chunked || !isset($this->_headers['content-length']) ||
     1216                0 != $this->_headers['content-length']))
     1217        {
     1218            if ($chunked || !isset($this->_headers['content-length'])) {
     1219                $this->_toRead = null;
     1220            } else {
     1221                $this->_toRead = $this->_headers['content-length'];
     1222            }
     1223            while (!$this->_sock->eof() && (is_null($this->_toRead) || 0 < $this->_toRead)) {
    10411224                if ($chunked) {
    10421225                    $data = $this->_readChunked();
     1226                } elseif (is_null($this->_toRead)) {
     1227                    $data = $this->_sock->read(4096);
    10431228                } else {
    1044                     $data = $this->_sock->read(4096);
     1229                    $data = $this->_sock->read(min(4096, $this->_toRead));
     1230                    $this->_toRead -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data);
    10451231                }
    10461232                if ('' == $data) {
     
    10551241            }
    10561242        }
     1243
    10571244        if ($hasBody) {
    10581245            // Uncompress the body if needed
    10591246            if ($gzipped) {
    1060                 $this->_body = gzinflate(substr($this->_body, 10));
     1247                $body = $this->_decodeGzip($this->_body);
     1248                if (PEAR::isError($body)) {
     1249                    return $body;
     1250                }
     1251                $this->_body = $body;
    10611252                $this->_notify('gotBody', $this->_body);
    10621253            } else {
     
    10761267    function _processHeader($header)
    10771268    {
     1269        if (false === strpos($header, ':')) {
     1270            return;
     1271        }
    10781272        list($headername, $headervalue) = explode(':', $header, 2);
    10791273        $headername  = strtolower($headername);
     
    11661360        }
    11671361        $data = $this->_sock->read($this->_chunkLength);
    1168         $this->_chunkLength -= strlen($data);
     1362        $this->_chunkLength -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data);
    11691363        if (0 == $this->_chunkLength) {
    11701364            $this->_sock->readLine(); // Trailing CRLF
     
    11881382        }
    11891383    }
     1384
     1385
     1386   /**
     1387    * Decodes the message-body encoded by gzip
     1388    *
     1389    * The real decoding work is done by gzinflate() built-in function, this
     1390    * method only parses the header and checks data for compliance with
     1391    * RFC 1952 
     1392    *
     1393    * @access   private
     1394    * @param    string  gzip-encoded data
     1395    * @return   string  decoded data
     1396    */
     1397    function _decodeGzip($data)
     1398    {
     1399        if (HTTP_REQUEST_MBSTRING) {
     1400            $oldEncoding = mb_internal_encoding();
     1401            mb_internal_encoding('iso-8859-1');
     1402        }
     1403        $length = strlen($data);
     1404        // If it doesn't look like gzip-encoded data, don't bother
     1405        if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) {
     1406            return $data;
     1407        }
     1408        $method = ord(substr($data, 2, 1));
     1409        if (8 != $method) {
     1410            return PEAR::raiseError('_decodeGzip(): unknown compression method', HTTP_REQUEST_ERROR_GZIP_METHOD);
     1411        }
     1412        $flags = ord(substr($data, 3, 1));
     1413        if ($flags & 224) {
     1414            return PEAR::raiseError('_decodeGzip(): reserved bits are set', HTTP_REQUEST_ERROR_GZIP_DATA);
     1415        }
     1416
     1417        // header is 10 bytes minimum. may be longer, though.
     1418        $headerLength = 10;
     1419        // extra fields, need to skip 'em
     1420        if ($flags & 4) {
     1421            if ($length - $headerLength - 2 < 8) {
     1422                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
     1423            }
     1424            $extraLength = unpack('v', substr($data, 10, 2));
     1425            if ($length - $headerLength - 2 - $extraLength[1] < 8) {
     1426                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
     1427            }
     1428            $headerLength += $extraLength[1] + 2;
     1429        }
     1430        // file name, need to skip that
     1431        if ($flags & 8) {
     1432            if ($length - $headerLength - 1 < 8) {
     1433                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
     1434            }
     1435            $filenameLength = strpos(substr($data, $headerLength), chr(0));
     1436            if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) {
     1437                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
     1438            }
     1439            $headerLength += $filenameLength + 1;
     1440        }
     1441        // comment, need to skip that also
     1442        if ($flags & 16) {
     1443            if ($length - $headerLength - 1 < 8) {
     1444                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
     1445            }
     1446            $commentLength = strpos(substr($data, $headerLength), chr(0));
     1447            if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) {
     1448                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
     1449            }
     1450            $headerLength += $commentLength + 1;
     1451        }
     1452        // have a CRC for header. let's check
     1453        if ($flags & 1) {
     1454            if ($length - $headerLength - 2 < 8) {
     1455                return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
     1456            }
     1457            $crcReal   = 0xffff & crc32(substr($data, 0, $headerLength));
     1458            $crcStored = unpack('v', substr($data, $headerLength, 2));
     1459            if ($crcReal != $crcStored[1]) {
     1460                return PEAR::raiseError('_decodeGzip(): header CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC);
     1461            }
     1462            $headerLength += 2;
     1463        }
     1464        // unpacked data CRC and size at the end of encoded data
     1465        $tmp = unpack('V2', substr($data, -8));
     1466        $dataCrc  = $tmp[1];
     1467        $dataSize = $tmp[2];
     1468
     1469        // finally, call the gzinflate() function
     1470        $unpacked = @gzinflate(substr($data, $headerLength, -8), $dataSize);
     1471        if (false === $unpacked) {
     1472            return PEAR::raiseError('_decodeGzip(): gzinflate() call failed', HTTP_REQUEST_ERROR_GZIP_READ);
     1473        } elseif ($dataSize != strlen($unpacked)) {
     1474            return PEAR::raiseError('_decodeGzip(): data size check failed', HTTP_REQUEST_ERROR_GZIP_READ);
     1475        } elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) {
     1476            return PEAR::raiseError('_decodeGzip(): data CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC);
     1477        }
     1478        if (HTTP_REQUEST_MBSTRING) {
     1479            mb_internal_encoding($oldEncoding);
     1480        }
     1481        return $unpacked;
     1482    }
    11901483} // End class HTTP_Response
    11911484?>
  • OpenPNE/trunk/lib/include/HTTP/Request/Listener.php

    r2 r4926  
    11<?php
    2 // +-----------------------------------------------------------------------+
    3 // | Copyright (c) 2002-2003, Richard Heyes                                |
    4 // | All rights reserved.                                                  |
    5 // |                                                                       |
    6 // | Redistribution and use in source and binary forms, with or without    |
    7 // | modification, are permitted provided that the following conditions    |
    8 // | are met:                                                              |
    9 // |                                                                       |
    10 // | o Redistributions of source code must retain the above copyright      |
    11 // |   notice, this list of conditions and the following disclaimer.       |
    12 // | o Redistributions in binary form must reproduce the above copyright   |
    13 // |   notice, this list of conditions and the following disclaimer in the |
    14 // |   documentation and/or other materials provided with the distribution.|
    15 // | o The names of the authors may not be used to endorse or promote      |
    16 // |   products derived from this software without specific prior written  |
    17 // |   permission.                                                         |
    18 // |                                                                       |
    19 // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
    20 // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
    21 // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
    22 // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
    23 // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
    24 // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
    25 // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
    26 // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
    27 // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
    28 // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
    29 // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
    30 // |                                                                       |
    31 // +-----------------------------------------------------------------------+
    32 // | Author: Alexey Borzov <avb@php.net>                                  |
    33 // +-----------------------------------------------------------------------+
    34 //
    35 // $Id: Listener.php,v 1.2 2003/10/26 10:28:29 avb Exp $
    36 //
     2/**
     3 * Listener for HTTP_Request and HTTP_Response objects
     4 *
     5 * PHP versions 4 and 5
     6 *
     7 * LICENSE:
     8 *
     9 * Copyright (c) 2002-2007, Richard Heyes
     10 * All rights reserved.
     11 *
     12 * Redistribution and use in source and binary forms, with or without
     13 * modification, are permitted provided that the following conditions
     14 * are met:
     15 *
     16 * o Redistributions of source code must retain the above copyright
     17 *   notice, this list of conditions and the following disclaimer.
     18 * o Redistributions in binary form must reproduce the above copyright
     19 *   notice, this list of conditions and the following disclaimer in the
     20 *   documentation and/or other materials provided with the distribution.
     21 * o The names of the authors may not be used to endorse or promote
     22 *   products derived from this software without specific prior written
     23 *   permission.
     24 *
     25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     36 *
     37 * @category    HTTP
     38 * @package     HTTP_Request
     39 * @author      Alexey Borzov <avb@php.net>
     40 * @copyright   2002-2007 Richard Heyes
     41 * @license     http://opensource.org/licenses/bsd-license.php New BSD License
     42 * @version     CVS: $Id: Listener.php,v 1.3 2007/05/18 10:33:31 avb Exp $
     43 * @link        http://pear.php.net/package/HTTP_Request/
     44 */
    3745
    3846/**
     47 * Listener for HTTP_Request and HTTP_Response objects
     48 *
    3949 * This class implements the Observer part of a Subject-Observer
    40  * design pattern. It listens to the events sent by a
    41  * HTTP_Request or HTTP_Response instance.
     50 * design pattern.
    4251 *
    43  * @package HTTP_Request
    44  * @author  Alexey Borzov <avb@php.net>
    45  * @version $Revision: 1.2 $
     52 * @category    HTTP
     53 * @package     HTTP_Request
     54 * @author      Alexey Borzov <avb@php.net>
     55 * @version     Release: 1.4.2
    4656 */
    4757class HTTP_Request_Listener
Note: See TracChangeset for help on using the changeset viewer.