Fixes super-dev-mode for Chrome 24+ and above due to a change in the interaction between //@ sourceURL directives and HTTP headers. Previously, //@ sourceURL would only affect the display of the script name in the Inspector, but now it actually changes where the Inspector looks for associated network headers.


This patch uses the //@ sourceMapURL directive instead. I left in the X-SourceMap header support as well since it may affect older versions of Chrome and Firefox if and when it gains full SourceMap support.

Change-Id: I54ada111b1fe795c9d98b9adf75b59f7367f480a
Review-Link: https://gwt-review.googlesource.com/#/c/1300/


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@11408 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
index 101d0f0..9069ac3 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/CodeServer.java
@@ -83,7 +83,7 @@
       AppSpace appSpace = AppSpace.create(new File(workDir, moduleName));
 
       Recompiler recompiler = new Recompiler(appSpace, moduleName,
-        options.getSourcePath(), logger);
+        options.getSourcePath(), logger, options.getPreferredHost() + ":" + options.getPort());
       modules.addModuleState(new ModuleState(recompiler, logger, options.getNoPrecompile()));
     }
 
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
index e5db41e..f6c8b4a 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
@@ -51,6 +51,7 @@
   private final String originalModuleName;
   private final List<File> sourcePath;
   private final TreeLogger logger;
+  private String serverPrefix;
   private int compilesDone = 0;
 
   // after renaming
@@ -61,11 +62,12 @@
       new AtomicReference<ResourceLoader>();
 
   Recompiler(AppSpace appSpace, String moduleName, List<File> sourcePath,
-      TreeLogger logger) {
+             String serverPrefix, TreeLogger logger) {
     this.appSpace = appSpace;
     this.originalModuleName = moduleName;
     this.sourcePath = sourcePath;
     this.logger = logger;
+    this.serverPrefix = serverPrefix;
   }
 
   synchronized CompileDir compile(Map<String, String> bindingProperties)
@@ -209,6 +211,10 @@
     // override computeScriptBase.js to enable the "Compile" button
     overrideConfig(moduleDef, "computeScriptBaseJs",
         "com/google/gwt/dev/codeserver/computeScriptBase.js");
+    // Fix bug with SDM and Chrome 24+ where //@ sourceURL directives cause X-SourceMap header to be ignored
+    // Frustratingly, Chrome won't canonicalize a relative URL
+    overrideConfig(moduleDef, "includeSourceMapUrl", "http://" + serverPrefix +
+        WebServer.sourceMapLocationForModule(moduleDef.getName()));
 
     // If present, set some config properties back to defaults.
     // (Needed for Google's server-side linker.)
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java
index 75108a9..52edcd8 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java
@@ -259,8 +259,7 @@
 
     String mimeType = guessMimeType(target);
     if (target.endsWith(".cache.js")) {
-      response.addHeader("X-SourceMap", SourceHandler.SOURCEMAP_PATH + moduleName +
-          "/gwtSourceMap.json");
+      response.addHeader("X-SourceMap", sourceMapLocationForModule(moduleName));
     }
     response.addHeader("Access-Control-Allow-Origin", "*");
     PageUtil.sendFile(mimeType, file, response);
@@ -380,6 +379,11 @@
     return result;
   }
 
+  public static String sourceMapLocationForModule(String moduleName) {
+     return SourceHandler.SOURCEMAP_PATH + moduleName +
+         "/gwtSourceMap.json";
+  }
+
   private static void setHandled(HttpServletRequest request) {
     Request baseRequest = (request instanceof Request) ? (Request) request :
         HttpConnection.getCurrentConnection().getRequest();
diff --git a/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java b/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java
index 556a6d7..8e59403 100644
--- a/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/CrossSiteIframeLinker.java
@@ -406,7 +406,20 @@
         + "__gwtModuleFunction.__computePropValue);");
     out.newlineOpt();
     out.print("$sendStats('moduleStartup', 'end');");
-    out.print("\n//@ sourceURL=0.js\n");
+    String includeSourceMapUrl = getStringConfigurationProperty(context, "includeSourceMapUrl", "false");
+    if (!"false".equalsIgnoreCase(includeSourceMapUrl)) {
+      String sourceMapUrl = SymbolMapsLinker.SourceMapArtifact.sourceMapFilenameForFragment(0);
+      if (!"true".equalsIgnoreCase(includeSourceMapUrl)) {
+        sourceMapUrl = includeSourceMapUrl;
+      }
+      // The sourceURL magic comment can cause browsers to ignore the X-SourceMap header
+      // This magic comment ensures that they can still locate them in that case
+      out.print("\n//@ sourceMappingURL=" + sourceMapUrl + " ");
+    }
+    // Magic comment serves several purposes:
+    // 1. renames strongName to a stable name in browser debugger
+    // 2. provides name to scripts installed via eval()
+    out.print("\n//@ sourceURL=0.js \n");
     return out.toString();
   }
 
diff --git a/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java b/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java
index 91a1d43..e4c8eaf 100644
--- a/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java
+++ b/dev/core/src/com/google/gwt/core/linker/SymbolMapsLinker.java
@@ -170,7 +170,7 @@
     private byte[] js;
 
     public SourceMapArtifact(int permutationId, int fragment, byte[] js) {
-      super(SymbolMapsLinker.class, permutationId + "/sourceMap" + fragment + ".json", js);
+      super(SymbolMapsLinker.class, permutationId + '/' + sourceMapFilenameForFragment(fragment), js);
       this.permutationId = permutationId;
       this.fragment = fragment;
       this.js = js;
@@ -183,6 +183,10 @@
     public int getPermutationId() {
       return permutationId;
     }
+
+    public static String sourceMapFilenameForFragment(int fragment) {
+             return "sourceMap" + fragment + ".json";
+    }
   }
 
   /**
diff --git a/user/src/com/google/gwt/core/CrossSiteIframeLinker.gwt.xml b/user/src/com/google/gwt/core/CrossSiteIframeLinker.gwt.xml
index b988b19..1c45f9d 100644
--- a/user/src/com/google/gwt/core/CrossSiteIframeLinker.gwt.xml
+++ b/user/src/com/google/gwt/core/CrossSiteIframeLinker.gwt.xml
@@ -23,7 +23,17 @@
   <define-configuration-property name="installScriptJs" is-multi-valued="false" />
   <define-configuration-property name="installCode" is-multi-valued="false" />
   <define-configuration-property name="computeScriptBaseJs" is-multi-valued="false" />
-
+  <!--
+     - Determines whether the GWT compiler generates cache.js files
+     - that end with a comment pointing to a sourcemap file, to support source-level
+     - debugging in browsers.
+     - Specification: http://goo.gl/ZQ3V3
+     - Takes on the following values:
+     - if false, no sourcemap URL declarations are included at the end of the primary fragment script
+     - if true, a relative URL to the standard sourcemap for the primary fragment is included
+     - else the value is assumed to be a custom URL -->
+  <define-configuration-property name="includeSourceMapUrl" is-multi-valued="false"/>
+  <set-configuration-property name="includeSourceMapUrl" value="false"/>
   <set-configuration-property name="xsiframe.failIfScriptTag" value="TRUE"/> 
 
   <replace-with class="com.google.gwt.core.client.impl.ScriptTagLoadingStrategy">
@@ -31,4 +41,6 @@
       class="com.google.gwt.core.client.impl.AsyncFragmentLoader.LoadingStrategy" />
     <when-linker-added name="xsiframe" />
   </replace-with>
+
+
 </module>