diff --git a/lib/SimpleSAML/Utils/HTTP.php b/lib/SimpleSAML/Utils/HTTP.php
index 25d5596e951c163c906be43c89682fcdd7fcab2a..9f5a50e40aa2d540bad8eb3c61277e629a4619d3 100644
--- a/lib/SimpleSAML/Utils/HTTP.php
+++ b/lib/SimpleSAML/Utils/HTTP.php
@@ -729,11 +729,31 @@ class HTTP
     {
         $cfg = \SimpleSAML_Configuration::getInstance();
         $baseDir = $cfg->getBaseDir();
-        $current_path = realpath($_SERVER['SCRIPT_FILENAME']);
-        $rel_path = str_replace($baseDir.'www'.DIRECTORY_SEPARATOR, '', $current_path);
-
-        if ($current_path == $rel_path) { // compare loosely ($current_path can be false)
-            // we were accessed from an external script, do not try to apply our base URL
+        $cur_path = realpath($_SERVER['SCRIPT_FILENAME']);
+        // find the path to the current script relative to the www/ directory of SimpleSAMLphp
+        $rel_path = str_replace($baseDir.'www'.DIRECTORY_SEPARATOR, '', $cur_path);
+        // convert that relative path to an HTTP query
+        $url_path = str_replace(DIRECTORY_SEPARATOR, '/', $rel_path);
+        // find where the relative path starts in the current request URI
+        $uri_pos = (!empty($url_path)) ? strpos($_SERVER['REQUEST_URI'], $url_path) : false;
+
+        if ($cur_path == $rel_path || $uri_pos === false) {
+            /*
+             * We were accessed from an external script. This can happen in the following cases:
+             *
+             * - $_SERVER['SCRIPT_FILENAME'] points to a script that doesn't exist. E.g. functional testing. In this
+             *   case, realpath() returns false and str_replace an empty string, so we compare them loosely.
+             *
+             * - The URI requested does not belong to a script in the www/ directory of SimpleSAMLphp. In that case,
+             *   removing SimpleSAMLphp's base dir from the current path yields the same path, so $cur_path and
+             *   $rel_path are equal.
+             *
+             * - The request URI does not match the current script. Even if the current script is located in the www/
+             *   directory of SimpleSAMLphp, the URI does not contain its relative path, and $uri_pos is false.
+             *
+             * It doesn't matter which one of those cases we have. We just know we can't apply our base URL to the
+             * current URI, so we need to build it back from the PHP environment.
+             */
             $protocol = 'http';
             $protocol .= (self::getServerHTTPS()) ? 's' : '';
             $protocol .= '://';
@@ -743,10 +763,7 @@ class HTTP
             return $protocol.$hostname.$port.$_SERVER['REQUEST_URI'];
         }
 
-        $url = self::getBaseURL();
-        $rel_path = str_replace(DIRECTORY_SEPARATOR, '/', $rel_path);
-        $pos = strpos($_SERVER['REQUEST_URI'], $rel_path) + strlen($rel_path);
-        return $url.$rel_path.substr($_SERVER['REQUEST_URI'], $pos);
+        return self::getBaseURL().$rel_path.substr($_SERVER['REQUEST_URI'], $uri_pos + strlen($url_path));
     }
 
 
diff --git a/tests/lib/SimpleSAML/Utils/HTTPTest.php b/tests/lib/SimpleSAML/Utils/HTTPTest.php
index b6bfb6b160016b7093289a9e582d1cb9adae031e..4fd540cfb241d38575cf0638b9fa10902f54fb2d 100644
--- a/tests/lib/SimpleSAML/Utils/HTTPTest.php
+++ b/tests/lib/SimpleSAML/Utils/HTTPTest.php
@@ -189,12 +189,24 @@ class HTTPTest extends \PHPUnit_Framework_TestCase
         $this->assertTrue(HTTP::isHTTPS());
         $this->assertEquals('https://'.HTTP::getSelfHostWithNonStandardPort(), HTTP::getSelfURLHost());
 
-        // test a valid, full URL, based on a full URL in the configuration
+        // test a request URI that doesn't match the current script
         $cfg = \SimpleSAML_Configuration::loadFromArray(array(
-            'baseurlpath' => 'https://example.com/simplesaml/',
+            'baseurlpath' => 'https://example.org/simplesaml/',
         ), '[ARRAY]', 'simplesaml');
         $baseDir = $cfg->getBaseDir();
         $_SERVER['SCRIPT_FILENAME'] = $baseDir.'www/module.php';
+        $this->setupEnvFromURL('http://www.example.com/protected/resource.asp?foo=bar');
+        $this->assertEquals('http://www.example.com/protected/resource.asp?foo=bar', HTTP::getSelfURL());
+        $this->assertEquals('http://www.example.com', HTTP::getSelfURLHost());
+        $this->assertEquals('http://www.example.com/protected/resource.asp', HTTP::getSelfURLNoQuery());
+        $this->assertFalse(HTTP::isHTTPS());
+        $this->assertEquals('example.org', HTTP::getSelfHostWithNonStandardPort());
+        $this->assertEquals('http://www.example.com', HTTP::getSelfURLHost());
+
+        // test a valid, full URL, based on a full URL in the configuration
+        \SimpleSAML_Configuration::loadFromArray(array(
+            'baseurlpath' => 'https://example.com/simplesaml/',
+        ), '[ARRAY]', 'simplesaml');
         $this->setupEnvFromURL('http://www.example.org/module.php/module/file.php?foo=bar');
         $this->assertEquals(
             'https://example.com/simplesaml/module.php/module/file.php?foo=bar',