diff --git a/core/trunk/build.yaml b/core/trunk/build.yaml
index 3ec35a41a4b85b8fd467bd095b2892d837257e07..eaeb5a299f0a1f642c373610202fe7787702588e 100644
--- a/core/trunk/build.yaml
+++ b/core/trunk/build.yaml
@@ -11,7 +11,7 @@ src_dir: /
 #src_dir: MaarchX 
 
 
-# test_dir:
+# tests_dir:
 #
 # Indicates the directory where automated tests are relatively to the 
 # root of the project
@@ -19,7 +19,7 @@ src_dir: /
 # Default: tests
 #
 # Examples:
-#test_dir: test
+tests_dir: "core/tests"
 
 # ignore_patterns:
 #
diff --git a/core/trunk/core/class/Url.php b/core/trunk/core/class/Url.php
new file mode 100644
index 0000000000000000000000000000000000000000..2d4ad5db2881225a76a37ce60a3ba3145bb049a9
--- /dev/null
+++ b/core/trunk/core/class/Url.php
@@ -0,0 +1,397 @@
+<?php
+/*
+*   Copyright 2011 Maarch
+*
+*   This file is part of Maarch Framework.
+*
+*   Maarch Framework is free software: you can redistribute it and/or modify
+*   it under the terms of the GNU General Public License as published by
+*   the Free Software Foundation, either version 3 of the License, or
+*   (at your option) any later version.
+*
+*   Maarch Framework is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU General Public License for more details.
+*
+*   You should have received a copy of the GNU General Public License
+*    along with Maarch Framework.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * A simple API to handle and reconstruct URLs in Maarch applications
+ *
+ * This file provides a static class with two goals:
+ * - give access to parts of the url the user used to access the application
+ * - reconstructs some meaningful urls to be used in the application
+ *
+ * Example:
+ * <code>
+ * <?php
+ *
+ * // If the user calls the URL
+ * // http://example.com/entreprise/apps/maarch_entreprise/index.php
+ *
+ * require_once 'core/class/Url.php';
+ *
+ * Url::port(); //-> '80'
+ * Url::host(); //-> 'example.com'
+ * Url::proto(); //-> 'http'
+ * Url::coreurl(); //-> 'http://example.com/entreprise/'
+ *
+ *
+ * // If the user calls the URL
+ * // https://example.com:8043/apps/maarch_entreprise/index.php
+ *
+ *
+ * Url::port(); //-> '8043'
+ * Url::host(); //-> 'example.com'
+ * Url::proto(); //-> 'https'
+ * Url::coreurl(); //-> 'https://example.com:8043/'
+ *
+ * </code>
+ *
+ * <b>the class Url is compatible with reverse proxies</b>
+ *
+ * Given the reverse proxy provides the necessary information about the original
+ * request, {@link Url} is able to detect that the application is running
+ * behind a reverse proxy and looks for special HTTP headers in order to
+ * reconstruct URLs that are accessible by a user (i.e. external URLS).
+ *
+ * {@link Url} looks for the following headers
+ * (they must be set by the reverse proxy) :
+ * - X-Forwarded-Host: The original host of the request (i.e. the host of the
+ *   proxy server)
+ * - X-Forwarded-Proto: The original protocol of the request (i.e. the protocol
+ *   of the proxy server)
+ * - X-Forwarded-Port: The original port of the request (i.e. the port of the
+ *   proxy server)
+ * - X-Forwarded-Script-Name: The original value of the Script Name variable
+ *
+ * Example:
+ * - the public url is:
+ *   https://example.com:8043/apps/maarch_entreprise/index.php
+ * - it redirects to:
+ *   http://internal/subdir/entreprise/apps/maarch_entreprise/index.php
+ *
+ * Following headers must be set in the reverse proxy before it forwards the
+ * request:
+ * - X-Forwarded-Host: example.com
+ * - X-Forwarded-Proto: https
+ * - X-Forwarded-Port: 8043
+ * - X-Forwarded-Script-Name: /apps/maarch_entreprise/index.php
+ *
+ * Then, the {@link Url} class will return the corrects values:
+ * <code>
+ * <?php
+ *
+ * require_once 'core/class/Url.php';
+ *
+ * Url::coreurl(); //-> 'https://example.com:8043/'
+ * </code>
+ *
+ * If the reverse proxy did not set the necessary headers, it would have return:
+ * <code>
+ * <?php
+ *
+ * require_once 'core/class/Url.php';
+ *
+ * Url::coreurl(); //-> 'http://internal/subdir/entreprise/' -- It is an local
+ *                 //only URL, the external user cannot access it.
+ * </code>
+ *
+ * @package Core
+ * @author Bruno Carlin <bruno.carlin@maarch.org>
+ *
+ */
+
+/**
+ * Url allows one to get necessary elements to use full urls.
+ *
+ * It is a static class, which means it does not have to be instantiated to be
+ * used. In fact, its constructor has been disabled and tentative to instantiate
+ * it will throw a Fatal error.
+ *
+ * Example of use:
+ * <code>
+ * <?php
+ *
+ * require 'core/class/Url.php';
+ *
+ * $u = new Url(); // Throws a fatal eror
+ *
+ * Url::host(); // -> 'example.com'
+ * Url::coreuri(); //-> 'http://example.com/entreprise/';
+ *
+ * </code>
+ *
+ * For performance reasons, it has an internal cache, which means that url
+ * components will only be computed once. The cost of calling any method of
+ * this class is the cost of an associative array lookup.
+ * In terms of performance, and after the first call, calling
+ * <code>Url::host()</code> is roughly equivalent to something like
+ * <code>$url['host']</code>.
+ *
+ * @author Bruno Carlin <bruno.carlin@maarch.org>
+ *
+ */
+class Url
+{
+    private static $_cache = array();
+
+    // @codeCoverageIgnoreStart
+    private function __construct() {}
+    // @codeCoverageIgnoreEnd
+
+    /**
+     * Cleans the internal cache of Url
+     *
+     * To use with caution. It allows you to clean the internal cache of this
+     * class.
+     */
+    public static function forget()
+    {
+        self::$_cache = array();
+    }
+
+
+    private static function _buildScriptName()
+    {
+        return array_key_exists('HTTP_X_FORWARDED_SCRIPT_NAME', $_SERVER)
+                ? $_SERVER['HTTP_X_FORWARDED_SCRIPT_NAME']
+                : $_SERVER['SCRIPT_NAME'];
+    }
+
+    private static function _buildRequestUri()
+    {
+        if ($_SERVER["QUERY_STRING"] !== "") {
+            return self::scriptName() . "?" . $_SERVER["QUERY_STRING"];
+        } else {
+            return self::scriptName();
+        }
+    }
+
+    private static function _buildBaseUri()
+    {
+        $baseUri = array_key_exists('HTTP_X_FORWARDED_SCRIPT_NAME', $_SERVER)
+                    ? $_SERVER['HTTP_X_FORWARDED_SCRIPT_NAME']
+                    : $_SERVER['SCRIPT_NAME'];
+        $baseUri = trim(dirname($baseUri), '/');
+        if (($appsPos = strpos($baseUri, 'apps')) !== false) {
+            $baseUri = substr($baseUri, 0, max($appsPos - 1, 0));
+        }
+        return '/'.$baseUri;
+    }
+
+    private static function _buildHost()
+    {
+        return array_key_exists('HTTP_X_FORWARDED_HOST', $_SERVER)
+                ? $_SERVER['HTTP_X_FORWARDED_HOST'] : $_SERVER['HTTP_HOST'];
+    }
+
+    private static function _buildPort()
+    {
+        return array_key_exists('HTTP_X_FORWARDED_PORT', $_SERVER)
+                ? $_SERVER['HTTP_X_FORWARDED_PORT'] : $_SERVER['SERVER_PORT'];
+    }
+
+    private static function _buildProto()
+    {
+        if (array_key_exists('HTTP_X_FORWARDED_PROTO', $_SERVER)) {
+            return $_SERVER['HTTP_X_FORWARDED_PROTO'];
+        }
+        return (array_key_exists('HTTPS', $_SERVER)
+                && $_SERVER['HTTPS'] == 'on')
+                    ? 'https' : 'http';
+    }
+
+
+    private static function _buildCoreUrl()
+    {
+        $tmp = self::proto() . '://';
+        $tmp .= self::host();
+        if (self::proto() === 'http') {
+            $tmp .= (self::port() == '80') ? '' : ':' . self::port();
+        } else {
+            $tmp .= (self::port() == '443') ? '' : ':' . self::port();
+        }
+        $tmp .= self::baseUri();
+        $tmp .= (strrpos(self::baseUri(), '/') == strlen(self::baseUri()) - 1)
+                    ? '' : '/';
+        return $tmp;
+    }
+
+
+    /**
+     * Returns the coreurl of a Maarch application.
+     *
+     * The core url is the base URL for the application ; i.e. the URL to access
+     * the folder where the application is located.
+     *
+     * Example:
+     * <code>
+     * <?php
+     * require 'core/class/Url.php';
+     *
+     * Url::coreurl(); // -> 'http://example.com/entreprise/'
+     * </code>
+     *
+     * @return String The coreurl
+     */
+    public static function coreurl()
+    {
+        if (!array_key_exists('coreurl', self::$_cache)) {
+            self::$_cache['coreurl'] = self::_buildCoreUrl();
+        }
+        return self::$_cache['coreurl'];
+    }
+
+    /**
+     * Returns the SCRIPT_NAME of the current request.
+     *
+     * The SCRIPT_NAME Server vairble is the URI entered by the user to access
+     * a page of theapplication, excluding the query string.
+     *
+     * It is particularly useful to abstract the current url and not test
+     * whether the application is running behind a proxy or not.
+     *
+     * Example:
+     * <code>
+     * <?php
+     * require 'core/class/Url.php';
+     *
+     * Url::requestUri(); // -> '/entreprise/apps/maarch_entreprise/index.php'
+     * </code>
+     *
+     *  @return String The SCRIPT_NAME value
+     */
+    public static function scriptName()
+    {
+        if (!array_key_exists('scriptName', self::$_cache)) {
+            self::$_cache['scriptName'] = self::_buildScriptName();
+        }
+        return self::$_cache['scriptName'];
+    }
+
+    /**
+     * Returns the request uri of the current request.
+     *
+     * The request URI is the path entered by the user to access a page of the
+     * application, including the query string.
+     *
+     * It is particularly useful to abstract the current url and not test
+     * whether the application is running behind a proxy or not.
+     *
+     * Example:
+     * <code>
+     * <?php
+     * require 'core/class/Url.php';
+     *
+     * Url::requestUri(); // -> '/entreprise/apps/maarch_entreprise/index.php?args'
+     * </code>
+     *
+     * @return String The request URI
+     */
+    public static function requestUri()
+    {
+        if (!array_key_exists('requestUri', self::$_cache)) {
+            self::$_cache['requestUri'] = self::_buildRequestUri();
+        }
+        return self::$_cache['requestUri'];
+    }
+
+
+    /**
+     * Returns the protocol to used to access a Maarch Application.
+     *
+     * It can only have two values : "http" or "https".
+     *
+     * Example:
+     * <code>
+     * <?php
+     * require 'core/class/Url.php';
+     *
+     * Url::protocol(); // -> 'http'
+     * </code>
+     * @return String The protocol used ("http" or "https")
+     */
+    public static function proto()
+    {
+        if (!array_key_exists('proto', self::$_cache)) {
+            self::$_cache['proto'] = self::_buildProto();
+        }
+        return self::$_cache['proto'];
+    }
+
+
+    /**
+     * Returns the host used to access a Maarch Application.
+     *
+     * This sends back the "Host" header of the HTTP request called by the user.
+     *
+     * Example:
+     * <code>
+     * <?php
+     * require 'core/class/Url.php';
+     *
+     * Url::host(); // -> 'example.com'
+     * </code>
+     *
+     * @return String The host
+     */
+    public static function host()
+    {
+        if (!array_key_exists('host', self::$_cache)) {
+            self::$_cache['host'] = self::_buildHost();
+        }
+        return self::$_cache['host'];
+    }
+
+
+    /**
+     * Returns the port of the server used to access a Maarch Application.
+     *
+     * Example:
+     * <code>
+     * <?php
+     * require 'core/class/Url.php';
+     *
+     * Url::port(); // -> '80'
+     * </code>
+     *
+     * @return String The port
+     */
+    public static function port()
+    {
+        if (!array_key_exists('port', self::$_cache)) {
+            self::$_cache['port'] = self::_buildPort();
+        }
+        return self::$_cache['port'];
+    }
+
+
+    /**
+     * Returns the base URI of a Maarch Application.
+     *
+     * The base URI is the path of URL for the root folder of a Maarch
+     * Application.
+     *
+     * Example:
+     * <code>
+     * <?php
+     * require 'core/class/Url.php';
+     *
+     * Url::baseUri(); // -> '/subdir/entreprise'
+     * </code>
+     *
+     * @return String The base URI of the application
+     */
+    public static function baseUri()
+    {
+        if (!array_key_exists('baseUri', self::$_cache)) {
+            self::$_cache['baseUri'] = self::_buildBaseUri();
+        }
+        return self::$_cache['baseUri'];
+    }
+
+}
diff --git a/core/trunk/core/class/class_portal.php b/core/trunk/core/class/class_portal.php
index 0f6b2cfb624bfeb9082354068d94032640ecb317..ebc5041b7627b45b21f416f69cac20a3f7cb6406 100644
--- a/core/trunk/core/class/class_portal.php
+++ b/core/trunk/core/class/class_portal.php
@@ -1,4 +1,4 @@
-<?php 
+<?php
 /*
 *    Copyright 2008,2009 Maarch
 *
@@ -43,9 +43,9 @@ class portal extends functions
 	* Loads Maarch portal configuration into sessions  from an xml configuration file (core/xml/config.xml)
 	*/
 	public function build_config() {
-		$xmlconfig = simplexml_load_file(dirname(__FILE__) 
+		$xmlconfig = simplexml_load_file(dirname(__FILE__)
                    . DIRECTORY_SEPARATOR . '..'
-                   . DIRECTORY_SEPARATOR . 'xml' 
+                   . DIRECTORY_SEPARATOR . 'xml'
                    . DIRECTORY_SEPARATOR . 'config.xml');
 		foreach($xmlconfig->CONFIG as $CONFIG) {
 			$_SESSION['config']['corename'] = (string) $CONFIG->corename;
@@ -59,44 +59,7 @@ class portal extends functions
 			} else {
 				$_SESSION['config']['default_timezone'] = 'Europe/Paris';
 			}
-			if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on")
-				$protocol = "https";
-			else
-				$protocol = "http";
-			
-			if($_SERVER['SERVER_PORT'] <> 443 && $protocol == "https") {
-				$server_port = ":".$_SERVER['SERVER_PORT'];
-			} elseif ($_SERVER['SERVER_PORT'] <> 80 && $protocol == "http") {
-				$server_port = ":".$_SERVER['SERVER_PORT'];
-			} else {
-				$server_port = '';
-			}
-			if(isset($_SERVER['HTTP_X_FORWARDED_HOST']) && $_SERVER['HTTP_X_FORWARDED_HOST'] <> "") {
-					$host = $_SERVER['HTTP_X_FORWARDED_HOST'];
-			}
-			else {
-					$host = $_SERVER['HTTP_HOST'];
-			}
-			$tmp = $host;
-			if(!preg_match('/:[0-9]+$/', $host)) {
-				$tmp =$host.$server_port;
-			}
-            
-            if (isset($_SERVER['HTTP_X_BASE_URL']) 
-                && $_SERVER['HTTP_X_BASE_URL'] <> ""
-            ) {
-                $uri = str_replace($_SERVER['HTTP_X_BASE_URL'], '', $_SERVER['SCRIPT_NAME']);
-            } else {
-                $uri = $_SERVER['SCRIPT_NAME'];
-            }
-            
-            if (($appsInUri = strpos($uri, 'apps')) !== false)  {
-                $uri = substr($uri, 0, $appsInUri);
-            }
-            $uri = str_replace('index.php', '', $uri);
-            
-            $_SESSION['config']['coreurl'] = $protocol . "://" . $tmp
-                                           . $uri;
+			$_SESSION['config']['coreurl'] = Url::coreurl();
 		}
 		$i=0;
 		foreach($xmlconfig->BUSINESSAPPS as $BUSINESSAPPS) {
diff --git a/core/trunk/core/init.php b/core/trunk/core/init.php
index 419dfb7f556a7916519d1ed76fa88d3b76713da4..e1625b84e0e0b420fa8b4545c44e6f7021e7488a 100644
--- a/core/trunk/core/init.php
+++ b/core/trunk/core/init.php
@@ -1,4 +1,7 @@
 <?php
+
+require_once dirname(__file__) . 'class/Url.php';
+
 session_name('maarch_entreprise_trunk');
 session_start();
 
@@ -10,7 +13,7 @@ if (!isset($_SESSION['config'])) {
 }
 
 
-if (isset($_SESSION['config']['default_timezone']) 
+if (isset($_SESSION['config']['default_timezone'])
     && ! empty($_SESSION['config']['default_timezone'])
 ) {
     ini_set('date.timezone', $_SESSION['config']['default_timezone']);
@@ -20,15 +23,15 @@ if (isset($_SESSION['config']['default_timezone'])
     date_default_timezone_set('Europe/Paris');
 }
 
-if (isset($_SESSION['config']['corepath']) 
+if (isset($_SESSION['config']['corepath'])
     && ! empty($_SESSION['config']['corepath'])
 ) {
     chdir($_SESSION['config']['corepath']);
 }
 //ini_set('error_reporting', E_ALL);
-if (isset($_SESSION['custom_override_id']) 
-    && ! empty($_SESSION['custom_override_id']) 
-    && isset($_SESSION['config']['corepath']) 
+if (isset($_SESSION['custom_override_id'])
+    && ! empty($_SESSION['custom_override_id'])
+    && isset($_SESSION['config']['corepath'])
     && ! empty($_SESSION['config']['corepath'])
 ) {
     $path = $_SESSION['config']['corepath'] . 'custom' . DIRECTORY_SEPARATOR
@@ -38,7 +41,7 @@ if (isset($_SESSION['custom_override_id'])
         $path . PATH_SEPARATOR . $_SESSION['config']['corepath']
         . PATH_SEPARATOR . get_include_path()
     );
-} else if (isset($_SESSION['config']['corepath']) 
+} else if (isset($_SESSION['config']['corepath'])
 	&& ! empty($_SESSION['config']['corepath'])
 ) {
     set_include_path(
diff --git a/core/trunk/core/tests/class/UrlTest.php b/core/trunk/core/tests/class/UrlTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a42b8b476427db6138a54a704db677bf9dba3289
--- /dev/null
+++ b/core/trunk/core/tests/class/UrlTest.php
@@ -0,0 +1,190 @@
+<?php
+
+require_once dirname(__FILE__) . '/../../class/Url.php';
+
+class UrlTest extends PHPUnit_Framework_TestCase
+{
+
+    public function setUp()
+    {
+        global $_SERVER;
+        $this->_old_values = $_SERVER;
+        $url = 'http://example.com/entreprise/apps/maarch_entreprise/index.php';
+        $this->_patchServerVars($url);
+    }
+
+    public function tearDown()
+    {
+        $_SERVER = $this->_old_values;
+        Url::forget();
+    }
+
+    protected function _patchServerVars($url)    {
+        global $_SERVER;
+        $url_parts = explode("/", $url, 4);
+        $_SERVER['HTTPS'] = (strpos($url_parts[0], 's') !== false)
+                                ? 'on': '';
+        $host_parts = explode(':', $url_parts[2]);
+        $_SERVER['HTTP_HOST'] = $host_parts[0];
+        if (count($host_parts) == 2) {
+            $_SERVER['SERVER_PORT'] = $host_parts[1];
+        } else {
+            $_SERVER['SERVER_PORT'] = ($_SERVER['HTTPS'] === 'on')
+                                        ? '443' : '80';
+        }
+        if ((count($url_parts) > 3)) {
+            $uriParts = explode("?", $url_parts[3], 2);
+            $_SERVER['SCRIPT_NAME'] = '/' . $uriParts[0];
+            $_SERVER['QUERY_STRING'] = (count($uriParts) > 1)
+                                         ? $uriParts[1] : '';
+        } else {
+            $_SERVER['SCRIPT_NAME'] = "";
+            $_SERVER['QUERY_STRING'] = "";
+        }
+    }
+
+
+
+    public function test_cache_cleared_on_forget() {
+        $old = Url::coreurl();
+        Url::forget();
+
+
+        $url = 'http://foo.com'
+             . '/bar';
+        $this->_patchServerVars($url);
+
+        $new = Url::coreurl();
+
+        $this->assertNotEquals($old, $new);
+    }
+
+    public function test_cache_must_persist_between_two_instances()
+    {
+        $old = Url::coreurl();
+        unset($u);
+
+        $this->assertEquals('example.com', Url::host());
+    }
+
+    public function test_http_subdir_url_from_apps_index()
+    {
+        $url = 'http://example.com'
+             . '/entreprise/apps/maarch_entreprise/index.php';
+        $this->_patchServerVars($url);
+
+        $this->assertEquals(
+            'http://example.com/entreprise/',
+            Url::coreurl()
+        );
+    }
+
+    public function test_http_subdir_url_from_root_index()
+    {
+        $url = 'http://example.com'
+             . '/entreprise/index.php';
+        $this->_patchServerVars($url);
+
+        $this->assertEquals(
+            'http://example.com/entreprise/',
+            Url::coreurl()
+        );
+    }
+
+    public function test_https_subdir()
+    {
+        $url = 'https://example.com'
+             . '/entreprise/index.php';
+        $this->_patchServerVars($url);
+
+        $this->assertEquals(
+            'https://example.com/entreprise/',
+            Url::coreurl()
+        );
+        $this->assertEquals('https', Url::proto());
+        $this->assertEquals('443', Url::port());
+    }
+
+    public function test_http_url_at_server_root_root_index()
+    {
+        $url = 'http://example.com'
+             . '/index.php';
+        $this->_patchServerVars($url);
+
+        $this->assertEquals(
+            'http://example.com/',
+            Url::coreurl()
+        );
+        $this->assertEquals('/', Url::baseUri());
+        $this->assertEquals('/index.php', Url::requestUri());
+    }
+
+    public function test_http_url_at_server_root_apps_index()
+    {
+        $url = 'http://example.com'
+             . '/apps/maarch_entreprise/index.php';
+        $this->_patchServerVars($url);
+
+        $this->assertEquals(
+            'http://example.com/',
+            Url::coreurl()
+        );
+        $this->assertEquals('/', Url::baseUri());
+        $this->assertEquals('/apps/maarch_entreprise/index.php',
+                            Url::requestUri());
+    }
+
+    public function test_http_non_standard_port()
+    {
+        $url = 'http://example.com:8080'
+             . '/entreprise/index.php';
+        $this->_patchServerVars($url);
+
+        $this->assertEquals(
+            'http://example.com:8080/entreprise/',
+            Url::coreurl()
+        );
+        $this->assertEquals('http', Url::proto());
+        $this->assertEquals('8080', Url::port());
+    }
+
+    public function test_https_non_standard_port()
+    {
+        $url = 'https://example.com:8043'
+             . '/entreprise/index.php';
+        $this->_patchServerVars($url);
+
+        $this->assertEquals(
+            'https://example.com:8043/entreprise/',
+            Url::coreurl()
+        );
+        $this->assertEquals('https', Url::proto());
+        $this->assertEquals('8043', Url::port());
+    }
+
+    public function test_query_string()
+    {
+        $url = 'https://example.com'
+             . '/entreprise/index.php?foo=bar';
+        $this->_patchServerVars($url);
+
+        $this->assertEquals(
+                'https://example.com/entreprise/',
+                Url::coreurl()
+        );
+        $this->assertEquals('/entreprise/index.php', Url::scriptName());
+        $this->assertEquals('/entreprise/index.php?foo=bar', Url::requestUri());
+    }
+}
+
+#HTTPS
+
+#'SERVER_PORT' => 80
+#'HTTP_HOST' => 'example.com'
+#'SCRIPT_NAME' => 'entreprise/apps/maarch_entreprise/index.php'
+
+#HTTP_X_FORWARDED_HOST
+#HTTP_X_FORWARDED_PORT
+#HTTP_X_FORWARDED_PROTO
+
+#HTTP_BASE_URL / HTTP_X_FORWARDED_PROTO / PATH_INFO
diff --git a/core/trunk/core/tests/class/UrlWithProxyTest.php b/core/trunk/core/tests/class/UrlWithProxyTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ce41d0f54adb34e3eb69eaf6ba0f8f70825bf0b3
--- /dev/null
+++ b/core/trunk/core/tests/class/UrlWithProxyTest.php
@@ -0,0 +1,181 @@
+<?php
+
+
+require_once dirname(__FILE__) . '/../../class/Url.php';
+
+class UrlWithProxyTest extends PHPUnit_Framework_TestCase
+{
+    public function setUp()
+    {
+        global $_SERVER;
+        $this->_old_values = $_SERVER;
+        $url = 'http://example.com/entreprise/apps/maarch_entreprise/index.php';
+        $this->_patchServerVars($url);
+    }
+
+    public function tearDown()
+    {
+        $_SERVER = $this->_old_values;
+        Url::forget();
+    }
+
+    protected function _patchServerVars($url)    {
+        global $_SERVER;
+        $url_parts = explode("/", $url, 4);
+        $_SERVER['HTTPS'] = (strpos($url_parts[0], 's') !== false)
+        ? 'on': '';
+        $host_parts = explode(':', $url_parts[2]);
+        $_SERVER['HTTP_HOST'] = $host_parts[0];
+        if (count($host_parts) == 2) {
+            $_SERVER['SERVER_PORT'] = $host_parts[1];
+        } else {
+            $_SERVER['SERVER_PORT'] = ($_SERVER['HTTPS'] === 'on')
+            ? '443' : '80';
+        }
+        if ((count($url_parts) > 3)) {
+            $uriParts = explode("?", $url_parts[3], 2);
+            $_SERVER['SCRIPT_NAME'] = '/' . $uriParts[0];
+            $_SERVER['QUERY_STRING'] = (count($uriParts) > 1)
+                                         ? $uriParts[1] : '';
+        } else {
+            $_SERVER['SCRIPT_NAME'] = "";
+            $_SERVER['QUERY_STRING'] = "";
+        }
+    }
+
+    protected function _patchServerProxyVars($url)
+    {
+        $url_parts = explode("/", $url, 4);
+        $_SERVER['HTTP_X_FORWARDED_PROTO'] =
+        (strpos($url_parts[0], 's') !== false) ? 'https' : 'http';
+
+        $host_parts = explode(':', $url_parts[2]);
+
+        $_SERVER['HTTP_X_FORWARDED_HOST'] = $host_parts[0];
+
+        if (count($host_parts) == 2) {
+            $_SERVER['HTTP_X_FORWARDED_PORT'] = $host_parts[1];
+        } else {
+            $_SERVER['HTTP_X_FORWARDED_PORT'] =
+            ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') ? '443' : '80';
+        }
+        $_SERVER['HTTP_X_FORWARDED_SCRIPT_NAME'] =
+        	'/' . ((count($url_parts) > 3) ? $url_parts[3] : '');
+
+        if ((count($url_parts) > 3)) {
+            $uriParts = explode("?", $url_parts[3], 2);
+            $_SERVER['HTTP_X_FORWARDED_SCRIPT_NAME'] = '/' . $uriParts[0];
+        } else {
+            $_SERVER['HTTP_X_FORWARDED_SCRIPT_NAME'] = "";
+        }
+    }
+
+
+    public function test_different_hosts_root_url()
+    {
+        $testCase = array('http://example.com/entreprise/index.php',
+                      'http://internal.local/entreprise/index.php',
+                      'http://example.com/entreprise/');
+        call_user_func_array(array($this, "_test_implementation"),
+                             $testCase);
+    }
+
+    public function test_different_hosts_apps_url()
+    {
+        $testCase = array('http://example.com/entreprise/apps/maarch_entreprise/index.php',
+                  'http://internal.local/entreprise/apps/maarch_entreprise/index.php',
+                  'http://example.com/entreprise/');
+        call_user_func_array(array($this, "_test_implementation"),
+                             $testCase);
+    }
+
+    public function test_different_ports_frontend_non_standard()
+    {
+        $testCase = array('http://example.com:8080/entreprise/apps/maarch_entreprise/index.php',
+                  'http://internal.local/entreprise/apps/maarch_entreprise/index.php',
+                  'http://example.com:8080/entreprise/');
+        call_user_func_array(array($this, "_test_implementation"),
+                             $testCase);
+    }
+
+    public function test_test_different_ports_backend_non_standard()
+    {
+        $testCase = array('http://example.com/entreprise/apps/maarch_entreprise/index.php',
+                  'http://internal.local:8080/entreprise/apps/maarch_entreprise/index.php',
+                  'http://example.com/entreprise/');
+        call_user_func_array(array($this, "_test_implementation"),
+                             $testCase);
+    }
+
+    public function test_test_different_ports_both_non_standard()
+    {
+        $testCase = array('http://example.com:8080/entreprise/apps/maarch_entreprise/index.php',
+                      'http://internal.local:8081/entreprise/apps/maarch_entreprise/index.php',
+                      'http://example.com:8080/entreprise/');
+        call_user_func_array(array($this, "_test_implementation"),
+                             $testCase);
+    }
+
+    public function test_different_hosts_and_uris()
+    {
+        $testCase = array('http://entreprise.example.com/apps/maarch_entreprise/index.php',
+                      'http://internal.local/entreprise/apps/maarch_entreprise/index.php',
+                      'http://entreprise.example.com/');
+        call_user_func_array(array($this, "_test_implementation"),
+                             $testCase);
+        $this->assertEquals('/apps/maarch_entreprise/index.php',
+                            Url::requestUri());
+    }
+
+    public function test_different_hosts_and_uris_root_index()
+    {
+        $testCase = array('http://entreprise.example.com/index.php',
+                          'http://internal.local/entreprise/index.php',
+                          'http://entreprise.example.com/');
+        call_user_func_array(array($this, "_test_implementation"),
+                             $testCase);
+        $this->assertEquals('/index.php',
+                            Url::requestUri());
+    }
+
+
+
+    public function test_different_protocols()
+    {
+        $testCase = array('https://example.com/entreprise/apps/maarch_entreprise/index.php',
+                      'http://internal.local/entreprise/apps/maarch_entreprise/index.php',
+                      'https://example.com/entreprise/');
+        call_user_func_array(array($this, "_test_implementation"),
+                             $testCase);
+    }
+
+    public function test_different_protocols_on_non_standard_ports()
+    {
+        $testCase = array('https://example.com:8043/entreprise/apps/maarch_entreprise/index.php',
+                      'http://internal.local:8080/entreprise/apps/maarch_entreprise/index.php',
+                      'https://example.com:8043/entreprise/');
+        call_user_func_array(array($this, "_test_implementation"),
+                             $testCase);
+    }
+
+
+    public function test_with_query_string()
+    {
+        $testCase = array('https://example.com/index.php?foo=bar',
+                              'http://internal.local/index.php?foo=bar',
+                              'https://example.com/');
+        call_user_func_array(array($this, "_test_implementation"),
+        $testCase);
+        $this->assertEquals('/index.php', Url::scriptName());
+        $this->assertEquals('/index.php?foo=bar', Url::requestUri());
+    }
+
+
+
+
+    public function _test_implementation($proxyUrl, $url, $expectedCoreUrl) {
+        $this->_patchServerVars($url);
+        $this->_patchServerProxyVars($proxyUrl);
+        $this->assertEquals($expectedCoreUrl, Url::coreurl());
+    }
+}
\ No newline at end of file