Microsoft_Http
[ class tree: Microsoft_Http ] [ index: Microsoft_Http ] [ all elements ]

Source for file Proxy.php

Documentation is available at Proxy.php

  1. <?php
  2.  
  3. /**
  4.  * Zend Framework
  5.  *
  6.  * LICENSE
  7.  *
  8.  * This source file is subject to the new BSD license that is bundled
  9.  * with this package in the file LICENSE.txt.
  10.  * It is also available through the world-wide-web at this URL:
  11.  * http://framework.zend.com/license/new-bsd
  12.  * If you did not receive a copy of the license and are unable to
  13.  * obtain it through the world-wide-web, please send an email
  14.  * to license@zend.com so we can send you a copy immediately.
  15.  *
  16.  * @category   Microsoft
  17.  * @package    Microsoft_Http
  18.  * @subpackage Client_Adapter
  19.  * @version    $Id: Proxy.php 17059 2009-07-25 11:24:49Z shahar $
  20.  * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  21.  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  22.  */
  23.  
  24. /**
  25.  * @see Microsoft_AutoLoader
  26.  */
  27. require_once dirname(__FILE__'/../../../AutoLoader.php';
  28.  
  29. /**
  30.  * HTTP Proxy-supporting Microsoft_Http_Client adapter class, based on the default
  31.  * socket based adapter.
  32.  *
  33.  * Should be used if proxy HTTP access is required. If no proxy is set, will
  34.  * fall back to Microsoft_Http_Client_Adapter_Socket behavior. Just like the
  35.  * default Socket adapter, this adapter does not require any special extensions
  36.  * installed.
  37.  *
  38.  * @category   Microsoft
  39.  * @package    Microsoft_Http
  40.  * @subpackage Client_Adapter
  41.  * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
  42.  * @license    http://framework.zend.com/license/new-bsd     New BSD License
  43.  */
  44. {
  45.     /**
  46.      * Parameters array
  47.      *
  48.      * @var array 
  49.      */
  50.     protected $config = array(
  51.         'ssltransport'  => 'ssl',
  52.         'sslcert'       => null,
  53.         'sslpassphrase' => null,
  54.         'proxy_host'    => '',
  55.         'proxy_port'    => 8080,
  56.         'proxy_user'    => '',
  57.         'proxy_pass'    => '',
  58.         'proxy_auth'    => Microsoft_Http_Client::AUTH_BASIC,
  59.         'persistent'    => false
  60.     );
  61.  
  62.     /**
  63.      * Whether HTTPS CONNECT was already negotiated with the proxy or not
  64.      *
  65.      * @var boolean 
  66.      */
  67.     protected $negotiated = false;
  68.  
  69.     /**
  70.      * Connect to the remote server
  71.      *
  72.      * Will try to connect to the proxy server. If no proxy was set, will
  73.      * fall back to the target server (behave like regular Socket adapter)
  74.      *
  75.      * @param string  $host 
  76.      * @param int     $port 
  77.      * @param boolean $secure 
  78.      */
  79.     public function connect($host$port 80$secure false)
  80.     {
  81.         // If no proxy is set, fall back to Socket adapter
  82.         if ($this->config['proxy_host']{
  83.             return parent::connect($host$port$secure);
  84.         }
  85.  
  86.         // Connect (a non-secure connection) to the proxy server
  87.         return parent::connect(
  88.             $this->config['proxy_host'],
  89.             $this->config['proxy_port'],
  90.             false
  91.         );
  92.     }
  93.  
  94.     /**
  95.      * Send request to the proxy server
  96.      *
  97.      * @param string        $method 
  98.      * @param Microsoft_Uri_Http $uri 
  99.      * @param string        $http_ver 
  100.      * @param array         $headers 
  101.      * @param string        $body 
  102.      * @return string Request as string
  103.      */
  104.     public function write($method$uri$http_ver '1.1'$headers array()$body '')
  105.     {
  106.         // If no proxy is set, fall back to default Socket adapter
  107.         if ($this->config['proxy_host']return parent::write($method$uri$http_ver$headers$body);
  108.  
  109.         // Make sure we're properly connected
  110.         if ($this->socket{
  111.             require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  112.             throw new Microsoft_Http_Client_Adapter_Exception("Trying to write but we are not connected");
  113.         }
  114.  
  115.         $host $this->config['proxy_host'];
  116.         $port $this->config['proxy_port'];
  117.  
  118.         if ($this->connected_to[0!= "tcp://$host|| $this->connected_to[1!= $port{
  119.             require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  120.             throw new Microsoft_Http_Client_Adapter_Exception("Trying to write but we are connected to the wrong proxy server");
  121.         }
  122.  
  123.         // Add Proxy-Authorization header
  124.         if ($this->config['proxy_user'&& isset($headers['proxy-authorization'])) {
  125.             $headers['proxy-authorization'Microsoft_Http_Client::encodeAuthHeader(
  126.                 $this->config['proxy_user']$this->config['proxy_pass']$this->config['proxy_auth']
  127.             );
  128.         }
  129.  
  130.         // if we are proxying HTTPS, preform CONNECT handshake with the proxy
  131.         if ($uri->getScheme(== 'https' && ($this->negotiated)) {
  132.             $this->connectHandshake($uri->getHost()$uri->getPort()$http_ver$headers);
  133.             $this->negotiated = true;
  134.         }
  135.  
  136.         // Save request method for later
  137.         $this->method = $method;
  138.  
  139.         // Build request headers
  140.         if ($this->negotiated{
  141.             $path $uri->getPath();
  142.             if ($uri->getQuery()) {
  143.                 $path .= '?' $uri->getQuery();
  144.             }
  145.             $request "$method $path HTTP/$http_ver\r\n";
  146.         else {
  147.             $request "$method $uri HTTP/$http_ver\r\n";
  148.         }
  149.  
  150.         // Add all headers to the request string
  151.         foreach ($headers as $k => $v{
  152.             if (is_string($k)) $v "$k$v";
  153.             $request .= "$v\r\n";
  154.         }
  155.  
  156.         // Add the request body
  157.         $request .= "\r\n" $body;
  158.  
  159.         // Send the request
  160.         if (@fwrite($this->socket$request)) {
  161.             require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  162.             throw new Microsoft_Http_Client_Adapter_Exception("Error writing request to proxy server");
  163.         }
  164.  
  165.         return $request;
  166.     }
  167.  
  168.     /**
  169.      * Preform handshaking with HTTPS proxy using CONNECT method
  170.      *
  171.      * @param string  $host 
  172.      * @param integer $port 
  173.      * @param string  $http_ver 
  174.      * @param array   $headers 
  175.      */
  176.     protected function connectHandshake($host$port 443$http_ver '1.1'array &$headers array())
  177.     {
  178.         $request "CONNECT $host:$port HTTP/$http_ver\r\n.
  179.                    "Host: " $this->config['proxy_host'"\r\n";
  180.  
  181.         // Add the user-agent header
  182.         if (isset($this->config['useragent'])) {
  183.             $request .= "User-agent: " $this->config['useragent'"\r\n";
  184.         }
  185.  
  186.         // If the proxy-authorization header is set, send it to proxy but remove
  187.         // it from headers sent to target host
  188.         if (isset($headers['proxy-authorization'])) {
  189.             $request .= "Proxy-authorization: " $headers['proxy-authorization'"\r\n";
  190.             unset($headers['proxy-authorization']);
  191.         }
  192.  
  193.         $request .= "\r\n";
  194.  
  195.         // Send the request
  196.         if (@fwrite($this->socket$request)) {
  197.             require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  198.             throw new Microsoft_Http_Client_Adapter_Exception("Error writing request to proxy server");
  199.         }
  200.  
  201.         // Read response headers only
  202.         $response '';
  203.         $gotStatus false;
  204.         while ($line @fgets($this->socket)) {
  205.             $gotStatus $gotStatus || (strpos($line'HTTP'!== false);
  206.             if ($gotStatus{
  207.                 $response .= $line;
  208.                 if (!chop($line)) break;
  209.             }
  210.         }
  211.  
  212.         // Check that the response from the proxy is 200
  213.         if (Microsoft_Http_Response::extractCode($response!= 200{
  214.             require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  215.             throw new Microsoft_Http_Client_Adapter_Exception("Unable to connect to HTTPS proxy. Server response: " $response);
  216.         }
  217.  
  218.         // If all is good, switch socket to secure mode. We have to fall back
  219.         // through the different modes
  220.         $modes array(
  221.             STREAM_CRYPTO_METHOD_TLS_CLIENT,
  222.             STREAM_CRYPTO_METHOD_SSLv3_CLIENT,
  223.             STREAM_CRYPTO_METHOD_SSLv23_CLIENT,
  224.             STREAM_CRYPTO_METHOD_SSLv2_CLIENT
  225.         );
  226.  
  227.         $success false;
  228.         foreach($modes as $mode{
  229.             $success stream_socket_enable_crypto($this->sockettrue$mode);
  230.             if ($successbreak;
  231.         }
  232.  
  233.         if ($success{
  234.                 require_once 'Microsoft/Http/Client/Adapter/Exception.php';
  235.                 throw new Microsoft_Http_Client_Adapter_Exception("Unable to connect to" .
  236.                     " HTTPS server through proxy: could not negotiate secure connection.");
  237.         }
  238.     }
  239.  
  240.     /**
  241.      * Close the connection to the server
  242.      *
  243.      */
  244.     public function close()
  245.     {
  246.         parent::close();
  247.         $this->negotiated = false;
  248.     }
  249.  
  250.     /**
  251.      * Destructor: make sure the socket is disconnected
  252.      *
  253.      */
  254.     public function __destruct()
  255.     {
  256.         if ($this->socket$this->close();
  257.     }
  258. }

Documentation generated on Wed, 18 May 2011 12:06:44 +0200 by phpDocumentor 1.4.3