Browse Source

Fix ZF-3189: Zend_Http_Client_Adapter_Proxy::connectHandshake ignores useragent set in headers. Patch by Adam Lundrigan

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@24818 44c647ce-9c0f-0410-b52a-842ac1e357ba
rob 13 years ago
parent
commit
f434a9c050
2 changed files with 129 additions and 15 deletions
  1. 35 15
      library/Zend/Http/Client/Adapter/Proxy.php
  2. 94 0
      tests/Zend/Http/Client/ProxyAdapterTest.php

+ 35 - 15
library/Zend/Http/Client/Adapter/Proxy.php

@@ -75,6 +75,13 @@ class Zend_Http_Client_Adapter_Proxy extends Zend_Http_Client_Adapter_Socket
      * @var boolean
      */
     protected $negotiated = false;
+    
+    /**
+     * Stores the last CONNECT handshake request
+     * 
+     * @var string
+     */
+    protected $connectHandshakeRequest;
 
     /**
      * Connect to the remote server
@@ -136,10 +143,20 @@ class Zend_Http_Client_Adapter_Proxy extends Zend_Http_Client_Adapter_Socket
         }
 
         // Add Proxy-Authorization header
-        if ($this->config['proxy_user'] && ! isset($headers['proxy-authorization'])) {
-            $headers['proxy-authorization'] = Zend_Http_Client::encodeAuthHeader(
-                $this->config['proxy_user'], $this->config['proxy_pass'], $this->config['proxy_auth']
-            );
+        if ($this->config['proxy_user']) {
+            // Check to see if one already exists
+            $hasProxyAuthHeader = false;
+            foreach ($headers as $k => $v) {
+                if ($k == 'proxy-authorization' || preg_match("/^proxy-authorization:/i", $v) ) {
+                    $hasProxyAuthHeader = true;
+                    break;
+                }
+            }
+            if (!$hasProxyAuthHeader) {
+                $headers[] = 'Proxy-authorization: ' . Zend_Http_Client::encodeAuthHeader(
+                    $this->config['proxy_user'], $this->config['proxy_pass'], $this->config['proxy_auth']
+                );
+            }
         }
 
         // if we are proxying HTTPS, preform CONNECT handshake with the proxy
@@ -204,19 +221,22 @@ class Zend_Http_Client_Adapter_Proxy extends Zend_Http_Client_Adapter_Socket
         $request = "CONNECT $host:$port HTTP/$http_ver\r\n" .
                    "Host: " . $this->config['proxy_host'] . "\r\n";
 
-        // Add the user-agent header
-        if (isset($this->config['useragent'])) {
-            $request .= "User-agent: " . $this->config['useragent'] . "\r\n";
-        }
-
-        // If the proxy-authorization header is set, send it to proxy but remove
-        // it from headers sent to target host
-        if (isset($headers['proxy-authorization'])) {
-            $request .= "Proxy-authorization: " . $headers['proxy-authorization'] . "\r\n";
-            unset($headers['proxy-authorization']);
+        // Process provided headers, including important ones to CONNECT request
+        foreach ( $headers as $k=>$v ) {
+            switch ( strtolower(substr($v,0,strpos($v,':'))) ) {
+                case 'proxy-authorization':
+                    // break intentionally omitted
+                case 'user-agent':
+                    $request .= $v . "\r\n";
+                    break;
+                default:
+                    break;
+            }
         }
-
         $request .= "\r\n";
+        
+        // @see ZF-3189
+        $this->connectHandshakeRequest = $request;
 
         // Send the request
         if (! @fwrite($this->socket, $request)) {

+ 94 - 0
tests/Zend/Http/Client/ProxyAdapterTest.php

@@ -118,4 +118,98 @@ class Zend_Http_Client_ProxyAdapterTest extends Zend_Http_Client_SocketTest
          * the TRACE response
          */
     }
+    
+    /**
+     * @group ZF-3189
+     */
+    public function testConnectHandshakeSendsCustomUserAgentHeader()
+    {      
+        // Change the adapter
+        $this->config['adapter'] = 'ZF3189_ProxyAdapter';
+        $this->config['useragent'] = 'ZendTest';
+        parent::setUp();
+        
+        $base = preg_replace("/^http:/", "https:", $this->baseuri);
+        $this->client->setUri($base . 'testSimpleRequests.php');
+
+        // Ensure we're proxying a HTTPS request
+        $this->assertEquals('https', $this->client->getUri()->getScheme());
+        
+        // Perform the request
+        $this->client->request();
+
+        $this->assertRegExp(
+            "/\r\nUser-Agent: {$this->config['useragent']}\r\n/i",
+            $this->client->getAdapter()->getLastConnectHandshakeRequest()
+        );
+    }
+    
+    /**
+     * @group ZF-3189
+     */
+    public function testConnectHandshakeSendsCustomUserAgentHeaderWhenSetInHeaders()
+    {      
+        // Change the adapter
+        $this->config['adapter'] = 'ZF3189_ProxyAdapter';
+        parent::setUp();
+        
+        $base = preg_replace("/^http:/", "https:", $this->baseuri);
+        $this->client->setUri($base . 'testSimpleRequests.php');
+        $this->client->setHeaders('User-Agent', 'ZendTest');
+
+        // Ensure we're proxying a HTTPS request
+        $this->assertEquals('https', $this->client->getUri()->getScheme());
+        
+        // Perform the request
+        $this->client->request();
+        print_r($this->client->getAdapter()->getLastConnectHandshakeRequest());
+        $this->assertRegExp(
+            "/\r\nUser-Agent: ZendTest\r\n/i",
+            $this->client->getAdapter()->getLastConnectHandshakeRequest()
+        );
+    }
+    
+    /**
+     * @group ZF-3189
+     */
+    public function testProxyAdapterDoesNotOverwriteExistingProxyAuthorizationHeader()
+    {      
+        // Change the adapter
+        $this->config['adapter'] = 'ZF3189_ProxyAdapter';
+        parent::setUp();
+        
+        $base = preg_replace("/^http:/", "https:", $this->baseuri);
+        $this->client->setUri($base . 'testSimpleRequests.php');
+        $this->client->setHeaders('Proxy-Authorization', 'FooBarBaz');
+
+        // Ensure we're proxying a HTTPS request
+        $this->assertEquals('https', $this->client->getUri()->getScheme());
+        
+        // Perform the request
+        $this->client->request();
+        print_r($this->client->getAdapter()->getLastConnectHandshakeRequest());
+        
+        $resp = $this->client->getAdapter()->getLastConnectHandshakeRequest();
+        $this->assertEquals(1, preg_match_all('/\r\nProxy-Authorization: ([^\r\n]+)\r\n/i', $resp, $matches));
+        $this->assertEquals('FooBarBaz', $matches[1][0]);
+    }
+    
 }
+
+/**
+ * Exposes internal variable connectHandshakeRequest for test purposes
+ * @see ZF-3189
+ */
+class ZF3189_ProxyAdapter extends Zend_Http_Client_Adapter_Proxy
+{
+    
+    /**
+     * Retrieve the request data from last CONNECT handshake
+     * @return string
+     */
+    public function getLastConnectHandshakeRequest()
+    {
+        return $this->connectHandshakeRequest;
+    }
+    
+}