Should WebSocket.onclose be triggered by user navigation or refresh? - event-handling

Part 1: Expected behaviour?
I'm seeing some inconsistent browser behaviour between Firefox and Chrome in relation to the onclose handler being called.
It seems that Chrome does not trigger an onclose if it was caused by a user page navigation/refresh. However, Firefox does trigger the onclose.
It seems to me that Firefox may be behaving correctly here:
When the WebSocket connection is closed, possibly cleanly, the user agent must create an event that uses the CloseEvent interface, with the event name close, which does not bubble, is not cancelable, has no default action, whose wasClean attribute is set to true if the connection closed cleanly and false otherwise, whose code attribute is set to the WebSocket connection close code, and whose reason attribute is set to the WebSocket connection close reason; and queue a task to first change the readyState attribute's value to CLOSED (3), and then dispatch the event at the WebSocket object.
Source: http://www.w3.org/TR/2011/WD-websockets-20110419/#closeWebSocket
Even though it can lead to some sneaky code/unexpected behaviour.
Can anybody confirm the expected behaviour?
Part 2: How to implement auto-reconnect?
If you have a library that auto-reconnects for the user how do you know if you should try to reconnect? Do you check the CloseEvent.wasClean property? I'm having to assume that 'clean' means that the close was supposed to happen through either an API call to WebSocket.close() or the server sending a close frame? If a network error causes the close I'm guessing the wasClean would be false?
In the Pusher JavaScript library we assumed (onclose -> waiting -> connecting) that a close should trigger a reconnect unless we are in a closing state - the developer has chosen to close the connection. It would appear that the socket.io client library makes the same assumption.
Based on this the Firefox onclose event caused by user navigation/refresh triggers an unwanted reconnection because neither library check the CloseEvent.wasClean property.
Example and Video
Here's an example that you can use to demonstrate the inconsistency:
http://jsbin.com/awonod/7
Here's a video of me demonstrating the problem:
http://www.screenr.com/vHn8
(it's late, ignore the couple of slip-ups :))
One point to note is that my hitting the Escape key could also be causing the WebSocket connection to close. However, if you watch closely or try for yourself you will see the close event being logged just before the page refreshes.

The unexpected behavior is due to the way in which Firefox and Chrome handle the closing of a Websocket. When the page is refreshed, both browsers close the connection, however, Firefox will execute your onclose code, while chrome closes the connection and skips straight to re-loading the new page. So yes, I confirm this strange behavior.
Even stranger is the fact that, from my observations, calling websocket.close() in chrome will immediately close the connection and call the onclose function, while Firefox waits for a close message back from the server.
The wasClean property will be true if a close message was received from the server
If your library is auto-reconnecting without checking the wasClean property then this could cause a problem, as it tries to re-establish the connection as the page refreshes. You should consider not using the library for this and doing it manually, it should'nt be very hard, just call connect in the onclose function with an if statement making sure the onclean property is true. Or to be even more safe set a variable in onbeforeunload that prevents any new connection.
hope this helps!

This is amazingly still the current behavior in 2022. You can demonstrate this trivially by adding a console log in an onclose handler for a websocket, and click a link in Firefox vs in Chrome while watching the console (ensuring you preserve the console between webpages):
ws.onclose = function(e) {
printMsg('CLOSE')
// ... my other code ...
}
Firefox will show you a 'CLOSE' and Chrome will not.

Related

Open conversejs chat window after it has already been closed with initialize

I have an mobile web based application where I want the user to only use a chat window between them and another person.
I have javascript button that opens a chat window but it does it through the converse.initalize method with all the configuration variables pass to it. On the mobile view the user is only allowed to closed the chat window, there is no minimize option available.
Is there a way to open the chat window again from outside converse.js with out using the initialize method again? It seems a bit heavy since the chat window was open previously I can not see a public api for doing this and I can not see a way of doing this using a plugin since the button event is out side converse.
There is probably a better way of doing this but in case it helps...
I was trying to decipher the debug log on this and I think that, even though the chat window is closed in Converse, the connection to my ejabberd server isn't disconnected. I tried firing a disconnect when the window close event is fired.
this._converse.on('chatBoxClosed', function (chatbox) {
this._converse.connection.disconnect();
});
At this point Converse is clever and tried to reopen the window and rejoin the room if auto_reconnect is set to true so I had to turn it off.
window.converse.initialize({
auto_reconnect: true,
Is there a way to open the chat window again from outside converse.js with out using the initialize method again?
Not from outside converse.js, but you can register a plugin for converse.js and open the chat from within the plugin by calling _converse.api.chats.open().
The API is documented here:
https://conversejs.org/docs/html/developer_api.html#the-chats-grouping

Chrome app "onSuspend" being called, why?

According to Google's app lifecycle docs
When the event page has no executing JavaScript, no pending callbacks, and no open windows, the runtime unloads the event page and closes the app.
I am seeing in my app that an onSuspend is being triggered, which also has the side effect of invalidating any FileEntry or DirectoryEntry references (an as-of-yet undocumented "feature"), only the onSuspend is triggered when I still have pending callbacks and open windows. Does anybody know which other conditions will trigger an onSuspend? Does it have to do with the app using too much memory?
It makes sense that onSuspend will be called when the event/background page has no activity and there are no windows open, but when else would onSuspend be called?
Is there a secret permission that I can use to disable onSuspend from being called? A background permission API in the works?
It should not be triggered if you have open windows unless something atypical is under way, like the user upgrading chrome.
If you are seeing onSuspend events at other times, that sounds like a bug. Please report at crbug.com with steps to reproduce.

How do NPAPI Plug-in accept command+o event?

I got into a trouble, because my plug-in want to open file dialog when using command+o,but the safari holded on this event.Anyone has a solution?
I strongly suspect there is nothing you can do about this; as a plugin you are a second class citizen, a guest in the process.
You can accept the command event, you have to listen to set a callback for the event member of NPPluginFuncs struct in NP_GetEntryPoints method.
In that method you'll receive all mouse and keyboard events, as well as window focus events. You can cast the second argument from void* to NPCocoaEvent where you will find all necessary parameters suchs as event type, mouse state, keys and focus data.
Please check which event type you're handling before digging into the 'data' union of NPCocoaEvent, otherwise you can get an EXC_BAD_ACCESS.
I'm having trouble with sharing commands with the browser, in my case Command+O should fire the plugin's file open dialog only, but it's also firing the browser open file dialog. Supposedly, returning TRUE for event handling method should report the browser that the plugin handled the event, but I'm having no luck yet.

Is there a way to detect if a browser window is closed?

Is there a way to detect if a browser window is closed using GWT. For example a window opened through GWT using this code:
Window.open("some_url", "__blank", null);
I need to detect wether this windows opened through gwt is closed. Is there a way to do that?
I think, it is a real problem making it cross-browser.
GWT has
Window.addCloseHandler(new CloseHandler<Window>() {
public void onClose(CloseEvent<Window> windowCloseEvent) {
}
});
Which handles the onunload event(occurs before the browser closes the document).
However it does not work for handling browser close event with all browsers, because when refreshing the page, this event is fired as well.
Since GWT also generates JavaScript see this article: Window Close Event of Browser
Here is conclusion of that article:
Conclusion
As we have already discussed that there is no 100% fool proof way to
detect the browser close event in a lot of cases, the above technique
can fail. For example if the user kills the browser's process from
task manager, there could be many more cases. Yet in a lot of cases,
this technique can be handy. Best of luck and happy programming.

Eclipse RAP - Firefox doesn't forget session

We've got an Eclipse RAP application that's behaving a bit strangely in Firefox - two distinct problems.
When you browse around, you can click on a button in one part of the system. This opens a popup window like so:
IWorkbenchBrowserSupport bs;
bs = PlatformUI.getWorkbench().getBrowserSupport();
int style = IWorkbenchBrowserSupport.AS_EXTERNAL;
IWebBrowser b = bs.createBrowser(style, getRandomID(), "Hello world", "");
b.openURL(new URL(...));
where the URL is another servlet in the application. This servlet is in the same runtime, but has nothing to do with RAP - it takes a binary blob from in-memory storage and dumps it in the output stream.
Problem 1: This causes the HTTP session to die in firefox, and shows the "session expired" RAP error page with a link to restart the session.
Problem 2: Now, when you click on the link to restart the session, it shows the application's dialog again, but the session expired error is shown again the moment you do anything. This prevents the user from using the system again, unless Firefox is closed down completely and restarted. A quick peek with FireBug reveals that the JSESSIONID passed by Firefox does not change.
Has anyone seen this before?
How long is the dumping of the stream to the output? May it cause a timeout? As RAP uses Javascript calls, it might be much shorter than the normal timeout time.
For problem 2: Firefox caches a lot of things; and if the Javascript execution hangs, it might cause such problems.
Are these problems present in other browsers? It might be a good idea to check with the internal browser (or any other browser with a different rendering engine).
It turns out that if a RAP application opens a popup window pointing to a servlet in the application itself, inside the current HTTP servlet context, the session is killed. Fixed by creating a dummy HTTP context for the servlet in question.
If you need to deliver content from within the same application, you should use a service handler instead. See this FAQ:
http://wiki.eclipse.org/RAP/FAQ#How_to_provide_download_link.3F