Ensure that all base URL's are absolut-ify-ed, no matter where we get them from.
Also refactor the compute script base code to be easier to read

Review at http://gwt-code-reviews.appspot.com/1066801

Review by: amitmanjhi@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9180 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/computeScriptBase.js b/dev/core/src/com/google/gwt/core/ext/linker/impl/computeScriptBase.js
index dd27fa0..3d4b61a 100644
--- a/dev/core/src/com/google/gwt/core/ext/linker/impl/computeScriptBase.js
+++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/computeScriptBase.js
@@ -29,53 +29,8 @@
  */
 
 function computeScriptBase() {
-  // First, check if the meta properties give the baseUrl
-  var metaVal = __gwt_getMetaProperty('baseUrl');
-  // Note: the base variable should not be defined in this function because in
-  // the older templates (like IFrameTemplate.js), base is defined outside this
-  // function, and they rely on the fact that calling computeScriptBase will set
-  // that base variable rather than using the return value. Instead, we define
-  // a tempBase variable, and then right before we return, we also set the
-  // base variable for backwards compatability
-  var tempBase = '';
 
-  if (metaVal != null) {
-    tempBase = metaVal;
-    base = tempBase;
-    return tempBase;
-  }
-
-  // The baseUrl will be similar to the URL for this script's URL
-  var thisScript;
-
-  // By default, this script looks like something/moduleName.nocache.js
-  // so look for a script tag that looks like that
-  var scriptTags = $doc.getElementsByTagName('script');
-  for (var i = 0; i < scriptTags.length; ++i) {
-    if (scriptTags[i].src.indexOf('__MODULE_NAME__.nocache.js') != -1) {
-      thisScript = scriptTags[i];
-    }
-  }
-
-  // If the user renamed their script tag, we'll use a fancier method to find
-  // it. Note that this will not work in the Late Loading case due to the
-  // document.write call.
-  if (!thisScript) {
-    if (typeof isBodyLoaded == 'undefined' || !isBodyLoaded()) {
-      // Put in a marker script element which should be the first script tag after
-      // the tag we're looking for. To find it, we start at the marker and walk
-      // backwards until we find a script.
-      var markerId = "__gwt_marker___MODULE_NAME__";
-      var markerScript;
-      $doc.write('<script id="' + markerId + '"></script>');
-      markerScript = $doc.getElementById(markerId);
-      thisScript = markerScript && markerScript.previousSibling;
-      while (thisScript && thisScript.tagName != 'SCRIPT') {
-        thisScript = thisScript.previousSibling;
-      }
-    }
-  }
-
+  // ================ Helper methods to process tags ======================  
   // Gets the part of a url up to and including the 'path' portion.
   function getDirectoryOfFile(path) {
     // Truncate starting at the first '?' or '#', whichever comes first. 
@@ -89,41 +44,102 @@
     }
     var slashIndex = path.lastIndexOf('/', Math.min(queryIndex, hashIndex));
     return (slashIndex >= 0) ? path.substring(0, slashIndex + 1) : '';
-  };
-
-  if (thisScript && thisScript.src) {
-    // Compute our base url
-    tempBase = getDirectoryOfFile(thisScript.src);
   }
 
-  // Make the base URL absolute
-  if (tempBase == '') {
-    // If there's a base tag, use it.
+  function ensureAbsoluteUrl(url) {
+    if ((url.match(/^\w+:\/\//))) {
+      // If the URL is obviously absolute, do nothing.
+    } else {
+      // Probably a relative URL; use magic to make the browser absolutify it.
+      // I wish there were a better way to do this, but this seems the only
+      // sure way!  (A side benefit is it preloads clear.cache.gif)
+      // Note: this trick is harmless if the URL was really already absolute.
+      var img = $doc.createElement("img");
+      img.src = url + 'clear.cache.gif';
+      url = getDirectoryOfFile(img.src);
+    }
+    return url;
+  }
+  
+// =============== Various methods to try finding the base =================  
+  function tryMetaTag() {
+    var metaVal = __gwt_getMetaProperty('baseUrl');
+    if (metaVal != null) {
+      return metaVal;
+    }
+    return '';
+  }
+    
+  function tryNocacheJsTag() {
+    // By default, this script looks like something/moduleName.nocache.js
+    // so look for a script tag that looks like that
+    var scriptTags = $doc.getElementsByTagName('script');
+    for (var i = 0; i < scriptTags.length; ++i) {
+      if (scriptTags[i].src.indexOf('__MODULE_NAME__.nocache.js') != -1) {
+        return getDirectoryOfFile(scriptTags[i].src);
+      }
+    }
+    return '';
+  }
+
+  function tryMarkerScript() {
+    // If the user renamed their script tag, we'll use a fancier method to find
+    // it. Note that this will not work in the Late Loading case due to the
+    // document.write call.
+    var thisScript;
+    if (typeof isBodyLoaded == 'undefined' || !isBodyLoaded()) {
+      // Put in a marker script element which should be the first script tag after
+      // the tag we're looking for. To find it, we start at the marker and walk
+      // backwards until we find a script.
+      var markerId = "__gwt_marker___MODULE_NAME__";
+      var markerScript;
+      $doc.write('<script id="' + markerId + '"></script>');
+      markerScript = $doc.getElementById(markerId);
+      thisScript = markerScript && markerScript.previousSibling;
+      while (thisScript && thisScript.tagName != 'SCRIPT') {
+        thisScript = thisScript.previousSibling;
+      }
+      if (markerScript) {
+        markerScript.parentNode.removeChild(markerScript);
+      }
+      if (thisScript && thisScript.src) {
+        return getDirectoryOfFile(thisScript.src);
+      }
+    }
+    return '';
+  }
+
+  function tryBaseTag() {
     var baseElements = $doc.getElementsByTagName('base');
     if (baseElements.length > 0) {
       // It's always the last parsed base tag that will apply to this script.
-      tempBase = baseElements[baseElements.length - 1].href;
-    } else {
-      // No base tag; the base must be the same as the document location.
-      tempBase = getDirectoryOfFile($doc.location.href);
+      return baseElements[baseElements.length - 1].href;
     }
-  } else if ((tempBase.match(/^\w+:\/\//))) {
-    // If the URL is obviously absolute, do nothing.
-  } else {
-    // Probably a relative URL; use magic to make the browser absolutify it.
-    // I wish there were a better way to do this, but this seems the only
-    // sure way!  (A side benefit is it preloads clear.cache.gif)
-    // Note: this trick is harmless if the URL was really already absolute.
-    var img = $doc.createElement("img");
-    img.src = tempBase + 'clear.cache.gif';
-    tempBase = getDirectoryOfFile(img.src);
+    return '';
   }
-
-  if (markerScript) {
-    // remove the marker element
-    markerScript.parentNode.removeChild(markerScript);
+  
+// ================ Inline Code =============================================
+  var tempBase = tryMetaTag();
+  if (tempBase == '') {
+    tempBase = tryNocacheJsTag();
   }
-
+  if (tempBase == '') {
+    tempBase = tryMarkerScript();
+  }
+  if (tempBase == '') {
+    tempBase = tryBaseTag();
+  }
+  if (tempBase == '') {
+    // last resort
+    tempBase = getDirectoryOfFile($doc.location.href);
+  }  
+  
+  tempBase = ensureAbsoluteUrl(tempBase);
+  
+  // Note: the base variable should not be defined in this function because in
+  // the older templates (like IFrameTemplate.js), base is defined outside this
+  // function, and they rely on the fact that calling computeScriptBase will set
+  // that base variable rather than using the return value.
   base = tempBase;
   return tempBase;
 }
diff --git a/dev/core/test/com/google/gwt/core/ext/linker/impl/SelectionScriptJavaScriptTest.java b/dev/core/test/com/google/gwt/core/ext/linker/impl/SelectionScriptJavaScriptTest.java
index f3baebc..e6a392a 100644
--- a/dev/core/test/com/google/gwt/core/ext/linker/impl/SelectionScriptJavaScriptTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/linker/impl/SelectionScriptJavaScriptTest.java
@@ -52,7 +52,7 @@
                  + "return (value == null) ? null : value; }");
     code.append(Utility.getFileFromClassPath(SelectionScriptLinker.COMPUTE_SCRIPT_BASE_JS));
     code.append("computeScriptBase();\n");
-    return code.toString().replaceAll("__MODULE_NAME__", TEST_MODULE_NAME);
+    return code.toString();
   }
 
   /**
@@ -133,11 +133,28 @@
   }
 
   /**
+   * Test the default href
+   */
+  public void testDefault() throws IOException {
+    StringBuffer testCode = new StringBuffer();
+    testCode.append("var metaProps = { };\n");
+    testCode.append("function isBodyLoaded() { return true; }\n");
+    testCode.append(loadComputeScriptBase());
+    testCode.append("alert('base='+base);\n");
+
+    List<String> alerts = loadPage(makeHostPage(""), testCode);
+
+    assertEquals(1, alerts.size());
+    assertEquals("base=http://foo.test/", alerts.get(0));
+  }
+  
+  /**
    * Test the fully magic script base with no meta properties.
    */
   public void testScriptBase() throws IOException {
     StringBuffer testCode = new StringBuffer();
     testCode.append("var metaProps = { };\n");
+    testCode.append("function isBodyLoaded() { return false; }\n");
     testCode.append(loadComputeScriptBase());
     testCode.append("alert('base='+base);\n");
 
@@ -146,7 +163,37 @@
     assertEquals(1, alerts.size());
     assertEquals("base=http://foo.test/foo/", alerts.get(0));
   }
+  
+  /**
+   * Test getting the base URL from a meta property with an absolute URL
+   */
+  public void testScriptBaseFromMetas() throws IOException {
+    StringBuffer testCode = new StringBuffer();
+    testCode.append("var metaProps = { baseUrl : \"http://static.test/fromMetaTag/\" };\n");
+    testCode.append(loadComputeScriptBase());
+    testCode.append("alert('base='+base);\n");
 
+    List<String> alerts = loadPage(makeHostPage(""), testCode);
+
+    assertEquals(1, alerts.size());
+    assertEquals("base=http://static.test/fromMetaTag/", alerts.get(0));
+  }
+
+  /**
+   * Test getting the base URL from a meta property with a relative URL
+   */
+  public void testRelativeScriptBaseFromMetas() throws IOException {
+    StringBuffer testCode = new StringBuffer();
+    testCode.append("var metaProps = { baseUrl : \"fromMeta/tag/\" };\n");
+    testCode.append(loadComputeScriptBase());
+    testCode.append("alert('base='+base);\n");
+
+    List<String> alerts = loadPage(makeHostPage(""), testCode);
+
+    assertEquals(1, alerts.size());
+    assertEquals("base=http://foo.test/fromMeta/tag/", alerts.get(0));
+  }
+  
   /**
    * Test the script base logic for an inlined selection script.
    */
@@ -171,7 +218,7 @@
   public void testScriptBaseFromBaseTag() throws IOException {
     StringBuffer hostPage = new StringBuffer();
     hostPage.append("<html><head>\n");
-    hostPage.append("<base href=\"http://static.test/foo/\">\n");
+    hostPage.append("<base href=\"http://static.test/fromBaseTag/\">\n");
     hostPage.append("<script lang=\"javascript\"><!--\n");
     hostPage.append("var metaProps = { }\n");
     hostPage.append(loadComputeScriptBase());
@@ -181,22 +228,27 @@
     List<String> alerts = loadPage(hostPage.toString(), "");
 
     assertEquals(1, alerts.size());
-    assertEquals("base=http://static.test/foo/", alerts.get(0));
+    assertEquals("base=http://static.test/fromBaseTag/", alerts.get(0));
   }
-
+  
   /**
-   * Test getting the base URL from a meta property
+   * Test the script base logic for an inlined selection script.
    */
-  public void testScriptBaseFromMetas() throws IOException {
-    StringBuffer testCode = new StringBuffer();
-    testCode.append("var metaProps = { baseUrl : \"http://static.test/foo/\" };\n");
-    testCode.append(loadComputeScriptBase());
-    testCode.append("alert('base='+base);\n");
+  public void testNocacheJsTag() throws IOException {
+    StringBuffer hostPage = new StringBuffer();
+    hostPage.append("<html><head>\n");
+    hostPage.append("<script lang='javascript' type='application/javascript' ");
+    hostPage.append("src='from/nocache/__MODULE_NAME__.nocache.js'></script>\n");
+    hostPage.append("<script lang=\"javascript\"><!--\n");
+    hostPage.append("var metaProps = { }\n");
+    hostPage.append(loadComputeScriptBase());
+    hostPage.append("alert('base='+base);\n");
+    hostPage.append("--></script>\n");
 
-    List<String> alerts = loadPage(makeHostPage(""), testCode);
+    List<String> alerts = loadPage(hostPage.toString(), "");
 
     assertEquals(1, alerts.size());
-    assertEquals("base=http://static.test/foo/", alerts.get(0));
+    assertEquals("base=http://foo.test/from/nocache/", alerts.get(0));
   }
 
   /**