Author: Kris.Wallsmith
Date: 2010-09-13 19:31:37 +0200 (Mon, 13 Sep 2010)
New Revision: 30900

Modified:
   branches/1.3/lib/request/sfWebRequest.class.php
   branches/1.3/test/unit/request/sfWebRequestTest.php
   branches/1.4/lib/request/sfWebRequest.class.php
   branches/1.4/test/unit/request/sfWebRequestTest.php
Log:
[1.3, 1.4] fixed getUriPrefix() when requested is forwarded from a secure one 
(closes #4723)


Modified: branches/1.3/lib/request/sfWebRequest.class.php
===================================================================
--- branches/1.3/lib/request/sfWebRequest.class.php     2010-09-13 17:15:38 UTC 
(rev 30899)
+++ branches/1.3/lib/request/sfWebRequest.class.php     2010-09-13 17:31:37 UTC 
(rev 30900)
@@ -22,6 +22,10 @@
  */
 class sfWebRequest extends sfRequest
 {
+  const
+    PORT_HTTP  = 80,
+    PORT_HTTPS = 443;
+  
   protected
     $languages              = null,
     $charsets               = null,
@@ -44,6 +48,8 @@
    *  * path_info_key:     The path info key (default to PATH_INFO)
    *  * path_info_array:   The path info array (default to SERVER)
    *  * relative_url_root: The relative URL root
+   *  * http_port:         The port to use for HTTP requests
+   *  * https_port:        The port to use for HTTPS requests
    *
    * @param  sfEventDispatcher $dispatcher  An sfEventDispatcher instance
    * @param  array             $parameters  An associative array of 
initialization parameters
@@ -61,6 +67,8 @@
     $options = array_merge(array(
       'path_info_key'   => 'PATH_INFO',
       'path_info_array' => 'SERVER',
+      'http_port'       => null,
+      'https_port'      => null,
       'default_format'  => null, // to maintain bc
     ), $options);
     parent::initialize($dispatcher, $parameters, $attributes, $options);
@@ -206,29 +214,38 @@
   public function getUriPrefix()
   {
     $pathArray = $this->getPathInfoArray();
-    if ($this->isSecure())
+    $secure = $this->isSecure();
+
+    $protocol = $secure ? 'https' : 'http';
+    $host = $this->getHost();
+    $port = null;
+
+    // extract port from host or environment variable
+    if (false !== strpos($host, ':'))
     {
-      $standardPort = '443';
-      $protocol = 'https';
+      list($host, $port) = explode(':', $host, 2);
     }
-    else
+    else if (isset($this->options[$protocol.'_port']))
     {
-      $standardPort = '80';
-      $protocol = 'http';
+      $port = $this->options[$protocol.'_port'];
     }
-
-    $host = explode(':', $this->getHost());
-    if (count($host) == 1)
+    else if (isset($pathArray['SERVER_PORT']))
     {
-      $host[] = isset($pathArray['SERVER_PORT']) ? $pathArray['SERVER_PORT'] : 
'';
+      $port = $pathArray['SERVER_PORT'];
     }
 
-    if ($host[1] == $standardPort || empty($host[1]))
+    // cleanup the port based on whether the current request is forwarded from
+    // a secure one and whether the introspected port matches the standard one
+    if ($this->isForwardedSecure())
     {
-      unset($host[1]);
+      $port = isset($this->options['https_port']) && self::PORT_HTTPS != 
$this->options['https_port'] ? $this->options['https_port'] : null;
     }
+    elseif (($secure && self::PORT_HTTPS == $port) || (!$secure && 
self::PORT_HTTP == $port))
+    {
+      $port = null;
+    }
 
-    return $protocol.'://'.implode(':', $host);
+    return sprintf('%s://%s%s', $protocol, $host, $port ? ':'.$port : '');
   }
 
   /**
@@ -553,7 +570,7 @@
   }
 
   /**
-   * Returns true if the current request is secure (HTTPS protocol).
+   * Returns true if the current or forwarded request is secure (HTTPS 
protocol).
    *
    * @return boolean
    */
@@ -561,16 +578,28 @@
   {
     $pathArray = $this->getPathInfoArray();
 
-    return (
-      (isset($pathArray['HTTPS']) && (strtolower($pathArray['HTTPS']) == 'on' 
|| $pathArray['HTTPS'] == 1))
+    return
+      (isset($pathArray['HTTPS']) && ('on' == strtolower($pathArray['HTTPS']) 
|| 1 == $pathArray['HTTPS']))
       ||
-      (isset($pathArray['HTTP_SSL_HTTPS']) && 
(strtolower($pathArray['HTTP_SSL_HTTPS']) == 'on' || 
$pathArray['HTTP_SSL_HTTPS'] == 1))
+      (isset($pathArray['HTTP_SSL_HTTPS']) && ('on' == 
strtolower($pathArray['HTTP_SSL_HTTPS']) || 1 == $pathArray['HTTP_SSL_HTTPS']))
       ||
-      (isset($pathArray['HTTP_X_FORWARDED_PROTO']) && 
strtolower($pathArray['HTTP_X_FORWARDED_PROTO']) == 'https')
-    );
+      $this->isForwardedSecure()
+    ;
   }
 
   /**
+   * Returns true if the current request is forwarded from a request that is 
secure.
+   *
+   * @return boolean
+   */
+  protected function isForwardedSecure()
+  {
+    $pathArray = $this->getPathInfoArray();
+
+    return isset($pathArray['HTTP_X_FORWARDED_PROTO']) && 'https' == 
strtolower($pathArray['HTTP_X_FORWARDED_PROTO']);
+  }
+
+  /**
    * Retrieves relative root url.
    *
    * @return string URL

Modified: branches/1.3/test/unit/request/sfWebRequestTest.php
===================================================================
--- branches/1.3/test/unit/request/sfWebRequestTest.php 2010-09-13 17:15:38 UTC 
(rev 30899)
+++ branches/1.3/test/unit/request/sfWebRequestTest.php 2010-09-13 17:31:37 UTC 
(rev 30900)
@@ -10,7 +10,7 @@
 
 require_once(dirname(__FILE__).'/../../bootstrap/unit.php');
 
-$t = new lime_test(65);
+$t = new lime_test(71);
 
 class myRequest extends sfWebRequest
 {
@@ -32,6 +32,11 @@
     $this->resetPathInfoArray();
   }
 
+  public function setOption($key, $value)
+  {
+    $this->options[$key] = $value;
+  }
+
   public function resetPathInfoArray()
   {
     foreach (array_diff(array_keys($this->getPathInfoArray()), 
self::$initialPathArrayKeys) as $key)
@@ -161,6 +166,7 @@
 // ->getUriPrefix()
 $t->diag('->getUriPrefix()');
 
+$request->resetPathInfoArray();
 $_SERVER['SERVER_PORT'] = '80';
 $_SERVER['HTTP_HOST'] = 'symfony-project.org:80';
 $t->is($request->getUriPrefix(), 'http://symfony-project.org', 
'->getUriPrefix() returns no port for standard http port');
@@ -169,6 +175,7 @@
 $_SERVER['HTTP_HOST'] = 'symfony-project.org:8088';
 $t->is($request->getUriPrefix(), 'http://symfony-project.org:8088', 
'->getUriPrefix() works for nonstandard http ports');
 
+$request->resetPathInfoArray();
 $_SERVER['HTTPS'] = 'on';
 $_SERVER['SERVER_PORT'] = '443';
 $_SERVER['HTTP_HOST'] = 'symfony-project.org:443';
@@ -178,6 +185,45 @@
 $_SERVER['HTTP_HOST'] = 'symfony-project.org:8043';
 $t->is($request->getUriPrefix(), 'https://symfony-project.org:8043', 
'->getUriPrefix() works for nonstandard https ports');
 
+$request->resetPathInfoArray();
+$_SERVER['HTTP_HOST'] = 'symfony-project.org';
+$_SERVER['SERVER_PORT'] = '8080';
+$t->is($request->getUriPrefix(), 'http://symfony-project.org:8080', 
'->getUriPrefix() uses the "SERVER_PORT" environment variable');
+
+$request->resetPathInfoArray();
+$_SERVER['HTTPS'] = 'on';
+$_SERVER['HTTP_HOST'] = 'symfony-project.org';
+$_SERVER['SERVER_PORT'] = '8043';
+$t->is($request->getUriPrefix(), 'https://symfony-project.org:8043', 
'->getUriPrefix() uses the "SERVER_PORT" environment variable');
+
+$request->resetPathInfoArray();
+$request->setOption('http_port', '8080');
+$_SERVER['HTTP_HOST'] = 'symfony-project.org';
+$t->is($request->getUriPrefix(), 'http://symfony-project.org:8080', 
'->getUriPrefix() uses the configured port');
+$request->setOption('http_port', null);
+
+$request->resetPathInfoArray();
+$request->setOption('https_port', '8043');
+$_SERVER['HTTPS'] = 'on';
+$_SERVER['HTTP_HOST'] = 'symfony-project.org';
+$t->is($request->getUriPrefix(), 'https://symfony-project.org:8043', 
'->getUriPrefix() uses the configured port');
+$request->setOption('https_port', null);
+
+$request->resetPathInfoArray();
+$_SERVER['HTTP_HOST'] = 'symfony-project.org';
+$_SERVER['SERVER_PORT'] = '80';
+$_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https';
+$t->is($request->getUriPrefix(), 'https://symfony-project.org', 
'->getUriPrefix() works on secure requests forwarded as non-secure requests');
+
+$request->resetPathInfoArray();
+$request->setOption('https_port', '8043');
+$_SERVER['HTTP_HOST'] = 'symfony-project.org';
+$_SERVER['SERVER_PORT'] = '80';
+$_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https';
+$t->is($request->getUriPrefix(), 'https://symfony-project.org:8043', 
'->getUriPrefix() uses the configured port on secure requests forwarded as 
non-secure requests');
+
+$request->resetPathInfoArray();
+
 // ->getRemoteAddress()
 $t->diag('->getRemoteAddress()');
 

Modified: branches/1.4/lib/request/sfWebRequest.class.php
===================================================================
--- branches/1.4/lib/request/sfWebRequest.class.php     2010-09-13 17:15:38 UTC 
(rev 30899)
+++ branches/1.4/lib/request/sfWebRequest.class.php     2010-09-13 17:31:37 UTC 
(rev 30900)
@@ -22,6 +22,10 @@
  */
 class sfWebRequest extends sfRequest
 {
+  const
+    PORT_HTTP  = 80,
+    PORT_HTTPS = 443;
+  
   protected
     $languages              = null,
     $charsets               = null,
@@ -44,6 +48,8 @@
    *  * path_info_key:     The path info key (default to PATH_INFO)
    *  * path_info_array:   The path info array (default to SERVER)
    *  * relative_url_root: The relative URL root
+   *  * http_port:         The port to use for HTTP requests
+   *  * https_port:        The port to use for HTTPS requests
    *
    * @param  sfEventDispatcher $dispatcher  An sfEventDispatcher instance
    * @param  array             $parameters  An associative array of 
initialization parameters
@@ -61,6 +67,8 @@
     $options = array_merge(array(
       'path_info_key'   => 'PATH_INFO',
       'path_info_array' => 'SERVER',
+      'http_port'       => null,
+      'https_port'      => null,
       'default_format'  => null, // to maintain bc
     ), $options);
     parent::initialize($dispatcher, $parameters, $attributes, $options);
@@ -206,29 +214,38 @@
   public function getUriPrefix()
   {
     $pathArray = $this->getPathInfoArray();
-    if ($this->isSecure())
+    $secure = $this->isSecure();
+
+    $protocol = $secure ? 'https' : 'http';
+    $host = $this->getHost();
+    $port = null;
+
+    // extract port from host or environment variable
+    if (false !== strpos($host, ':'))
     {
-      $standardPort = '443';
-      $protocol = 'https';
+      list($host, $port) = explode(':', $host, 2);
     }
-    else
+    else if (isset($this->options[$protocol.'_port']))
     {
-      $standardPort = '80';
-      $protocol = 'http';
+      $port = $this->options[$protocol.'_port'];
     }
-
-    $host = explode(':', $this->getHost());
-    if (count($host) == 1)
+    else if (isset($pathArray['SERVER_PORT']))
     {
-      $host[] = isset($pathArray['SERVER_PORT']) ? $pathArray['SERVER_PORT'] : 
'';
+      $port = $pathArray['SERVER_PORT'];
     }
 
-    if ($host[1] == $standardPort || empty($host[1]))
+    // cleanup the port based on whether the current request is forwarded from
+    // a secure one and whether the introspected port matches the standard one
+    if ($this->isForwardedSecure())
     {
-      unset($host[1]);
+      $port = isset($this->options['https_port']) && self::PORT_HTTPS != 
$this->options['https_port'] ? $this->options['https_port'] : null;
     }
+    elseif (($secure && self::PORT_HTTPS == $port) || (!$secure && 
self::PORT_HTTP == $port))
+    {
+      $port = null;
+    }
 
-    return $protocol.'://'.implode(':', $host);
+    return sprintf('%s://%s%s', $protocol, $host, $port ? ':'.$port : '');
   }
 
   /**
@@ -538,7 +555,7 @@
   }
 
   /**
-   * Returns true if the current request is secure (HTTPS protocol).
+   * Returns true if the current or forwarded request is secure (HTTPS 
protocol).
    *
    * @return boolean
    */
@@ -546,16 +563,28 @@
   {
     $pathArray = $this->getPathInfoArray();
 
-    return (
-      (isset($pathArray['HTTPS']) && (strtolower($pathArray['HTTPS']) == 'on' 
|| $pathArray['HTTPS'] == 1))
+    return
+      (isset($pathArray['HTTPS']) && ('on' == strtolower($pathArray['HTTPS']) 
|| 1 == $pathArray['HTTPS']))
       ||
-      (isset($pathArray['HTTP_SSL_HTTPS']) && 
(strtolower($pathArray['HTTP_SSL_HTTPS']) == 'on' || 
$pathArray['HTTP_SSL_HTTPS'] == 1))
+      (isset($pathArray['HTTP_SSL_HTTPS']) && ('on' == 
strtolower($pathArray['HTTP_SSL_HTTPS']) || 1 == $pathArray['HTTP_SSL_HTTPS']))
       ||
-      (isset($pathArray['HTTP_X_FORWARDED_PROTO']) && 
strtolower($pathArray['HTTP_X_FORWARDED_PROTO']) == 'https')
-    );
+      $this->isForwardedSecure()
+    ;
   }
 
   /**
+   * Returns true if the current request is forwarded from a request that is 
secure.
+   *
+   * @return boolean
+   */
+  protected function isForwardedSecure()
+  {
+    $pathArray = $this->getPathInfoArray();
+
+    return isset($pathArray['HTTP_X_FORWARDED_PROTO']) && 'https' == 
strtolower($pathArray['HTTP_X_FORWARDED_PROTO']);
+  }
+
+  /**
    * Retrieves relative root url.
    *
    * @return string URL

Modified: branches/1.4/test/unit/request/sfWebRequestTest.php
===================================================================
--- branches/1.4/test/unit/request/sfWebRequestTest.php 2010-09-13 17:15:38 UTC 
(rev 30899)
+++ branches/1.4/test/unit/request/sfWebRequestTest.php 2010-09-13 17:31:37 UTC 
(rev 30900)
@@ -10,7 +10,7 @@
 
 require_once(dirname(__FILE__).'/../../bootstrap/unit.php');
 
-$t = new lime_test(65);
+$t = new lime_test(71);
 
 class myRequest extends sfWebRequest
 {
@@ -32,6 +32,11 @@
     $this->resetPathInfoArray();
   }
 
+  public function setOption($key, $value)
+  {
+    $this->options[$key] = $value;
+  }
+
   public function resetPathInfoArray()
   {
     foreach (array_diff(array_keys($this->getPathInfoArray()), 
self::$initialPathArrayKeys) as $key)
@@ -161,6 +166,7 @@
 // ->getUriPrefix()
 $t->diag('->getUriPrefix()');
 
+$request->resetPathInfoArray();
 $_SERVER['SERVER_PORT'] = '80';
 $_SERVER['HTTP_HOST'] = 'symfony-project.org:80';
 $t->is($request->getUriPrefix(), 'http://symfony-project.org', 
'->getUriPrefix() returns no port for standard http port');
@@ -169,6 +175,7 @@
 $_SERVER['HTTP_HOST'] = 'symfony-project.org:8088';
 $t->is($request->getUriPrefix(), 'http://symfony-project.org:8088', 
'->getUriPrefix() works for nonstandard http ports');
 
+$request->resetPathInfoArray();
 $_SERVER['HTTPS'] = 'on';
 $_SERVER['SERVER_PORT'] = '443';
 $_SERVER['HTTP_HOST'] = 'symfony-project.org:443';
@@ -178,6 +185,45 @@
 $_SERVER['HTTP_HOST'] = 'symfony-project.org:8043';
 $t->is($request->getUriPrefix(), 'https://symfony-project.org:8043', 
'->getUriPrefix() works for nonstandard https ports');
 
+$request->resetPathInfoArray();
+$_SERVER['HTTP_HOST'] = 'symfony-project.org';
+$_SERVER['SERVER_PORT'] = '8080';
+$t->is($request->getUriPrefix(), 'http://symfony-project.org:8080', 
'->getUriPrefix() uses the "SERVER_PORT" environment variable');
+
+$request->resetPathInfoArray();
+$_SERVER['HTTPS'] = 'on';
+$_SERVER['HTTP_HOST'] = 'symfony-project.org';
+$_SERVER['SERVER_PORT'] = '8043';
+$t->is($request->getUriPrefix(), 'https://symfony-project.org:8043', 
'->getUriPrefix() uses the "SERVER_PORT" environment variable');
+
+$request->resetPathInfoArray();
+$request->setOption('http_port', '8080');
+$_SERVER['HTTP_HOST'] = 'symfony-project.org';
+$t->is($request->getUriPrefix(), 'http://symfony-project.org:8080', 
'->getUriPrefix() uses the configured port');
+$request->setOption('http_port', null);
+
+$request->resetPathInfoArray();
+$request->setOption('https_port', '8043');
+$_SERVER['HTTPS'] = 'on';
+$_SERVER['HTTP_HOST'] = 'symfony-project.org';
+$t->is($request->getUriPrefix(), 'https://symfony-project.org:8043', 
'->getUriPrefix() uses the configured port');
+$request->setOption('https_port', null);
+
+$request->resetPathInfoArray();
+$_SERVER['HTTP_HOST'] = 'symfony-project.org';
+$_SERVER['SERVER_PORT'] = '80';
+$_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https';
+$t->is($request->getUriPrefix(), 'https://symfony-project.org', 
'->getUriPrefix() works on secure requests forwarded as non-secure requests');
+
+$request->resetPathInfoArray();
+$request->setOption('https_port', '8043');
+$_SERVER['HTTP_HOST'] = 'symfony-project.org';
+$_SERVER['SERVER_PORT'] = '80';
+$_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https';
+$t->is($request->getUriPrefix(), 'https://symfony-project.org:8043', 
'->getUriPrefix() uses the configured port on secure requests forwarded as 
non-secure requests');
+
+$request->resetPathInfoArray();
+
 // ->getRemoteAddress()
 $t->diag('->getRemoteAddress()');
 

-- 
You received this message because you are subscribed to the Google Groups 
"symfony SVN" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/symfony-svn?hl=en.

Reply via email to