diff options
author | Leif Åstrand <leif@vaadin.com> | 2012-11-15 09:40:42 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2012-11-19 09:58:01 +0000 |
commit | 008dd4cf731522543c80ea81c0d5dca35f85c90b (patch) | |
tree | 8275ae680a4331412fc770891c80f223dcc88439 /client | |
parent | 977c8b01c042f2ffec36e3cb5c7ad517b738d06e (diff) | |
download | vaadin-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.java | 88 |
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()); |