Developer Plugin should allow whitelisting of code server hosts
Solution was to whitelist the host/code servers as a pair.  In order to do
this, both common and browser specific code had to be modified.
Common:
  AllowedConnections:
    +Adding static getCodeServerFromUrl() to aid in fetching "gwt.codesvr="
values.
    +Modifying definition of internal Rule class from an stl-pairing of string &
bool
     to a simple class holding the host & code servers as strings and bool
expection
    +Updating matchesRule() to take host and code server as params
    +Update addRule() and initFromAccessList() to handle new pairing:
     [!]host[/code][,[!][host[/code]...]
Browsers:
  FireFox / Chrome:
    +Update UI to show both host/code server



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10242 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/plugins/npapi/DevModeOptions/src/com/google/gwt/devmodeoptions/client/DevModeOptions.java b/plugins/npapi/DevModeOptions/src/com/google/gwt/devmodeoptions/client/DevModeOptions.java
index 6ec7ae8..1c768a8 100644
--- a/plugins/npapi/DevModeOptions/src/com/google/gwt/devmodeoptions/client/DevModeOptions.java
+++ b/plugins/npapi/DevModeOptions/src/com/google/gwt/devmodeoptions/client/DevModeOptions.java
@@ -56,6 +56,9 @@
   @UiField
   TextBox hostname;
 
+  @UiField
+  TextBox codeserver;
+
   JsArray<HostEntry> hosts;
 
   @UiField
@@ -76,7 +79,9 @@
 
     addBtn.addClickHandler(new ClickHandler() {
       public void onClick(ClickEvent event) {
-        addHost(HostEntry.create(hostname.getText(), includeYes.getValue()));
+        addHost(HostEntry.create(hostname.getText() + "/"
+            + getCodeServer(codeserver),
+            includeYes.getValue()));
       }
     });
 
@@ -86,27 +91,52 @@
       hostname.setText(host);
     }
 
+    String code = Location.getParameter("codeserver");
+    if (code != null) {
+      codeserver.setText(code);
+    } else {
+      //default for users entering through options
+      codeserver.setText("localhost");
+    }
+
     hostname.addKeyPressHandler(new KeyPressHandler() {
       public void onKeyPress(KeyPressEvent event) {
         if (event.getCharCode() == KeyCodes.KEY_ENTER) {
-          addHost(HostEntry.create(hostname.getText(), includeYes.getValue()));
+        addHost(HostEntry.create(hostname.getText() + "/"
+            + getCodeServer(codeserver),
+            includeYes.getValue()));
         }
       }
     });
 
-    savedHosts.setText(0, 0, "Host");
-    savedHosts.setText(0, 1, "Include/Exclude");
-    savedHosts.setText(0, 2, "Remove");
+    codeserver.addKeyPressHandler(new KeyPressHandler() {
+      public void onKeyPress(KeyPressEvent event) {
+        if (event.getCharCode() == KeyCodes.KEY_ENTER) {
+        addHost(HostEntry.create(hostname.getText() + "/"
+            + getCodeServer(codeserver),
+            includeYes.getValue()));
+        }
+      }
+    });
+
+    savedHosts.setText(0, 0, "Web server");
+    savedHosts.setText(0, 1, "Code server");
+    savedHosts.setText(0, 2, "Include/Exclude");
+    savedHosts.setText(0, 3, "Remove");
     savedHosts.getCellFormatter().addStyleName(0, 0,
         bundle.css().savedHostsHeading());
     savedHosts.getCellFormatter().addStyleName(0, 0, bundle.css().textCol());
 
     savedHosts.getCellFormatter().addStyleName(0, 1,
         bundle.css().savedHostsHeading());
+    savedHosts.getCellFormatter().addStyleName(0, 1, bundle.css().textCol());
 
     savedHosts.getCellFormatter().addStyleName(0, 2,
         bundle.css().savedHostsHeading());
 
+    savedHosts.getCellFormatter().addStyleName(0, 3,
+        bundle.css().savedHostsHeading());
+
     for (int i = 0; i < hosts.length(); i++) {
       displayHost(hosts.get(i));
     }
@@ -135,6 +165,7 @@
 
     displayHost(newHost);
 
+    codeserver.setText("");
     hostname.setText("");
     hostname.setFocus(true);
   }
@@ -146,8 +177,13 @@
   private void displayHost(final HostEntry newHost) {
     int numRows = savedHosts.getRowCount();
     int col = 0;
+    
+    String[] names = newHost.getUrl().split("/");
+   
     savedHosts.insertRow(numRows);
-    savedHosts.setText(numRows, col++, newHost.getUrl());
+    savedHosts.setText(numRows, col++, names[0]);
+    savedHosts.setText(numRows, col++, names.length > 0 ? names[1] 
+        : "localhost");
     savedHosts.setText(numRows, col++, newHost.include() ? "Include"
         : "Exclude");
     if (newHost.include()) {
@@ -155,11 +191,15 @@
           bundle.css().include());
       savedHosts.getCellFormatter().addStyleName(numRows, 1,
           bundle.css().include());
+      savedHosts.getCellFormatter().addStyleName(numRows, 2,
+          bundle.css().include());
     } else {
       savedHosts.getCellFormatter().addStyleName(numRows, 0,
           bundle.css().exclude());
       savedHosts.getCellFormatter().addStyleName(numRows, 1,
           bundle.css().exclude());
+      savedHosts.getCellFormatter().addStyleName(numRows, 2,
+          bundle.css().exclude());
     }
 
     Button removeHostButton = new Button("x");
@@ -189,4 +229,8 @@
     HostEntryStorage.get().saveEntries(hosts);
   }
 
+  private String getCodeServer(TextBox box) {
+    return (box.getText().length() > 0) ? box.getText() : "localhost";
+  }
+
 }
diff --git a/plugins/npapi/DevModeOptions/src/com/google/gwt/devmodeoptions/client/DevModeOptions.ui.xml b/plugins/npapi/DevModeOptions/src/com/google/gwt/devmodeoptions/client/DevModeOptions.ui.xml
index 555ce15..0e87b88 100644
--- a/plugins/npapi/DevModeOptions/src/com/google/gwt/devmodeoptions/client/DevModeOptions.ui.xml
+++ b/plugins/npapi/DevModeOptions/src/com/google/gwt/devmodeoptions/client/DevModeOptions.ui.xml
@@ -17,7 +17,7 @@
 	<ui:with field='res'
 		type='com.google.gwt.devmodeoptions.client.DevModeOptionsResources' />
 	<g:HTMLPanel styleName="{res.css.mainPanel}">
-		<g:VerticalPanel>
+		<div>
 			<g:HorizontalPanel>
 				<g:Image resource='{res.gwt64}' styleName="{res.css.logo}" />
 				<g:HTML>
@@ -30,23 +30,30 @@
 				host/port at the request of a web page. To minimize security risks,
 				by default it will only connect to the local machine. To allow
 				cross-machine debugging, you can add exceptions here -- include the
-				exact host name of the web servers you will use for debugging, but
-				do not include any you do not trust.</g:Label>
+				exact host name of the web and code servers you will use for debugging, 
+				but do not include any you do not trust.</g:Label>
 
 			<g:Label ui:field="errorMessage" styleName="{res.css.errorMessage}"/>
-			<g:HorizontalPanel>
-				<g:TextBox ui:field="hostname" styleName="{res.css.textBox}" />
-				<g:Button styleName="{res.css.important}" ui:field="addBtn">Add</g:Button>
-				<g:VerticalPanel>
-					<g:RadioButton name="include" ui:field="includeYes"
-						checked="true">Include</g:RadioButton>
-					<g:RadioButton name="include" ui:field="includeNo">Exclude</g:RadioButton>
-				</g:VerticalPanel>
-			</g:HorizontalPanel>
+			<div>
+				<div style="float:left">
+					<g:TextBox ui:field="hostname" styleName="{res.css.textBox}" />
+					<g:TextBox ui:field="codeserver" styleName="{res.css.textBox}" />
+					<g:Button styleName="{res.css.important}" ui:field="addBtn">Add</g:Button>
+				</div>
+				<div style="float:left">
+					<div>
+						<g:RadioButton name="include" ui:field="includeYes"
+							checked="true">Include</g:RadioButton>
+					</div>
+					<div>
+						<g:RadioButton name="include" ui:field="includeNo">Exclude</g:RadioButton>
+					</div>
+				</div>
+			</div>
 
 			<g:FlexTable ui:field="savedHosts" styleName="{res.css.savedHosts}">
 			</g:FlexTable>
-		</g:VerticalPanel>
+		</div>
 	</g:HTMLPanel>
 
 </ui:UiBinder> 
diff --git a/plugins/npapi/DevModeOptions/src/com/google/gwt/devmodeoptions/client/resources/DevModeOptions.css b/plugins/npapi/DevModeOptions/src/com/google/gwt/devmodeoptions/client/resources/DevModeOptions.css
index f42e7ad..51d8605 100644
--- a/plugins/npapi/DevModeOptions/src/com/google/gwt/devmodeoptions/client/resources/DevModeOptions.css
+++ b/plugins/npapi/DevModeOptions/src/com/google/gwt/devmodeoptions/client/resources/DevModeOptions.css
@@ -47,7 +47,7 @@
 }
 
 .textBox {
-  width: TEXTWIDTH;
+  width: 15em;
 }
 
 .textCol {
diff --git a/plugins/npapi/ScriptableInstance.cpp b/plugins/npapi/ScriptableInstance.cpp
index 7acbeee..4344a5b 100644
--- a/plugins/npapi/ScriptableInstance.cpp
+++ b/plugins/npapi/ScriptableInstance.cpp
@@ -307,7 +307,13 @@
       }
       bool include = includeVariant.getAsBoolean();
       Debug::log(Debug::Info) << "Adding " << urlString << "(" << (include ? "include" : "exclude") << ")\n";
-      AllowedConnections::addRule(urlString, !include);
+
+      int slash = urlString.find( '/' );
+      if( slash == std::string::npos ) {
+        AllowedConnections::addRule(urlString, "localhost", !include);
+      } else {
+        AllowedConnections::addRule(urlString.substr( 0, slash), urlString.substr(slash+1), !include);
+      }
     }
   } else {
     Debug::log(Debug::Error) << "ScriptableInstance::loadHostEntries called from outside the background page: " <<
@@ -323,9 +329,13 @@
   const NPString url = args[0].value.stringValue;
   const string urlStr = convertToString(url);
   bool allowed = false;
-  bool matches = AllowedConnections::matchesRule(urlStr, &allowed);
-  string retStr;
 
+  Debug::log(Debug::Info) << "getHostPermission() url " << urlStr << Debug::flush;
+  bool matches = AllowedConnections::matchesRule(
+      AllowedConnections::getHostFromUrl(urlStr),
+      AllowedConnections::getCodeServerFromUrl(urlStr),
+      &allowed);
+  string retStr;
   if (!matches) {
     retStr = UNKNOWN_STR;
   } else if (allowed) {
@@ -371,7 +381,10 @@
       << ")" << Debug::flush;
 
   bool allowed = false;
-  AllowedConnections::matchesRule(urlStr, &allowed);
+  AllowedConnections::matchesRule(
+      AllowedConnections::getHostFromUrl(urlStr),
+      AllowedConnections::getCodeServerFromUrl(appUrlStr),
+      &allowed);
   if (!allowed) {
     BOOLEAN_TO_NPVARIANT(false, *result);
     result->type = NPVariantType_Bool;
diff --git a/plugins/npapi/VisualStudio/npapi-plugin.sln b/plugins/npapi/VisualStudio/npapi-plugin.sln
index 8d6e04a..1705f7d 100755
--- a/plugins/npapi/VisualStudio/npapi-plugin.sln
+++ b/plugins/npapi/VisualStudio/npapi-plugin.sln
@@ -1,7 +1,7 @@
 
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "npapi-plugin", "npapi-plugin.vcproj", "{6BF0C2CE-CB0C-421B-A67C-1E448371D24A}"
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "npapi-plugin", "npapi-plugin.vcxproj", "{6BF0C2CE-CB0C-421B-A67C-1E448371D24A}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/plugins/npapi/prebuilt/gwt-dev-plugin/Darwin-gcc3/gwtDev.plugin/Contents/MacOS/libGwtDevPlugin.dylib b/plugins/npapi/prebuilt/gwt-dev-plugin/Darwin-gcc3/gwtDev.plugin/Contents/MacOS/libGwtDevPlugin.dylib
index a9cedcc..b089cef 100755
--- a/plugins/npapi/prebuilt/gwt-dev-plugin/Darwin-gcc3/gwtDev.plugin/Contents/MacOS/libGwtDevPlugin.dylib
+++ b/plugins/npapi/prebuilt/gwt-dev-plugin/Darwin-gcc3/gwtDev.plugin/Contents/MacOS/libGwtDevPlugin.dylib
Binary files differ
diff --git a/plugins/npapi/prebuilt/gwt-dev-plugin/Linux_x86-gcc3/libGwtDevPlugin.so b/plugins/npapi/prebuilt/gwt-dev-plugin/Linux_x86-gcc3/libGwtDevPlugin.so
index 4783c49..a25d124 100755
--- a/plugins/npapi/prebuilt/gwt-dev-plugin/Linux_x86-gcc3/libGwtDevPlugin.so
+++ b/plugins/npapi/prebuilt/gwt-dev-plugin/Linux_x86-gcc3/libGwtDevPlugin.so
Binary files differ
diff --git a/plugins/npapi/prebuilt/gwt-dev-plugin/Linux_x86_64-gcc3/libGwtDevPlugin.so b/plugins/npapi/prebuilt/gwt-dev-plugin/Linux_x86_64-gcc3/libGwtDevPlugin.so
index cf3b9f2..c0e4546 100755
--- a/plugins/npapi/prebuilt/gwt-dev-plugin/Linux_x86_64-gcc3/libGwtDevPlugin.so
+++ b/plugins/npapi/prebuilt/gwt-dev-plugin/Linux_x86_64-gcc3/libGwtDevPlugin.so
Binary files differ
diff --git a/plugins/npapi/prebuilt/gwt-dev-plugin/WINNT_x86-msvc/npGwtDevPlugin.dll b/plugins/npapi/prebuilt/gwt-dev-plugin/WINNT_x86-msvc/npGwtDevPlugin.dll
index 1e62460..cbc3f58 100755
--- a/plugins/npapi/prebuilt/gwt-dev-plugin/WINNT_x86-msvc/npGwtDevPlugin.dll
+++ b/plugins/npapi/prebuilt/gwt-dev-plugin/WINNT_x86-msvc/npGwtDevPlugin.dll
Binary files differ
diff --git a/plugins/npapi/prebuilt/gwt-dev-plugin/background.html b/plugins/npapi/prebuilt/gwt-dev-plugin/background.html
index 2569678..fe60956 100644
--- a/plugins/npapi/prebuilt/gwt-dev-plugin/background.html
+++ b/plugins/npapi/prebuilt/gwt-dev-plugin/background.html
@@ -22,23 +22,48 @@
   }
   idx = hostname.indexOf('/');
   if (idx >= 0) {
-    hostname = hostname.split('/')[0];
+    hostname = hostname.substring(0,idx);
+  }
+  idx = hostname.indexOf('@');
+  if( idx >= 0)
+  {
+    hostname = hostname.substring(idx+1);
   }
   idx = hostname.indexOf(':');
   if (idx >= 0) {
-    hostname = hostname.split(':')[0];
+    hostname = hostname.substring(0,idx);
   }
   return hostname;
 }
 
+function getCodeServerFromUrl(url) {
+  var idx = url.indexOf('?');
+  if (idx < 0) {
+    return '';
+  }
+  url = url.substring(idx+1);
+  idx = url.indexOf('gwt.codesvr=');
+  if( idx < 0 ) {
+    return '';
+  }
+  url = url.substring(idx+12);
+  var colon = url.indexOf(':');
+  var amp   = url.indexOf('&');
+  if( amp < 0 || colon < amp ) {
+    amp = colon;
+  }
+  return amp < 0 ? url : url.substring(0,amp);
+}
+
 function devModeTabListener(tabId, changeInfo, tab) {
   var search = tab.url.slice(tab.url.indexOf('?'));
   if (search.indexOf('gwt.codesvr=') >= 0 || search.indexOf('gwt.hosted=') >= 0) {
     var permission = plugin.getHostPermission(tab.url);
     var host = getHostFromUrl(tab.url);
+    var code = getCodeServerFromUrl(tab.url);
     var popup = 'page_action.html';
     var icon = null;
-    console.log("got permission " + permission + " for host " + host);
+    console.log("got permission " + permission + " for host " + host + '/ code ' + code);
 
     if (permission == 'include') {
       icon = enabledIcon;
@@ -47,7 +72,7 @@
     } else if (permission == 'unknown') {
       icon = disabledIcon;
     }
-    popup += "?permission=" + permission + "&host=" + host;
+    popup += "?permission=" + permission + "&host=" + host + "&codeserver=" + code;
     chrome.pageAction.setIcon({'tabId' : tabId, 'path' : icon});
     chrome.pageAction.setPopup({'tabId' : tabId, 'popup' : popup});
     chrome.pageAction.show(tabId);
diff --git a/plugins/npapi/prebuilt/gwt-dev-plugin/page_action.html b/plugins/npapi/prebuilt/gwt-dev-plugin/page_action.html
index f891515..4094828 100644
--- a/plugins/npapi/prebuilt/gwt-dev-plugin/page_action.html
+++ b/plugins/npapi/prebuilt/gwt-dev-plugin/page_action.html
@@ -18,21 +18,22 @@
     function init() {
       var permission = getParam('permission');
       var host = getParam('host');
+      var code = getParam('codeserver');
       var message='';
 
       if (permission == 'include') {
-        message = 'The host at ' + host + ' is allowed to use the plugin';
+        message = 'The web and code server (' + host + '/' + code + ') is allowed to use the plugin';
       } else if (permission == 'exclude') {
-        message = 'The host at ' + host + ' has been been blacklisted.';
+        message = 'The web and code server (' + host + '/' + code + ') has been been blacklisted.';
       } else if (permission == 'unknown') {
-        message = 'The host at ' + host + ' is unknown to the plugin.';
+        message = 'The web and code server (' + host + '/' + code + ') is unknown to the plugin.';
       }
 
       document.getElementById('message').innerText = message;
     }
 
     function updateConfiguration() {
-      var url = 'DevModeOptions.html?host=' + getParam('host');
+      var url = 'DevModeOptions.html?host=' + getParam('host') + '&codeserver=' + getParam('codeserver');
       url = chrome.extension.getURL(url);
       chrome.tabs.create({'url' : url});
     }