diff --git a/.github/workflows/full-check.yml b/.github/workflows/full-check.yml
index 2e7a2644bc7..27bf3b861f3 100644
--- a/.github/workflows/full-check.yml
+++ b/.github/workflows/full-check.yml
@@ -31,7 +31,8 @@ jobs:
- name: Checkout GWT tools into a sibling directory
uses: actions/checkout@v4
with:
- repository: 'gwtproject/tools'
+ repository: 'zbynek/tools'
+ ref: 'htmlunit-4'
path: 'tools'
- name: Set up JDK ${{ matrix.java-version }}
# GWT requires Java 11+ to build
diff --git a/.github/workflows/quick-check.yml b/.github/workflows/quick-check.yml
index 09977bd4d68..fcdd80d0378 100644
--- a/.github/workflows/quick-check.yml
+++ b/.github/workflows/quick-check.yml
@@ -19,7 +19,8 @@ jobs:
- name: Checkout GWT tools into a sibling directory
uses: actions/checkout@v4
with:
- repository: 'gwtproject/tools'
+ repository: 'zbynek/tools'
+ ref: 'htmlunit-4'
path: 'tools'
- name: Set up JDK ${{ matrix.java-version }}
# GWT presently requires Java 11+ to build
diff --git a/dev/build.xml b/dev/build.xml
index 28846480959..bf5c0354c8e 100755
--- a/dev/build.xml
+++ b/dev/build.xml
@@ -85,19 +85,20 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -155,20 +156,20 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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 98d5051d8f9..c9aeaef5853 100644
--- a/dev/core/src/com/google/gwt/dev/shell/HostedModePluginObject.java
+++ b/dev/core/src/com/google/gwt/dev/shell/HostedModePluginObject.java
@@ -17,17 +17,15 @@
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 net.sourceforge.htmlunit.corejs.javascript.Context;
-import net.sourceforge.htmlunit.corejs.javascript.Function;
-import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
-import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;
+import org.htmlunit.WebClient;
+import org.htmlunit.corejs.javascript.Context;
+import org.htmlunit.corejs.javascript.Function;
+import org.htmlunit.corejs.javascript.Scriptable;
+import org.htmlunit.corejs.javascript.ScriptableObject;
+import org.htmlunit.javascript.JavaScriptEngine;
+import org.htmlunit.javascript.host.Window;
import java.io.IOException;
-import java.util.Collections;
/**
* HTMLUnit object that represents the hosted-mode plugin.
@@ -187,15 +185,6 @@ public boolean connect(String url, String sessionKey, String address,
return false;
}
// 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, webClient);
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 75abb3aea3c..8b93757bcc2 100644
--- a/dev/core/src/com/google/gwt/dev/shell/HtmlUnitSessionHandler.java
+++ b/dev/core/src/com/google/gwt/dev/shell/HtmlUnitSessionHandler.java
@@ -23,23 +23,21 @@
import com.google.gwt.dev.shell.BrowserChannelClient.SessionHandlerClient;
import com.google.gwt.dev.util.log.PrintWriterTreeLogger;
-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;
-import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable;
-import com.gargoylesoftware.htmlunit.javascript.SimpleScriptableProxy;
-import com.gargoylesoftware.htmlunit.javascript.host.Window;
-
-import net.sourceforge.htmlunit.corejs.javascript.ConsString;
-import net.sourceforge.htmlunit.corejs.javascript.Context;
-import net.sourceforge.htmlunit.corejs.javascript.Function;
-import net.sourceforge.htmlunit.corejs.javascript.JavaScriptException;
-import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
-import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;
-import net.sourceforge.htmlunit.corejs.javascript.Undefined;
+import org.htmlunit.ScriptException;
+import org.htmlunit.ScriptResult;
+import org.htmlunit.WebClient;
+import org.htmlunit.WebWindow;
+import org.htmlunit.corejs.javascript.ConsString;
+import org.htmlunit.corejs.javascript.Context;
+import org.htmlunit.corejs.javascript.Function;
+import org.htmlunit.corejs.javascript.JavaScriptException;
+import org.htmlunit.corejs.javascript.Scriptable;
+import org.htmlunit.corejs.javascript.ScriptableObject;
+import org.htmlunit.corejs.javascript.Undefined;
+import org.htmlunit.html.HtmlPage;
+import org.htmlunit.javascript.HtmlUnitScriptableProxy;
+import org.htmlunit.javascript.JavaScriptEngine;
+import org.htmlunit.javascript.host.Window;
import java.util.Arrays;
import java.util.HashMap;
@@ -185,13 +183,14 @@ public ExceptionOrReturnValue invoke(BrowserChannelClient channel, Value thisObj
jsThis = window;
} else {
Object obj = makeJsvalFromValue(jsContext, thisObj);
+ if (obj instanceof HtmlUnitScriptableProxy) {
+ obj = ((HtmlUnitScriptableProxy>) obj).getDelegee();
+ }
if (obj instanceof ScriptableObject) {
jsThis = (ScriptableObject) obj;
- } else if (obj instanceof SimpleScriptableProxy>) {
- jsThis = ((SimpleScriptableProxy) obj).getDelegee();
} else {
logger.log(TreeLogger.ERROR, "Unable to convert " + obj + " to either "
- + " ScriptableObject or SimpleScriptableProxy");
+ + " ScriptableObject or HtmlUnitScriptableProxy");
return new ExceptionOrReturnValue(true, new Value(null));
}
}
@@ -289,14 +288,14 @@ public Value makeValueFromJsval(Context jsContext, Object value) {
return returnVal;
}
if (value instanceof Scriptable) {
- if (value instanceof SimpleScriptableProxy) {
+ if (value instanceof HtmlUnitScriptableProxy) {
// 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();
+ value = ((HtmlUnitScriptableProxy>) value).getDelegee();
}
if (value instanceof ScriptableObject) {
/*
diff --git a/dev/core/src/com/google/gwt/dev/shell/JavaObject.java b/dev/core/src/com/google/gwt/dev/shell/JavaObject.java
index 19a31f96042..86a91fcfa15 100644
--- a/dev/core/src/com/google/gwt/dev/shell/JavaObject.java
+++ b/dev/core/src/com/google/gwt/dev/shell/JavaObject.java
@@ -21,11 +21,11 @@
import com.google.gwt.dev.shell.BrowserChannel.SessionHandler.ExceptionOrReturnValue;
import com.google.gwt.dev.shell.BrowserChannel.Value;
-import net.sourceforge.htmlunit.corejs.javascript.Context;
-import net.sourceforge.htmlunit.corejs.javascript.Function;
-import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
-import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;
-import net.sourceforge.htmlunit.corejs.javascript.Undefined;
+import org.htmlunit.corejs.javascript.Context;
+import org.htmlunit.corejs.javascript.Function;
+import org.htmlunit.corejs.javascript.Scriptable;
+import org.htmlunit.corejs.javascript.ScriptableObject;
+import org.htmlunit.corejs.javascript.Undefined;
import java.io.IOException;
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 b1b1e513cab..0bbc97169e4 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
@@ -18,14 +18,14 @@
import com.google.gwt.core.ext.linker.LinkerUtils;
-import com.gargoylesoftware.htmlunit.AlertHandler;
-import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
-import com.gargoylesoftware.htmlunit.MockWebConnection;
-import com.gargoylesoftware.htmlunit.Page;
-import com.gargoylesoftware.htmlunit.WebClient;
-
import junit.framework.TestCase;
+import org.htmlunit.AlertHandler;
+import org.htmlunit.FailingHttpStatusCodeException;
+import org.htmlunit.MockWebConnection;
+import org.htmlunit.Page;
+import org.htmlunit.WebClient;
+
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
diff --git a/maven/poms/gwt/gwt-dev/pom-template.xml b/maven/poms/gwt/gwt-dev/pom-template.xml
index c8f34193507..70d0c0655ff 100644
--- a/maven/poms/gwt/gwt-dev/pom-template.xml
+++ b/maven/poms/gwt/gwt-dev/pom-template.xml
@@ -95,7 +95,7 @@
- net.sourceforge.htmlunit
+ org.htmlunit
htmlunit
diff --git a/maven/poms/gwt/pom-template.xml b/maven/poms/gwt/pom-template.xml
index b165744e3e9..0e6d70be8d7 100644
--- a/maven/poms/gwt/pom-template.xml
+++ b/maven/poms/gwt/pom-template.xml
@@ -141,9 +141,9 @@
63.1
- net.sourceforge.htmlunit
+ org.htmlunit
htmlunit
- 2.55.0
+ 4.11.1
org.w3c.css
diff --git a/user/src/com/google/gwt/junit/RunStyleHtmlUnit.java b/user/src/com/google/gwt/junit/RunStyleHtmlUnit.java
index 73815427f5b..1a09f21233f 100644
--- a/user/src/com/google/gwt/junit/RunStyleHtmlUnit.java
+++ b/user/src/com/google/gwt/junit/RunStyleHtmlUnit.java
@@ -20,30 +20,26 @@
import com.google.gwt.thirdparty.guava.common.collect.ImmutableSet;
import com.google.gwt.thirdparty.guava.common.collect.Maps;
-import com.gargoylesoftware.htmlunit.AlertHandler;
-import com.gargoylesoftware.htmlunit.BrowserVersion;
-import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
-import com.gargoylesoftware.htmlunit.IncorrectnessListener;
-import com.gargoylesoftware.htmlunit.OnbeforeunloadHandler;
-import com.gargoylesoftware.htmlunit.Page;
-import com.gargoylesoftware.htmlunit.ScriptException;
-import com.gargoylesoftware.htmlunit.WebClient;
-import com.gargoylesoftware.htmlunit.WebWindow;
-import com.gargoylesoftware.htmlunit.html.HtmlPage;
-import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine;
-import com.gargoylesoftware.htmlunit.javascript.JavaScriptErrorListener;
-import com.gargoylesoftware.htmlunit.javascript.host.Window;
-import com.gargoylesoftware.htmlunit.util.WebClientUtils;
-
-import net.sourceforge.htmlunit.corejs.javascript.Context;
-import net.sourceforge.htmlunit.corejs.javascript.Function;
-import net.sourceforge.htmlunit.corejs.javascript.JavaScriptException;
-import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import org.htmlunit.AlertHandler;
+import org.htmlunit.BrowserVersion;
+import org.htmlunit.FailingHttpStatusCodeException;
+import org.htmlunit.IncorrectnessListener;
+import org.htmlunit.OnbeforeunloadHandler;
+import org.htmlunit.Page;
+import org.htmlunit.ScriptException;
+import org.htmlunit.WebClient;
+import org.htmlunit.WebWindow;
+import org.htmlunit.corejs.javascript.Context;
+import org.htmlunit.corejs.javascript.ScriptableObject;
+import org.htmlunit.html.HtmlPage;
+import org.htmlunit.javascript.HtmlUnitContextFactory;
+import org.htmlunit.javascript.JavaScriptEngine;
+import org.htmlunit.javascript.JavaScriptErrorListener;
+import org.htmlunit.javascript.host.Window;
+import org.htmlunit.util.WebClientUtils;
import java.io.IOException;
+import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
@@ -52,6 +48,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TimeZone;
/**
* Launches a web-mode test via HTMLUnit.
@@ -105,6 +102,7 @@ public void run() {
webClient.setAlertHandler(this);
webClient.setIncorrectnessListener(this);
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
+ webClient.getOptions().setFetchPolyfillEnabled(true);
// To receive exceptions from js side in the development mode, we need set this to 'true'.
// However, as htmlunit dies after throwing the exception, we still want it to be 'false'
// for web mode.
@@ -138,7 +136,7 @@ public void malformedScriptURL(HtmlPage htmlPage, String url,
@Override
public void scriptException(HtmlPage htmlPage,
ScriptException scriptException) {
- treeLogger.log(TreeLogger.DEBUG,
+ treeLogger.log(TreeLogger.ERROR,
"Script Exception: " + scriptException.getLocalizedMessage() +
", line " + scriptException.getFailingLine());
}
@@ -177,7 +175,7 @@ protected void setupWebClient(WebClient webClient) {
treeLogger);
webClient.setJavaScriptEngine(hostedEngine);
} else {
- JavaScriptEngine webEngine = new WebJavaScriptEngine(webClient);
+ JavaScriptEngine webEngine = new JavaScriptEngine(webClient);
webClient.setJavaScriptEngine(webEngine);
}
if (System.getProperty("gwt.htmlunit.debug") != null) {
@@ -196,108 +194,57 @@ private static class HostedJavaScriptEngine extends JavaScriptEngine {
private static final long serialVersionUID = 3594816610842448691L;
private final WebClient webClient;
private final TreeLogger logger;
+ private final HtmlUnitContextFactory htmlUnitContextFactory;
- public HostedJavaScriptEngine(WebClient webClient, TreeLogger logger) {
+ HostedJavaScriptEngine(WebClient webClient, TreeLogger logger) {
super(webClient);
this.webClient = webClient;
this.logger = logger;
+ this.htmlUnitContextFactory = new HtmlUnitContextFactory(webClient) {
+ protected Context makeContext() {
+ Context ctx = super.makeContext();
+ try {
+ Field hasShutter = Context.class.getDeclaredField("hasClassShutter");
+ hasShutter.setAccessible(true);
+ hasShutter.setBoolean(ctx, false);
+ } catch (IllegalAccessException | NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
+ ctx.setClassShutter(any -> true);
+ return ctx;
+ }
+ };
+ }
+
+ @Override
+ public HtmlUnitContextFactory getContextFactory() {
+ return htmlUnitContextFactory;
}
@Override
public void initialize(WebWindow webWindow, Page page) {
// Hook in the hosted-mode plugin after initializing the JS engine.
super.initialize(webWindow, page);
- Window window = (Window) webWindow.getScriptableObject();
+ Window window = webWindow.getScriptableObject();
window.defineProperty("__gwt_HostedModePlugin",
new HostedModePluginObject(this, webClient, logger), ScriptableObject.READONLY);
}
}
- /**
- * JavaScriptEngine subclass that fixes a bug when calling {@code window.onerror}.
- * Make sure to remove when updating HtmlUnit.
- *
- * @see HtmlUnit bug #1924
- */
- 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
- protected void handleJavaScriptException(ScriptException scriptException,
- boolean triggerOnError) {
- // XXX(tbroyer): copied from JavaScriptEngine to call below triggerOnError
- // instead of Window's triggerOnError.
-
- // Trigger window.onerror, if it has been set.
- final HtmlPage page = scriptException.getPage();
- if (triggerOnError && page != null) {
- final WebWindow window = page.getEnclosingWindow();
- if (window != null) {
- final Window w = (Window) window.getScriptableObject();
- if (w != null) {
- try {
- triggerOnError(w, scriptException);
- } catch (final Exception e) {
- handleJavaScriptException(new ScriptException(page, e, null), false);
- }
- }
- }
- }
- final JavaScriptErrorListener javaScriptErrorListener =
- webClient.getJavaScriptErrorListener();
- if (javaScriptErrorListener != null) {
- javaScriptErrorListener.scriptException(page, scriptException);
- }
- // Throw a Java exception if the user wants us to.
- if (webClient.getOptions().isThrowExceptionOnScriptError()) {
- throw scriptException;
- }
- // Log the error; ScriptException instances provide good debug info.
- LOG.info("Caught script exception", scriptException);
- }
-
- private void triggerOnError(Window w, ScriptException e) {
- // XXX(tbroyer): copied from HtmlUnit's javascript.host.Window
- // with fix unwrapping the JS exception before passing it back to JS.
- final Object o = w.getOnerror();
- if (o instanceof Function) {
- final Function f = (Function) o;
- final String msg = e.getMessage();
- final String url = e.getPage().getUrl().toExternalForm();
- final int line = e.getFailingLineNumber();
-
- final int column = e.getFailingColumnNumber();
-
- 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);
- }
- }
- }
-
private static final Map BROWSER_MAP = Maps.newHashMap();
private static final Map USER_AGENT_MAP = Maps.newHashMap();
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″
+ // “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, "gecko1_8");
addBrowser(BrowserVersion.CHROME, "safari");
- addBrowser(BrowserVersion.INTERNET_EXPLORER, "gecko1_8");
}
- private static void addBrowser(BrowserVersion browser, String userAgent) {
+ private static void addBrowser(BrowserVersion baseBrowser, String userAgent) {
+ BrowserVersion browser = new BrowserVersion.BrowserVersionBuilder(baseBrowser)
+ .setSystemTimezone(TimeZone.getDefault()).build();
BROWSER_MAP.put(browser.getNickname(), browser);
USER_AGENT_MAP.put(browser, userAgent);
}
diff --git a/user/test/com/google/gwt/emultest/java/util/DateTest.java b/user/test/com/google/gwt/emultest/java/util/DateTest.java
index 452e1f53f94..ba1507c0df4 100644
--- a/user/test/com/google/gwt/emultest/java/util/DateTest.java
+++ b/user/test/com/google/gwt/emultest/java/util/DateTest.java
@@ -571,15 +571,17 @@ public void testToLocaleString() {
// /////////////////////////////
// Past
// /////////////////////////////
- Date accum1 = create(PAST);
+ Date accum1 = createLocal("1/5/1890");
String a1 = accum1.toLocaleString();
- assertTrue(a1.indexOf("1890") != -1);
+ assertTrue(a1 + " should describe 1/5/1890",
+ a1.contains("1890") || a1.contains("1/5/90"));
// /////////////////////////////
// Future
// /////////////////////////////
- Date accum2 = create(FUTURE);
+ Date accum2 = createLocal("12/30/2030 3:4:5");
String a2 = accum2.toLocaleString();
- assertTrue(a2.indexOf("2030") != -1);
+ assertTrue(a2 + " should describe 12/30/2030",
+ a2.contains("2030") || a2.contains("12/30/30"));
}
}
@@ -895,6 +897,11 @@ Date create(String s) {
}
}
+ Date createLocal(String s) {
+ // aligned with the TZ used in CI
+ return new Date(s + " GMT-8:00");
+ }
+
private String createString(String s) {
if (s.equals(FUTURE)) {
return "12/30/2030 3:4:5 GMT";