Upgrade HtmlUnit to 2.55.0 and Jetty to 9.4.44

Several old tests previously not able to run in HtmlUnit are now
enabled, and two tests are disabled, linked to the appropriate bug
report.

The jaspi security/authentication module has been disabled in the dev
mode server. It is no longer included in the base jetty install due to
licensing reasons, and is disabled by default here for the same reason.

Many small changes were necessary across various parts of testing and
dev mode infrastructure:
 * HtmlUnit has introduced a proxy for window and document, legacy dev
   mode needs to treat those objects as if they were the real instance.
 * HtmlUnit has additional protection to avoid letting a page interact
   with a real Java object. This had to be relaxed in order to let
   legacy dev mode tests continue to work.
 * The custom classloader used to run a webapp within dev mode now
   overrides loadClass instead of findClass, to correctly delegate to
   Jetty's own implementation to handle startup issues. Additionally,
   isSystemClass and isServerClass are relocated and deprecated.

Bug: #9720
Bug-Link: https://github.com/gwtproject/gwt/issues/9720
Co-Authored-By: Mihai Stanciu <mihaisdm@gmail.com>
Change-Id: Ie14cb33cb0edea57c121de943f2964a8cf0540ee
diff --git a/dev/build.xml b/dev/build.xml
index 69962fd..37ffb3e 100755
--- a/dev/build.xml
+++ b/dev/build.xml
@@ -79,44 +79,46 @@
           <include name="colt/colt-1.2.jar"/>
           <include name="eclipse/org.eclipse.jdt.core_3.17.0.v20190306-2240.jar"/>
           <include name="eclipse/jdtCompilerAdapter_3.17.0.v20190306-2240.jar"/>
-          <include name="objectweb/asm-7.1/asm-7.1.jar"/>
-          <include name="objectweb/asm-7.1/asm-commons-7.1.jar"/>
-          <include name="objectweb/asm-7.1/asm-util-7.1.jar"/>
+          <include name="objectweb/asm-9.2/asm-9.2.jar"/>
+          <include name="objectweb/asm-9.2/asm-commons-9.2.jar"/>
+          <include name="objectweb/asm-9.2/asm-util-9.2.jar"/>
           <include name="guava/guava-19.0/guava-19.0-rebased.jar"/>
           <include name="icu4j/63.1/icu4j.jar"/>
-          <include name="jetty/jetty-9.2.14.v20151106/jetty-all-9.2.14.v20151106.jar"/>
+          <include name="jetty/jetty-9.4.44.v20210927/jetty-all-9.4.44.v20210927.jar"/>
           <include name="gson/gson-2.6.2.jar"/>
           <include name="jscomp/20160315/sourcemap-rebased.jar"/>
           <include name="jsr305/jsr305.jar"/>
           <include name="protobuf/protobuf-2.5.0/protobuf-java-rebased-2.5.0.jar"/>
           <!-- dependencies needed for JSP support in DevMode: BEGIN -->
-          <include name="jetty/jetty-9.2.14.v20151106/mortbay-apache-jsp-8.0.9.M3.jar"/>
-          <include name="jetty/jetty-9.2.14.v20151106/mortbay-apache-el-8.0.9.M3.jar"/>
-          <include name="jetty/jetty-9.2.14.v20151106/jetty-apache-jsp-9.2.14.v20151106.jar"/>
+          <include name="jetty/jetty-9.4.44.v20210927/mortbay-apache-jsp-8.5.70.jar"/>
+          <include name="jetty/jetty-9.4.44.v20210927/mortbay-apache-el-8.5.70.jar"/>
+          <include name="jetty/jetty-9.4.44.v20210927/jetty-apache-jsp-9.4.44.v20210927.jar"/>
           <!-- dependencies needed for JSP support in DevMode: END -->
           <include name="tomcat/tomcat-servlet-api-8.0.28.jar"/>
           <include name="tomcat/tomcat-websocket-api-8.0.28.jar"/>
           <include name="tomcat/tomcat-annotations-api-8.0.28.jar"/>
           <include name="apache/commons/commons-collections-3.2.2.jar"/>
           <!-- htmlunit dependencies not already included: BEGIN -->
-          <include name="apache/http/httpclient-4.5.1.jar"/>
-          <include name="apache/http/httpcore-4.4.4.jar"/>
-          <include name="apache/http/httpmime-4.5.1.jar"/>
+          <include name="apache/http/httpclient-4.5.13.jar"/>
+          <include name="apache/http/httpcore-4.4.13.jar"/>
+          <include name="apache/http/httpmime-4.5.13.jar"/>
           <include name="apache/james/apache-mime4j-0.6.jar"/>
           <include name="apache/commons/commons-codec-1.10.jar"/>
           <include name="apache/commons/commons-io-2.4.jar"/>
           <include name="apache/commons/commons-lang3-3.4.jar"/>
           <include name="apache/commons/commons-logging-1.2.jar"/>
-          <include name="cssparser/cssparser-0.9.18.jar"/>
-         <include name="htmlunit/htmlunit-2.19/htmlunit-2.19.jar"/>
-         <include name="htmlunit/htmlunit-2.19/htmlunit-core-js-2.15.jar"/>
-          <include name="nekohtml/nekohtml-1.9.22.jar"/>
+          <include name="htmlunit/htmlunit-2.55.0/htmlunit-cssparser-1.10.0.jar"/>
+          <include name="htmlunit/htmlunit-2.55.0/htmlunit-2.55.0.jar"/>
+          <include name="htmlunit/htmlunit-2.55.0/htmlunit-core-js-2.55.0.jar"/>
+          <include name="htmlunit/htmlunit-2.55.0/neko-htmlunit-2.55.0.jar"/>
+          <include name="htmlunit/htmlunit-2.55.0/salvation2-3.0.0.jar"/>
           <include name="cup/java-cup-11a.jar"/>
           <include name="xalan/xalan-2.7.1-nocup.jar"/>
           <include name="xerces/xerces-2_11_0/serializer-2.7.1.jar"/>
           <include name="xerces/xerces-2_11_0/xercesImpl-2.11.0.jar"/>
           <include name="xerces/xerces-2_11_0/xml-apis-1.4.01.jar"/>
           <include name="w3c/sac/sac-1.3.jar"/>
+          <include name="brotli/dec-0.1.2.jar"/>
           <!-- htmlunit dependencies not already included: END -->
           <include name="json/android-sdk-19.1/json-android-rebased.jar"/>
         </fileset>
@@ -131,9 +133,9 @@
             <provider classname="org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer"/>
             <provider classname="org.eclipse.jetty.apache.jsp.JettyJasperInitializer"/>
           </service>
-          <zipfileset src="${gwt.tools.lib}/objectweb/asm-7.1/asm-7.1.jar"/>
-          <zipfileset src="${gwt.tools.lib}/objectweb/asm-7.1/asm-commons-7.1.jar"/>
-          <zipfileset src="${gwt.tools.lib}/objectweb/asm-7.1/asm-util-7.1.jar"/>
+          <zipfileset src="${gwt.tools.lib}/objectweb/asm-9.2/asm-9.2.jar"/>
+          <zipfileset src="${gwt.tools.lib}/objectweb/asm-9.2/asm-commons-9.2.jar"/>
+          <zipfileset src="${gwt.tools.lib}/objectweb/asm-9.2/asm-util-9.2.jar"/>
           <zipfileset src="${gwt.tools.lib}/apache/tapestry-util-text-4.0.2.jar"/>
           <zipfileset src="${gwt.tools.lib}/apache/ant-zipscanner/ant-zipscanner-1.6.5-1-rebased.jar"/>
           <zipfileset src="${gwt.tools.lib}/colt/colt-1.2.jar"/>
@@ -144,16 +146,22 @@
           <zipfileset src="${gwt.tools.lib}/guava/guava-19.0/guava-19.0-rebased.jar"/>
           <zipfileset src="${gwt.tools.lib}/icu4j/63.1/icu4j.jar"/>
           <zipfileset
-              src="${gwt.tools.lib}/jetty/jetty-9.2.14.v20151106/jetty-all-9.2.14.v20151106.jar"/>
+              src="${gwt.tools.lib}/jetty/jetty-9.4.44.v20210927/jetty-all-9.4.44.v20210927.jar">
+            <!--
+            Don't add jetty auth implementation from jetty-jaspi, as we would also need to package jetty's
+            javax.security.auth.message implementation as well as geronimo-jaspi.
+             -->
+            <exclude name="META-INF/services/org.eclipse.jetty.security.Authenticator$Factory"/>
+          </zipfileset>
           <zipfileset src="${gwt.tools.lib}/gson/gson-2.6.2.jar"/>
           <zipfileset src="${gwt.tools.lib}/jscomp/20160315/sourcemap-rebased.jar"/>
           <zipfileset src="${gwt.tools.lib}/jsr305/jsr305.jar"/>
           <zipfileset
               src="${gwt.tools.lib}/protobuf/protobuf-2.5.0/protobuf-java-rebased-2.5.0.jar"/>
           <!-- dependencies needed for JSP support in DevMode: BEGIN -->
-          <zipfileset src="${gwt.tools.lib}/jetty/jetty-9.2.14.v20151106/mortbay-apache-jsp-8.0.9.M3.jar"/>
-          <zipfileset src="${gwt.tools.lib}/jetty/jetty-9.2.14.v20151106/mortbay-apache-el-8.0.9.M3.jar"/>
-          <zipfileset src="${gwt.tools.lib}/jetty/jetty-9.2.14.v20151106/jetty-apache-jsp-9.2.14.v20151106.jar"/>
+          <zipfileset src="${gwt.tools.lib}/jetty/jetty-9.4.44.v20210927/mortbay-apache-jsp-8.5.70.jar"/>
+          <zipfileset src="${gwt.tools.lib}/jetty/jetty-9.4.44.v20210927/mortbay-apache-el-8.5.70.jar"/>
+          <zipfileset src="${gwt.tools.lib}/jetty/jetty-9.4.44.v20210927/jetty-apache-jsp-9.4.44.v20210927.jar"/>
           <!-- dependencies needed for JSP support in DevMode: END -->
           <zipfileset src="${gwt.tools.lib}/tomcat/tomcat-servlet-api-8.0.28.jar"/>
           <zipfileset src="${gwt.tools.lib}/tomcat/tomcat-websocket-api-8.0.28.jar"/>
@@ -161,25 +169,27 @@
           <zipfileset
               src="${gwt.tools.lib}/apache/commons/commons-collections-3.2.2.jar"/>
           <!-- htmlunit dependencies not already included: BEGIN -->
-          <zipfileset src="${gwt.tools.lib}/apache/http/httpclient-4.5.1.jar"/>
-          <zipfileset src="${gwt.tools.lib}/apache/http/httpcore-4.4.4.jar"/>
-          <zipfileset src="${gwt.tools.lib}/apache/http/httpmime-4.5.1.jar"/>
+          <zipfileset src="${gwt.tools.lib}/apache/http/httpclient-4.5.13.jar"/>
+          <zipfileset src="${gwt.tools.lib}/apache/http/httpcore-4.4.13.jar"/>
+          <zipfileset src="${gwt.tools.lib}/apache/http/httpmime-4.5.13.jar"/>
           <zipfileset src="${gwt.tools.lib}/apache/james/apache-mime4j-0.6.jar"/>
           <zipfileset src="${gwt.tools.lib}/apache/commons/commons-codec-1.10.jar"/>
           <zipfileset src="${gwt.tools.lib}/apache/commons/commons-io-2.4.jar"/>
           <zipfileset src="${gwt.tools.lib}/apache/commons/commons-lang3-3.4.jar"/>
           <zipfileset src="${gwt.tools.lib}/apache/commons/commons-logging-1.2.jar"/>
-          <zipfileset src="${gwt.tools.lib}/cssparser/cssparser-0.9.18.jar"/>
-          <zipfileset src="${gwt.tools.lib}/htmlunit/htmlunit-2.19/htmlunit-2.19.jar"/>
+          <zipfileset src="${gwt.tools.lib}/htmlunit/htmlunit-2.55.0/htmlunit-cssparser-1.10.0.jar"/>
+          <zipfileset src="${gwt.tools.lib}/htmlunit/htmlunit-2.55.0/htmlunit-2.55.0.jar"/>
           <zipfileset
-              src="${gwt.tools.lib}/htmlunit/htmlunit-2.19/htmlunit-core-js-2.15.jar"/>
-          <zipfileset src="${gwt.tools.lib}/nekohtml/nekohtml-1.9.22.jar"/>
+              src="${gwt.tools.lib}/htmlunit/htmlunit-2.55.0/htmlunit-core-js-2.55.0.jar"/>
+          <zipfileset src="${gwt.tools.lib}/htmlunit/htmlunit-2.55.0/neko-htmlunit-2.55.0.jar"/>
+          <zipfileset src="${gwt.tools.lib}/htmlunit/htmlunit-2.55.0/salvation2-3.0.0.jar"/>
           <zipfileset src="${gwt.tools.lib}/cup/java-cup-11a.jar"/>
           <zipfileset src="${gwt.tools.lib}/xalan/xalan-2.7.1-nocup.jar"/>
           <zipfileset src="${gwt.tools.lib}/xerces/xerces-2_11_0/serializer-2.7.1.jar"/>
           <zipfileset src="${gwt.tools.lib}/xerces/xerces-2_11_0/xercesImpl-2.11.0.jar"/>
           <zipfileset src="${gwt.tools.lib}/xerces/xerces-2_11_0/xml-apis-1.4.01.jar"/>
           <zipfileset src="${gwt.tools.lib}/w3c/sac/sac-1.3.jar"/>
+          <zipfileset src="${gwt.tools.lib}/brotli/dec-0.1.2.jar"/>
           <!-- htmlunit dependencies not already included: END -->
           <zipfileset src="${gwt.tools.lib}/json/android-sdk-19.1/json-android-rebased.jar"/>
         </gwt.jar>
@@ -226,9 +236,9 @@
       <classpath>
         <pathelement location="${gwt.tools.lib}/apache/ant-zipscanner/ant-zipscanner-1.6.5-1-rebased.jar"/>
         <pathelement location="${gwt.tools.lib}/colt/colt-1.2.jar"/>
-        <pathelement location="${gwt.tools.lib}/objectweb/asm-7.1/asm-7.1.jar"/>
-        <pathelement location="${gwt.tools.lib}/objectweb/asm-7.1/asm-commons-7.1.jar"/>
-        <pathelement location="${gwt.tools.lib}/objectweb/asm-7.1/asm-util-7.1.jar"/>
+        <pathelement location="${gwt.tools.lib}/objectweb/asm-9.2/asm-9.2.jar"/>
+        <pathelement location="${gwt.tools.lib}/objectweb/asm-9.2/asm-commons-9.2.jar"/>
+        <pathelement location="${gwt.tools.lib}/objectweb/asm-9.2/asm-util-9.2.jar"/>
         <pathelement
             location="${gwt.tools.lib}/apache/commons/commons-collections-3.2.2.jar"/>
         <pathelement
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 2b91969..d6b333a 100644
--- a/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java
+++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/WebServer.java
@@ -123,7 +123,6 @@
     connector.setHost(bindAddress);
     connector.setPort(port);
     connector.setReuseAddress(false);
-    connector.setSoLingerTime(0);
     newServer.addConnector(connector);
 
     ServletContextHandler newHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
diff --git a/dev/core/src/com/google/gwt/dev/shell/HostedModePluginObject.java b/dev/core/src/com/google/gwt/dev/shell/HostedModePluginObject.java
index 68af427..98d5051 100644
--- a/dev/core/src/com/google/gwt/dev/shell/HostedModePluginObject.java
+++ b/dev/core/src/com/google/gwt/dev/shell/HostedModePluginObject.java
@@ -17,9 +17,9 @@
 
 import com.google.gwt.core.ext.TreeLogger;
 
+import com.gargoylesoftware.htmlunit.WebClient;
 import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
 import com.gargoylesoftware.htmlunit.javascript.host.Window;
-import com.gargoylesoftware.htmlunit.javascript.host.WindowProxy;
 
 import net.sourceforge.htmlunit.corejs.javascript.Context;
 import net.sourceforge.htmlunit.corejs.javascript.Function;
@@ -27,6 +27,7 @@
 import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;
 
 import java.io.IOException;
+import java.util.Collections;
 
 /**
  * HTMLUnit object that represents the hosted-mode plugin.
@@ -122,11 +123,10 @@
             + " init: expected 1, got " + args.length);
       }
       try {
-        window = ((WindowProxy) args[0]).getDelegee();
+        window = (Window) args[0];
         return init(VERSION);
       } catch (ClassCastException e) {
-        throw Context.reportRuntimeError("Incorrect parameter types for "
-            + " initt: expected String");
+        throw Context.reportRuntimeError("Incorrect parameter types for init: expected Window");
       }
     }
 
@@ -149,6 +149,7 @@
   private Scriptable initMethod;
   private Window window;
   private final JavaScriptEngine jsEngine;
+  private final WebClient webClient;
   private final TreeLogger logger;
 
   private BrowserChannelClient browserChannelClient;
@@ -157,9 +158,12 @@
    * Creates a HostedModePluginObject with the passed-in JavaScriptEngine.
    *
    * @param jsEngine The JavaScriptEngine.
+   * @param webClient The WebClient being tested.
+   * @param logger A logger instance to notify the user of errors.
    */
-  public HostedModePluginObject(JavaScriptEngine jsEngine, TreeLogger logger) {
+  public HostedModePluginObject(JavaScriptEngine jsEngine, WebClient webClient, TreeLogger logger) {
     this.jsEngine = jsEngine;
+    this.webClient = webClient;
     this.logger = logger;
   }
 
@@ -184,9 +188,17 @@
     }
     // TODO: add whitelist and default-port support?
 
+    // We know that legacy dev mode is running, we need to tell HtmlUnit that it is safe
+    // to permit plain Java objects to leak into JS - the JavaObject type will return a
+    // Object[] with a success boolean and a value, and HtmlUnit will guard against this.
+    // The simplest way to do that here is to mark java.lang.Object as the java equivalent
+    // of some JS type - the name of the type doesn't matter.
+    webClient.setActiveXObjectMap(Collections.singletonMap(
+            "GwtLegacyDevModeExceptionOrReturnValue", "java.lang.Object"));
+
     try {
       HtmlUnitSessionHandler htmlUnitSessionHandler = new HtmlUnitSessionHandler(
-          window, jsEngine);
+          window, jsEngine, webClient);
       browserChannelClient = new BrowserChannelClient(addressParts, url,
           sessionKey, module, version, htmlUnitSessionHandler);
       htmlUnitSessionHandler.setSessionData(new SessionData(
diff --git a/dev/core/src/com/google/gwt/dev/shell/HtmlUnitSessionHandler.java b/dev/core/src/com/google/gwt/dev/shell/HtmlUnitSessionHandler.java
index 81cc71c..75abb3a 100644
--- a/dev/core/src/com/google/gwt/dev/shell/HtmlUnitSessionHandler.java
+++ b/dev/core/src/com/google/gwt/dev/shell/HtmlUnitSessionHandler.java
@@ -25,6 +25,7 @@
 
 import com.gargoylesoftware.htmlunit.ScriptException;
 import com.gargoylesoftware.htmlunit.ScriptResult;
+import com.gargoylesoftware.htmlunit.WebClient;
 import com.gargoylesoftware.htmlunit.WebWindow;
 import com.gargoylesoftware.htmlunit.html.HtmlPage;
 import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
@@ -108,9 +109,11 @@
   private final ToStringMethod toStringMethod = new ToStringMethod();
 
   private final Window window;
+  private final WebClient webClient;
 
-  HtmlUnitSessionHandler(Window window, JavaScriptEngine jsEngine) {
+  HtmlUnitSessionHandler(Window window, JavaScriptEngine jsEngine, WebClient webClient) {
     this.window = window;
+    this.webClient = webClient;
     logger.setMaxDetail(TreeLogger.ERROR);
     this.jsEngine = jsEngine;
     htmlPage = (HtmlPage) this.window.getWebWindow().getEnclosedPage();
@@ -161,7 +164,7 @@
   @Override
   public String getUserAgent() {
     return "HtmlUnit-"
-        + jsEngine.getWebClient().getBrowserVersion().getUserAgent();
+        + webClient.getBrowserVersion().getUserAgent();
   }
 
   @SuppressWarnings("unchecked")
@@ -286,6 +289,15 @@
       return returnVal;
     }
     if (value instanceof Scriptable) {
+      if (value instanceof SimpleScriptableProxy) {
+        // HtmlUnit will return proxies to java for the window/document objects,
+        // so that those objects can work after navigating away from the page.
+        // However, GWTTestCase operates inside a single page session, so we
+        // can unwrap these proxies to get the real instance. Without doing
+        // this, the refToJsObject mapping would indicate that an object might
+        // not equal itself
+        value = ((SimpleScriptableProxy<?>) value).getDelegee();
+      }
       if (value instanceof ScriptableObject) {
         /*
          * HACK: check for native types like NativeString. NativeString is
diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
index fcfe5d3..9c1475c 100644
--- a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
+++ b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
@@ -26,6 +26,7 @@
 
 import org.eclipse.jetty.http.HttpField;
 import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.security.ConstraintSecurityHandler;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.HttpConnectionFactory;
 import org.eclipse.jetty.server.Request;
@@ -36,6 +37,8 @@
 import org.eclipse.jetty.server.ServerConnector;
 import org.eclipse.jetty.server.SslConnectionFactory;
 import org.eclipse.jetty.server.handler.RequestLogHandler;
+import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
+import org.eclipse.jetty.servlet.ServletContextHandler;
 import org.eclipse.jetty.util.component.AbstractLifeCycle;
 import org.eclipse.jetty.util.log.Log;
 import org.eclipse.jetty.util.log.Logger;
@@ -127,7 +130,7 @@
       }
       if (logger.isLoggable(logStatus)) {
         TreeLogger branch = logger.branch(logStatus, String.valueOf(status)
-            + " - " + request.getMethod() + ' ' + request.getUri() + " ("
+            + " - " + request.getMethod() + ' ' + request.getRequestURI() + " ("
             + userString + request.getRemoteHost() + ')' + bytesString);
         if (branch.isLoggable(logHeaders)) {
           logHeaders(branch.branch(logHeaders, "Request headers"), logHeaders,
@@ -350,6 +353,7 @@
       private final ClasspathPattern systemClassesFromWebappFirst = new ClasspathPattern(new String[] {
           "-javax.servlet.",
           "-javax.el.",
+          "-javax.websocket.",
           "javax.",
       });
       private final ClasspathPattern allowedFromSystemClassLoader = new ClasspathPattern(new String[] {
@@ -371,11 +375,13 @@
 
       @Override
       public Enumeration<URL> getResources(String name) throws IOException {
-        // Logic copied from Jetty's WebAppClassLoader
-        List<URL> fromParent = isServerClass(name)
+        // Logic copied from Jetty's WebAppClassLoader, modified to use the system classloader
+        // instead of the parent classloader for server classes
+        List<URL> fromParent = WebAppContextWithReload.this.isServerClass(name)
             ? Collections.<URL>emptyList()
             : Lists.newArrayList(Iterators.forEnumeration(systemClassLoader.getResources(name)));
-        Iterator<URL> fromWebapp = isSystemClass(name) && !fromParent.isEmpty()
+        Iterator<URL> fromWebapp = WebAppContextWithReload.this.isSystemClass(name)
+                && !fromParent.isEmpty()
             ? Collections.<URL>emptyIterator()
             : Iterators.forEnumeration(findResources(name));
         return Iterators.asEnumeration(Iterators.concat(fromWebapp, fromParent.iterator()));
@@ -394,7 +400,8 @@
         // Note: bootstrap has already been searched, so javax. classes should be
         // tried from the webapp first (except for javax.servlet and javax.el).
         URL found;
-        if (isSystemClass(checkName) && !systemClassesFromWebappFirst.match(checkName)) {
+        if (WebAppContextWithReload.this.isSystemClass(checkName)
+                && !systemClassesFromWebappFirst.match(checkName)) {
           found = systemClassLoader.getResource(name);
           if (found != null) {
             return found;
@@ -409,7 +416,7 @@
 
         // See if the outside world has it.
         found = systemClassLoader.getResource(name);
-        if (found == null || isServerClass(checkName)) {
+        if (found == null || WebAppContextWithReload.this.isServerClass(checkName)) {
           return null;
         }
 
@@ -431,22 +438,27 @@
       }
 
       @Override
-      protected Class<?> findClass(String name) throws ClassNotFoundException {
+      protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
         // For system path, always prefer the outside world.
         // Note: bootstrap has already been searched, so javax. classes should be
         // tried from the webapp first (except for javax.servlet).
-        if (isSystemClass(name) && !systemClassesFromWebappFirst.match(name)) {
+        if (WebAppContextWithReload.this.isSystemClass(name)
+                && !systemClassesFromWebappFirst.match(name)) {
           try {
-            return systemClassLoader.loadClass(name);
+            Class<?> loaded = systemClassLoader.loadClass(name);
+            if (resolve) {
+              resolveClass(loaded);
+            }
+            return loaded;
           } catch (ClassNotFoundException e) {
           }
         }
 
         try {
-          return super.findClass(name);
+          return super.loadClass(name, resolve);
         } catch (ClassNotFoundException e) {
           // Don't allow server classes to be loaded from the outside.
-          if (isServerClass(name)) {
+          if (WebAppContextWithReload.this.isServerClass(name)) {
             throw e;
           }
         }
@@ -455,7 +467,7 @@
         String resourceName = name.replace('.', '/') + ".class";
         URL found = systemClassLoader.getResource(resourceName);
         if (found == null) {
-          return null;
+          throw new ClassNotFoundException(name);
         }
 
         // Special-case JDBCUnloader; it should always be loaded in the webapp classloader
@@ -467,17 +479,21 @@
         // Those classes are allowed to be loaded right from the systemClassLoader
         // Note: Jetty classes here are not "server classes", handled above.
         if (allowedFromSystemClassLoader.match(name)) {
-          return systemClassLoader.loadClass(name);
+          Class<?> loaded = systemClassLoader.loadClass(name);
+          if (resolve) {
+            resolveClass(loaded);
+          }
+          return loaded;
         }
 
         // Warn, add containing URL to our own ClassLoader, and retry the call.
         String warnMessage = "Server class '"
-            + name
-            + "' could not be found in the web app, but was found on the system classpath";
+                + name
+                + "' could not be found in the web app, but was found on the system classpath";
         if (!addContainingClassPathEntry(warnMessage, found, resourceName)) {
           throw new ClassNotFoundException(name);
         }
-        return super.findClass(name);
+        return super.loadClass(name, resolve);
       }
 
       private boolean addContainingClassPathEntry(String warnMessage,
@@ -533,7 +549,9 @@
 
     private WebAppContextWithReload(TreeLogger logger, String webApp,
         String contextPath) {
-      super(webApp, contextPath);
+      super(null, contextPath, null, null, null, new ErrorPageErrorHandler(),
+              ServletContextHandler.SESSIONS);
+      this.setWar(webApp);
       this.logger = logger;
 
       // Prevent file locking on Windows; pick up file changes.
@@ -594,9 +612,6 @@
 
     // Allow binding to a port even if it's still in state TIME_WAIT.
     connector.setReuseAddress(true);
-
-    // Linux keeps the port blocked after shutdown if we don't disable this.
-    connector.setSoLingerTime(0);
   }
 
   // default value used if setBaseLogLevel isn't called
@@ -751,7 +766,8 @@
     }
 
     // Create a new web app in the war directory.
-      WebAppContext wac = createWebAppContext(logger, appRootDir);
+    WebAppContext wac = createWebAppContext(logger, appRootDir);
+    wac.setSecurityHandler(new ConstraintSecurityHandler());
 
     RequestLogHandler logHandler = new RequestLogHandler();
     logHandler.setRequestLog(new JettyRequestLogger(logger, getBaseLogLevel()));
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 6b67e7e..b022cdb 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
@@ -265,6 +265,10 @@
     webConnection.setResponse(new URL(
         "http://foo.test/foo/test.Module.nocache.js"), testScript.toString(),
         "application/javascript");
+    webConnection.setResponse(new URL(
+            "http://foo.test/from/nocache/__MODULE_NAME__.nocache.js"),
+            testScript.toString(),
+            "application/javascript");
     webClient.setWebConnection(webConnection);
 
     final List<String> alerts = new ArrayList<String>();
diff --git a/maven/poms/gwt/pom-template.xml b/maven/poms/gwt/pom-template.xml
index 3bd4042..f4bae17 100644
--- a/maven/poms/gwt/pom-template.xml
+++ b/maven/poms/gwt/pom-template.xml
@@ -21,8 +21,8 @@
         </license>
     </licenses>
     <properties>
-      <jetty.version>9.2.14.v20151106</jetty.version>
-      <asm.version>7.1</asm.version>
+      <jetty.version>9.4.44.v20210927</jetty.version>
+      <asm.version>9.2</asm.version>
     </properties>
     <dependencyManagement>
         <dependencies>
@@ -118,7 +118,7 @@
             <dependency>
                 <groupId>net.sourceforge.htmlunit</groupId>
                 <artifactId>htmlunit</artifactId>
-                <version>2.19</version>
+                <version>2.55.0</version>
             </dependency>
             <dependency>
                 <groupId>org.w3c.css</groupId>
diff --git a/user/src/com/google/gwt/dom/client/DOMImplMozilla.java b/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
index c582597..100d7d0 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplMozilla.java
@@ -233,6 +233,18 @@
   private native NativeEvent createKeyEventImpl(Document doc, String type,
       boolean canBubble, boolean cancelable, boolean ctrlKey, boolean altKey,
       boolean shiftKey, boolean metaKey, int keyCode, int charCode) /*-{
+    if (!!window.KeyboardEvent) {
+      return new KeyboardEvent(type, {
+        ctrlKey: ctrlKey,
+        altKey: altKey,
+        shiftKey: shiftKey,
+        metaKey: metaKey,
+        keyCode: keyCode,
+        charCode: charCode,
+        bubbles: canBubble,
+        cancelable: cancelable
+      });
+    }
     var evt = doc.createEvent('KeyboardEvent');
     if (evt.initKeyEvent) {
       // Gecko
diff --git a/user/src/com/google/gwt/junit/RunStyleHtmlUnit.java b/user/src/com/google/gwt/junit/RunStyleHtmlUnit.java
index 133c848..7381542 100644
--- a/user/src/com/google/gwt/junit/RunStyleHtmlUnit.java
+++ b/user/src/com/google/gwt/junit/RunStyleHtmlUnit.java
@@ -15,8 +15,6 @@
  */
 package com.google.gwt.junit;
 
-import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_WINDOW_ONERROR_COLUMN_ERROR_ARGUMENT;
-
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.dev.shell.HostedModePluginObject;
 import com.google.gwt.thirdparty.guava.common.collect.ImmutableSet;
@@ -26,7 +24,6 @@
 import com.gargoylesoftware.htmlunit.BrowserVersion;
 import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
 import com.gargoylesoftware.htmlunit.IncorrectnessListener;
-import com.gargoylesoftware.htmlunit.InteractivePage;
 import com.gargoylesoftware.htmlunit.OnbeforeunloadHandler;
 import com.gargoylesoftware.htmlunit.Page;
 import com.gargoylesoftware.htmlunit.ScriptException;
@@ -116,21 +113,30 @@
       webClient.setJavaScriptErrorListener(new JavaScriptErrorListener() {
 
         @Override
-        public void loadScriptError(InteractivePage htmlPage, URL scriptUrl,
+        public void loadScriptError(HtmlPage htmlPage, URL scriptUrl,
             Exception exception) {
             treeLogger.log(TreeLogger.ERROR,
               "Load Script Error: " + exception, exception);
         }
 
         @Override
-        public void malformedScriptURL(InteractivePage htmlPage, String url,
+        public void warn(String message, String sourceName, int line,
+                         String lineSource, int lineOffset) {
+            treeLogger.log(TreeLogger.WARN, "Script Warning: " + message +
+                    ", sourceName=" + sourceName + ", line=" + line + ", lineSource=" +
+                    lineSource + ", lineOffset=" + lineOffset
+            );
+        }
+
+        @Override
+        public void malformedScriptURL(HtmlPage htmlPage, String url,
             MalformedURLException malformedURLException) {
           treeLogger.log(TreeLogger.ERROR,
               "Malformed Script URL: " + malformedURLException.getLocalizedMessage());
         }
 
         @Override
-        public void scriptException(InteractivePage htmlPage,
+        public void scriptException(HtmlPage htmlPage,
             ScriptException scriptException) {
           treeLogger.log(TreeLogger.DEBUG,
               "Script Exception: " + scriptException.getLocalizedMessage() +
@@ -138,7 +144,7 @@
         }
 
         @Override
-        public void timeoutError(InteractivePage htmlPage, long allowedTime,
+        public void timeoutError(HtmlPage htmlPage, long allowedTime,
             long executionTime) {
           treeLogger.log(TreeLogger.ERROR,
               "Script Timeout Error " + executionTime + " > " + allowedTime);
@@ -188,20 +194,22 @@
   private static class HostedJavaScriptEngine extends JavaScriptEngine {
 
     private static final long serialVersionUID = 3594816610842448691L;
+    private final WebClient webClient;
     private final TreeLogger logger;
 
     public HostedJavaScriptEngine(WebClient webClient, TreeLogger logger) {
       super(webClient);
+      this.webClient = webClient;
       this.logger = logger;
     }
 
     @Override
-    public void initialize(WebWindow webWindow) {
+    public void initialize(WebWindow webWindow, Page page) {
       // Hook in the hosted-mode plugin after initializing the JS engine.
-      super.initialize(webWindow);
+      super.initialize(webWindow, page);
       Window window = (Window) webWindow.getScriptableObject();
       window.defineProperty("__gwt_HostedModePlugin",
-          new HostedModePluginObject(this, logger), ScriptableObject.READONLY);
+          new HostedModePluginObject(this, webClient, logger), ScriptableObject.READONLY);
     }
   }
 
@@ -213,9 +221,11 @@
    */
   private static class WebJavaScriptEngine extends JavaScriptEngine {
     private static final Log LOG = LogFactory.getLog(JavaScriptEngine.class);
+    private final WebClient webClient;
 
     public WebJavaScriptEngine(WebClient webClient) {
       super(webClient);
+      this.webClient = webClient;
     }
 
     @Override
@@ -225,7 +235,7 @@
       // instead of Window's triggerOnError.
 
       // Trigger window.onerror, if it has been set.
-      final InteractivePage page = scriptException.getPage();
+      final HtmlPage page = scriptException.getPage();
       if (triggerOnError && page != null) {
         final WebWindow window = page.getEnclosingWindow();
         if (window != null) {
@@ -240,12 +250,12 @@
         }
       }
       final JavaScriptErrorListener javaScriptErrorListener =
-          getWebClient().getJavaScriptErrorListener();
+              webClient.getJavaScriptErrorListener();
       if (javaScriptErrorListener != null) {
         javaScriptErrorListener.scriptException(page, scriptException);
       }
       // Throw a Java exception if the user wants us to.
-      if (getWebClient().getOptions().isThrowExceptionOnScriptError()) {
+      if (webClient.getOptions().isThrowExceptionOnScriptError()) {
         throw scriptException;
       }
       // Log the error; ScriptException instances provide good debug info.
@@ -262,19 +272,15 @@
         final String url = e.getPage().getUrl().toExternalForm();
         final int line = e.getFailingLineNumber();
 
-        Object[] args;
-        if (w.getBrowserVersion().hasFeature(JS_WINDOW_ONERROR_COLUMN_ERROR_ARGUMENT)) {
-          final int column = e.getFailingColumnNumber();
+        final int column = e.getFailingColumnNumber();
 
-          Object jsError = null;
-          if (e.getCause() instanceof JavaScriptException) {
-            jsError = ((JavaScriptException) e.getCause()).getValue();
-          }
-
-          args = new Object[] {msg, url, Integer.valueOf(line), Integer.valueOf(column), jsError};
-        } else {
-          args = new Object[] {msg, url, Integer.valueOf(line)};
+        Object jsError = null;
+        if (e.getCause() instanceof JavaScriptException) {
+          jsError = ((JavaScriptException) e.getCause()).getValue();
         }
+
+        Object[] args = new Object[]{msg, url, line, column, jsError};
+
         f.call(Context.getCurrentContext(), w, w, args);
       }
     }
@@ -286,9 +292,9 @@
   static {
     // “Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0″
     addBrowser(BrowserVersion.EDGE, "safari");
-    addBrowser(BrowserVersion.FIREFOX_38, "gecko1_8");
+    addBrowser(BrowserVersion.FIREFOX, "gecko1_8");
     addBrowser(BrowserVersion.CHROME, "safari");
-    addBrowser(BrowserVersion.INTERNET_EXPLORER_11, "gecko1_8");
+    addBrowser(BrowserVersion.INTERNET_EXPLORER, "gecko1_8");
   }
 
   private static void addBrowser(BrowserVersion browser, String userAgent) {
@@ -324,8 +330,8 @@
   @Override
   public int initialize(String args) {
     if (args == null || args.length() == 0) {
-      // If no browsers specified, default to Firefox 38.
-      args = "FF38";
+      // If no browsers specified, default to Firefox.
+      args = "FF";
     }
     Set<BrowserVersion> browserSet = new HashSet<BrowserVersion>();
     Set<String> userAgentSet = new HashSet<String>();
diff --git a/user/test/com/google/gwt/core/client/impl/StackTraceNativeTest.java b/user/test/com/google/gwt/core/client/impl/StackTraceNativeTest.java
index 576eb0d..1a6cd35 100644
--- a/user/test/com/google/gwt/core/client/impl/StackTraceNativeTest.java
+++ b/user/test/com/google/gwt/core/client/impl/StackTraceNativeTest.java
@@ -105,9 +105,6 @@
         ? limited_wrap : (thrown != TYPE_ERROR ? limited_fillInStackTrace : full);
   }
 
-  // TODO(goktug): new Error().stack is broken for htmlunit:
-  // https://sourceforge.net/p/htmlunit/bugs/1606/
-  @DoNotRunWith(Platform.HtmlUnitBug)
   public void testCollectorType() {
     if (isSafari5()) {
       assertTrue(isLegacyCollector());
diff --git a/user/test/com/google/gwt/dom/client/NodeTest.java b/user/test/com/google/gwt/dom/client/NodeTest.java
index 54df1a9..5e70c65 100644
--- a/user/test/com/google/gwt/dom/client/NodeTest.java
+++ b/user/test/com/google/gwt/dom/client/NodeTest.java
@@ -16,8 +16,6 @@
 package com.google.gwt.dom.client;
 
 import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.junit.DoNotRunWith;
-import com.google.gwt.junit.Platform;
 import com.google.gwt.junit.client.GWTTestCase;
 
 import java.util.Locale;
@@ -266,7 +264,6 @@
   /**
    * ownerDocument.
    */
-  @DoNotRunWith(Platform.HtmlUnitBug)
   public void testOwnerDocument() {
     Document doc = Document.get();
     BodyElement body = doc.getBody();
diff --git a/user/test/com/google/gwt/emultest/java/lang/SystemTest.java b/user/test/com/google/gwt/emultest/java/lang/SystemTest.java
index 33f7379..951b412 100644
--- a/user/test/com/google/gwt/emultest/java/lang/SystemTest.java
+++ b/user/test/com/google/gwt/emultest/java/lang/SystemTest.java
@@ -15,9 +15,6 @@
  */
 package com.google.gwt.emultest.java.lang;
 
-import static com.google.gwt.junit.Platform.HtmlUnitBug;
-
-import com.google.gwt.junit.DoNotRunWith;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.testing.TestUtils;
 
@@ -328,7 +325,6 @@
     assertEquals("default", System.getProperty("otherNonExistent", someConf));
   }
 
-  @DoNotRunWith({HtmlUnitBug})
   public void testNanoTime() {
     assertTrue(System.nanoTime() > 0);
   }
diff --git a/user/test/com/google/gwt/jsonp/client/JsonpRequestTest.java b/user/test/com/google/gwt/jsonp/client/JsonpRequestTest.java
index 7817583..a3d59da 100644
--- a/user/test/com/google/gwt/jsonp/client/JsonpRequestTest.java
+++ b/user/test/com/google/gwt/jsonp/client/JsonpRequestTest.java
@@ -223,19 +223,13 @@
         new AssertFailureCallback<String>("ERROR"));
   }
 
-  /**
-   * Hangs indefinitely in devmode with HtmlUnit.
-   * <p>
-   * Call occurs through postponedActions in HtmlUnit that execute
-   * synchronously. Should be async. Need to file HtmlUnitBug.
-   */
-  @DoNotRunWith(Platform.HtmlUnitBug)
   public void testIds() {
     delayTestFinish(RESPONSE_DELAY);
+    Counter counter = new Counter(2);
     JsonpRequest<String> reqA = jsonp.requestString(echo("'A'"),
-        new AssertSuccessCallback<String>("A"));
+        new AssertSuccessCallback<String>("A", counter));
     JsonpRequest<String> reqB = jsonp.requestString(echo("'B'"),
-        new AssertSuccessCallback<String>("B"));
+        new AssertSuccessCallback<String>("B", counter));
     // WARNING: knows the current structure of IDs
     int idA = Integer.parseInt(reqA.getCallbackId().substring(1));
     int idB = Integer.parseInt(reqB.getCallbackId().substring(1));
diff --git a/user/test/com/google/gwt/junit/client/CspTest.java b/user/test/com/google/gwt/junit/client/CspTest.java
index f078ee1..d0db547 100644
--- a/user/test/com/google/gwt/junit/client/CspTest.java
+++ b/user/test/com/google/gwt/junit/client/CspTest.java
@@ -31,7 +31,7 @@
     return "com.google.gwt.junit.JUnitTest";
   }
 
-  @DoNotRunWith(Platform.HtmlUnitLayout)
+  @DoNotRunWith(Platform.HtmlUnitBug)
   public void testCsp() {
     initClickDidFire();
 
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
index ddab38b..9ea8b15 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
+++ b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
@@ -20,8 +20,6 @@
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.ParagraphElement;
 import com.google.gwt.dom.client.SpanElement;
-import com.google.gwt.junit.DoNotRunWith;
-import com.google.gwt.junit.Platform;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.resources.client.ClientBundle;
 import com.google.gwt.resources.client.CssResource.NotStrict;
@@ -554,12 +552,6 @@
     assertEquals("funny characters \\ \" ' ' & < > > { }", t);
   }
 
-  /**
-   * Fails in all modes due to an HtmlUnit bug: offsetWidth always returns 1256.
-   * TODO(t.broyer): file a new HtmlUnit bug.
-   * Similar to http://sourceforge.net/p/htmlunit/bugs/1447/
-   */
-  @DoNotRunWith(Platform.HtmlUnitBug)
   public void testCustomImageClass() {
     ImageResource resource = widgetUi.prettyImage;
     Image widget = widgetUi.fooImage;
@@ -569,12 +561,6 @@
     assertEquals(resource.getLeft(), widget.getOriginLeft());
   }
 
-  /**
-   * Fails in all modes due to an HtmlUnit bug: offsetWidth always returns 1256.
-   * TODO(t.broyer): file a new HtmlUnit bug.
-   * Similar to http://sourceforge.net/p/htmlunit/bugs/1447/
-   */
-  @DoNotRunWith(Platform.HtmlUnitBug)
   public void testImageResourceInImageWidget() {
     ImageResource resource = widgetUi.prettyImage;
     Image widget = widgetUi.babyWidget;
diff --git a/user/test/com/google/gwt/user/client/ui/CreateEventTest.java b/user/test/com/google/gwt/user/client/ui/CreateEventTest.java
index 262223a..387feef 100644
--- a/user/test/com/google/gwt/user/client/ui/CreateEventTest.java
+++ b/user/test/com/google/gwt/user/client/ui/CreateEventTest.java
@@ -467,14 +467,6 @@
     assertTrue("Expected parent to receive event", listener.parentReceived);
   }
 
-  /**
-   * Tests createErrorEvent().
-   *
-   * Failed in all modes due to HtmlUnit bug:
-   * https://sourceforge.net/tracker/?func
-   * =detail&aid=2888342&group_id=47038&atid=448266
-   */
-  @DoNotRunWith({Platform.HtmlUnitBug})
   public void testTriggerErrorEvent() {
     ImgEventListener listener = new ImgEventListener("error");
     Event.setEventListener(parent, listener);
@@ -686,12 +678,6 @@
     listener.cancel();
   }
 
-  /**
-   * Tests createKeyPressEvent().
-   *
-   * Failed in all modes due to HtmlUnit bug:
-   */
-  @DoNotRunWith({Platform.HtmlUnitBug})
   public void testTriggerScrollEvent() {
     NonBubbleAssertingEventListener listener = new NonBubbleAssertingEventListener(
         "scroll") {
diff --git a/user/test/com/google/gwt/user/client/ui/HistoryTest.java b/user/test/com/google/gwt/user/client/ui/HistoryTest.java
index e3ea748..5df0b7f 100644
--- a/user/test/com/google/gwt/user/client/ui/HistoryTest.java
+++ b/user/test/com/google/gwt/user/client/ui/HistoryTest.java
@@ -414,12 +414,6 @@
     timer.schedule(200);
   }
 
-  /*
-   * HtmlUnit reports:
-   *   expected=abc;,/?:@&=+$-_.!~*()ABC123foo
-   *   actual  =abc;,/?:@&=%20$-_.!~*()ABC123foo
-   */
-  @DoNotRunWith(Platform.HtmlUnitBug)
   public void testTokenNonescaping() {
     final String shouldNotChange = "abc;,/?:@&=+$-_.!~*()ABC123foo";
 
diff --git a/user/test/com/google/gwt/user/client/ui/MenuBarTest.java b/user/test/com/google/gwt/user/client/ui/MenuBarTest.java
index 27bf0c8..862b6c9 100644
--- a/user/test/com/google/gwt/user/client/ui/MenuBarTest.java
+++ b/user/test/com/google/gwt/user/client/ui/MenuBarTest.java
@@ -21,8 +21,6 @@
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.NativeEvent;
 import com.google.gwt.event.dom.client.KeyCodes;
-import com.google.gwt.junit.DoNotRunWith;
-import com.google.gwt.junit.Platform;
 import com.google.gwt.safehtml.shared.SafeHtmlUtils;
 import com.google.gwt.user.client.Command;
 
@@ -216,7 +214,6 @@
     assertNull(l2.getPopup());
   }
 
-  @DoNotRunWith({Platform.HtmlUnitBug})
   public void testBlur() {
     // Create a menu bar with children.
     final MenuBar menu = new MenuBar();
@@ -234,7 +231,6 @@
     assertNull(menu.getSelectedItem());
   }
 
-  @DoNotRunWith({Platform.HtmlUnitBug})
   public void testSetFocusOnHoverEnabled() {
     delayTestFinish(1000);
     TextBox focusOwner = new TextBox();
diff --git a/user/test/com/google/gwt/user/client/ui/PopupTest.java b/user/test/com/google/gwt/user/client/ui/PopupTest.java
index d0738a4..16984bc 100644
--- a/user/test/com/google/gwt/user/client/ui/PopupTest.java
+++ b/user/test/com/google/gwt/user/client/ui/PopupTest.java
@@ -20,6 +20,8 @@
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.event.logical.shared.CloseEvent;
 import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.junit.DoNotRunWith;
+import com.google.gwt.junit.Platform;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.user.client.History;
 import com.google.gwt.user.client.Timer;
@@ -145,7 +147,11 @@
   /**
    * Tests that a large PopupPanel is not positioned off the top or left edges
    * of the browser window, making part of the panel unreachable.
+   *
+   * <p>This test is broken in HtmlUnit 2.55.0, see
+   * https://github.com/HtmlUnit/htmlunit/issues/382.</p>
    */
+  @DoNotRunWith(Platform.HtmlUnitLayout)
   public void testCenterLargePopup() {
     PopupPanel popup = new PopupPanel();
     popup.setHeight("4096px");
@@ -318,6 +324,11 @@
     }
   }
 
+  /**
+   * This test is broken in HtmlUnit 2.55.0, see
+   * https://github.com/HtmlUnit/htmlunit/issues/382.
+   */
+  @DoNotRunWith(Platform.HtmlUnitLayout)
   public void testPopup() {
     // Get rid of window margins so we can test absolute position.
     Window.setMargin("0px");
diff --git a/user/test/com/google/gwt/user/client/ui/impl/ClippedImagePrototypeTest.java b/user/test/com/google/gwt/user/client/ui/impl/ClippedImagePrototypeTest.java
index 4d4d1d4..27eb267 100644
--- a/user/test/com/google/gwt/user/client/ui/impl/ClippedImagePrototypeTest.java
+++ b/user/test/com/google/gwt/user/client/ui/impl/ClippedImagePrototypeTest.java
@@ -19,8 +19,6 @@
 import com.google.gwt.event.dom.client.ErrorHandler;
 import com.google.gwt.event.dom.client.LoadEvent;
 import com.google.gwt.event.dom.client.LoadHandler;
-import com.google.gwt.junit.DoNotRunWith;
-import com.google.gwt.junit.Platform;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.safehtml.shared.UriUtils;
 import com.google.gwt.user.client.Timer;
@@ -55,15 +53,6 @@
     return "com.google.gwt.user.UserTest";
   }
 
-  /**
-   * Tests that a clipped image can be transformed to match a given prototype.
-   * Also checks to make sure that a load event is fired on when
-   * {@link com.google.gwt.user.client.ui.impl.ClippedImagePrototype#applyTo(com.google.gwt.user.client.ui.Image)}
-   * is called.
-   *
-   * TODO(jlabanca): Enable this test when issue 863 is fixed
-   */
-  @DoNotRunWith({Platform.HtmlUnitBug})
   public void disabledTestApplyToClippedImage() {
     final Image image = new Image("counting-backwards.png", 12, 13, 8, 8);
 
diff --git a/user/test/com/google/gwt/xml/client/XMLTest.java b/user/test/com/google/gwt/xml/client/XMLTest.java
index 6a1396b..f349dd3 100644
--- a/user/test/com/google/gwt/xml/client/XMLTest.java
+++ b/user/test/com/google/gwt/xml/client/XMLTest.java
@@ -149,7 +149,6 @@
     assertEquals(de.getAttributeNode("unset"), null);
   }
 
-  @DoNotRunWith({Platform.HtmlUnitBug})
   public void testCreate() {
     Document d = XMLParser.createDocument();
     CDATASection createCDATA = d.createCDATASection("sampl<<< >>e data");
diff --git a/user/test/com/google/web/bindery/requestfactory/server/RequestFactoryTestServer.java b/user/test/com/google/web/bindery/requestfactory/server/RequestFactoryTestServer.java
index 0c9e3f2..a583d55 100644
--- a/user/test/com/google/web/bindery/requestfactory/server/RequestFactoryTestServer.java
+++ b/user/test/com/google/web/bindery/requestfactory/server/RequestFactoryTestServer.java
@@ -42,7 +42,7 @@
     handler.addFilter(GzipFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
 
     SessionHandler sessionHandler = new SessionHandler();
-    sessionHandler.getSessionManager().setMaxInactiveInterval(5);
+    sessionHandler.setMaxInactiveInterval(5);
     handler.setSessionHandler(sessionHandler);
     server.setHandler(handler);