summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2012-11-15 09:40:42 +0200
committerVaadin Code Review <review@vaadin.com>2012-11-19 09:58:01 +0000
commit008dd4cf731522543c80ea81c0d5dca35f85c90b (patch)
tree8275ae680a4331412fc770891c80f223dcc88439 /client
parent977c8b01c042f2ffec36e3cb5c7ad517b738d06e (diff)
downloadvaadin-framework-008dd4cf731522543c80ea81c0d5dca35f85c90b.tar.gz
vaadin-framework-008dd4cf731522543c80ea81c0d5dca35f85c90b.zip
Handle canceled or ignored XHR requests after beforeunload (#8891)
* Not automatically testable as it depends exact timings Change-Id: I53bccce675520ab2c7bb007766546b4cd3fe6e53
Diffstat (limited to 'client')
-rw-r--r--client/src/com/vaadin/client/ApplicationConnection.java88
1 files changed, 84 insertions, 4 deletions
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java
index c8206f96f6..23906f0e02 100644
--- a/client/src/com/vaadin/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/client/ApplicationConnection.java
@@ -56,6 +56,9 @@ import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.Window.ClosingEvent;
+import com.google.gwt.user.client.Window.ClosingHandler;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConfiguration.ErrorMessage;
@@ -170,6 +173,23 @@ public class ApplicationConnection {
private boolean hasActiveRequest = false;
+ /**
+ * Some browsers cancel pending XHR requests when a request that might
+ * navigate away from the page starts (indicated by a beforeunload event).
+ * In that case, we should just send the request again without displaying
+ * any error.
+ */
+ private boolean retryCanceledActiveRequest = false;
+
+ /**
+ * Webkit will ignore outgoing requests while waiting for a response to a
+ * navigation event (indicated by a beforeunload event). When this happens,
+ * we should keep trying to send the request every now and then until there
+ * is a response or until it throws an exception saying that it is already
+ * being sent.
+ */
+ private boolean webkitMaybeIgnoringRequests = false;
+
protected boolean cssLoaded = false;
/** Parameters for this application connection loaded from the web-page */
@@ -378,6 +398,21 @@ public class ApplicationConnection {
showLoadingIndicator();
scheduleHeartbeat();
+
+ Window.addWindowClosingHandler(new ClosingHandler() {
+ @Override
+ public void onWindowClosing(ClosingEvent event) {
+ /*
+ * Set some flags to avoid potential problems with XHR requests,
+ * see javadocs of the flags for details
+ */
+ if (hasActiveRequest()) {
+ retryCanceledActiveRequest = true;
+ }
+
+ webkitMaybeIgnoringRequests = true;
+ }
+ });
}
/**
@@ -668,9 +703,21 @@ public class ApplicationConnection {
switch (statusCode) {
case 0:
- handleCommunicationError(
- "Invalid status code 0 (server down?)",
- statusCode);
+ if (retryCanceledActiveRequest) {
+ /*
+ * Request was most likely canceled because the
+ * browser is maybe navigating away from the page.
+ * Just send the request again without displaying
+ * any error in case the navigation isn't carried
+ * through.
+ */
+ retryCanceledActiveRequest = false;
+ doUidlRequest(uri, payload, synchronous);
+ } else {
+ handleCommunicationError(
+ "Invalid status code 0 (server down?)",
+ statusCode);
+ }
return;
case 401:
@@ -814,9 +861,38 @@ public class ApplicationConnection {
rb.setRequestData(payload);
rb.setCallback(requestCallback);
- rb.send();
+ final Request request = rb.send();
+ if (webkitMaybeIgnoringRequests && BrowserInfo.get().isWebkit()) {
+ final int retryTimeout = 250;
+ new Timer() {
+ @Override
+ public void run() {
+ // Use native js to access private field in Request
+ if (resendRequest(request) && webkitMaybeIgnoringRequests) {
+ // Schedule retry if still needed
+ schedule(retryTimeout);
+ }
+ }
+ }.schedule(retryTimeout);
+ }
}
+ private static native boolean resendRequest(Request request)
+ /*-{
+ var xhr = request.@com.google.gwt.http.client.Request::xmlHttpRequest
+ if (xhr.readyState != 1) {
+ // Progressed to some other readyState -> no longer blocked
+ return false;
+ }
+ try {
+ xhr.send();
+ return true;
+ } catch (e) {
+ // send throws exception if it is running for real
+ return false;
+ }
+ }-*/;
+
int cssWaits = 0;
/**
@@ -977,6 +1053,10 @@ public class ApplicationConnection {
// the call. Active requests used to be tracked with an integer counter,
// so setting it after used to work but not with the #8505 changes.
hasActiveRequest = false;
+
+ retryCanceledActiveRequest = false;
+ webkitMaybeIgnoringRequests = false;
+
if (applicationRunning) {
checkForPendingVariableBursts();
runPostRequestHooks(configuration.getRootPanelId());