How to terminate long poll Ajax request at page leaving - ajax

I have long poll Ajax request. Browser, at least but not last IE doesn't terminate the request at page leaving, so request remains open and active even if a user visits some other site. Say more, a browser can successfully process responses from this connection, although their result go nowhere. General recommendations as call htmlxml connection abort or stop for a window obviously do not work.
So my implementation is adding extra Ajax call on unload to notify server connection holder that page is on leave, so it can send some dummy response and a browser will return the connection to pool of available after. This approach works but looks for me over engineered. Unfortunately I can observe a similar problem with some other programs, like GMAIL, it also does long poll and as result after some reloading it stops working. So if somebody found some good approach to address the problem without switching to short poll or assign connection timeout, then share your solution.

There's an abort() method on IE's XHR which will manually disconnect it.
It's a bit hacky, but you could try something like:
<body onbeforeunload="AbortMyAjax()">
and use that method to abort any active long-polls.
For reference, here's a bit of code from a project of mine:
$this.lp = null;
function _LongPoll() {
$.ajaxSetup({ cache: false });
$this.lp = $.getJSON(m_PollUrl, _LongPollCallback);
}
And in the body beforeunload:
if(!!QueueManager.lp && !!QueueManager.lp.abort) QueueManager.lp.abort('PAGE_CLOSED');

Related

Cypress tests failing in firefox in pages with polling requests

I have a following test in Cypress:
visit first page with the header A
click on the Go to B Page button
assert that the header of the page is now B
It works fine in Chrome, but failing in Firefox, as on the page B I have some background polling requests, and when cypress switches to another test and those requests get "canceled" away, I get either TypeError: NetworkError when attempting to fetch resource or AbortError: The operation was aborted
All the requests are using fetch api, by the way.
The possibility to mute those errors through the uncaught:exception event seems a bad idea, and so does the idea to do something on the page to cancel the polling, as it is not the thing under testing.
Maybe someone has encoutnered this problem too and got some non-hacky solution?
I had a similar issue with Cypress tests in Firefox and resorted to the slightly hacky solution of using an uncaught:exception handler as you mention. It is possible to filter error messages somewhat at least:
function handleUncaughtException(err){
if (err.message.includes('Request aborted') ) {
console.log("Request aborted. Test will continue. Error:",err);
return false; // return false to make test continue
}
throw err;
}
cy.on('uncaught:exception',handleUncaughtException);
In principle you can cancel this handler when it's no longer needed. In my case though, this stopped the test working, presumably because the request started previous to or after the calls.
cy.removeListener("uncaught:exception", handleUncaughtException)
The Cypress docs have some advice on defining these: see at https://docs.cypress.io/api/events/catalog-of-events#Examples. It may be useful to put the handler in a support file, so that it is applied to all tests.
(See also https://docs.cypress.io/api/events/catalog-of-events#Event-Types and https://nodejs.org/api/events.html#events_emitter_removelistener_eventname_listener).

Actionscript 4: NetConnection.connect(...) does not fire a NetStatusEvent event

I downloaded the red5-recorder (http://www.red5-recorder.com/) , which fails to allow me to start recording. After debugging I found that the netconnection, needed to record to a media server, created does not fire a NetStatusEvent event, so essentially it fails silently. I have implemented the connection with the following minimal working example:
trace("make net connection");
nc = new NetConnection();
nc.client = { onBWDone: function():void{ trace("bandwidth check done.") } };
trace("add event listener");
nc.addEventListener(NetStatusEvent.NET_STATUS, function(event:NetStatusEvent) {
trace("handle");
});
trace("connect!");
nc.connect("rtmp://localshost/oflaDemo/test/");
trace("connect done");
The output of this piece of code is:
make net connection
add event listener
connect!
connect done
The actionscript api states that the connect-call always fires such an event:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/NetConnection.html#includeExamplesSummary
Moreover, the netconnection is not 'connected' (a state of the NetConnection object) 10 seconds after the call. I also took a look at this: NetConnect fails silently in Flash when called from SilverLight But the fix suggested by the author, swapping rtmp and http in the connection uri, do not work. Also, I tested the uri and in fact the exact same code sniplet in a personal project, where it did work. I just can not seem to find why connecting to a media server fails silently in the red5-recorder project.
The awkward part is that if I pass some random string as a conenction uri, still nothing happens (no event, no exception, no crash). Also not setting nc.client becore nc.connect(), which caused exceptions in my experience, did not cause exceptions.
Any suggestions are welcome.
You are setting the address to localshost instead localhost.
nc.connect("rtmp://localshost/oflaDemo/test/");
Correct address:
nc.connect("rtmp://localhost/oflaDemo/test/");

mvc3 detect website (application) is closing

I'm building a website with mvc3 and I need to delete a data in my database only when the application is closing. (The user click on the red x).
I tried with javascript using the onbeforeunload event, but this event happens everytime I go into a new page in my application.
Is it possible to detect when the user closes the window?
It's not possible. But, what you can do is have a small javascript block that will make an ajax call every n minutes/seconds to tell the server that the user still has the browser open.
This way, you can set a timeout that says if after 5 minutes we haven't heard from the user we can delete the data in the database (or whatever action you need to do).
To implement the timeout logic there are 2 options:
You have a separate service (console app or windows service) running on some interval that checks if any user's timeout is greater than some value. If it is then perform whatever action you need.
If any user performs an action that would have been blocked, you first check if any user still has it active (the timeout value is greater than current time). If there is, you block the user, if there isn't, you can remove that old timeout value since it's expired.
Use a synchronous ajax request in the window.unload event.
When the user goes to a different page, or closes, or refreshes then this event will fire. You could call a service on your web app to notify it that the user is no longer editing the document
After a very quick google, I saw this snippet here
$(window).unload(function() {
$.ajax({
url: 'resetTheDocument?id=whatever',
async: false,
cache: false,
type: "POST",
data: "My work here is done"
});
});
Good morning you could try adding your logic to the global.asax file in the Session_End method to delete the record in your database.

Socket.IO disconnection problem before closing window

I am trying to prevent the client from disconnecting from the server. So before the user closes the window on which the app is open, I do:
$(window).bind("beforeunload", function() {
return("Close the app?");
});
But the problem is that no matter if the user chooses to leave or stay on the page where the app is open, the client get's disconnected (stops listening) from the server, before even I chose an option. So if the user chooses to stay on the page, nothing will be sent or received from the server.
Why can this be? How can this be prevented?
I had exactly the same problem in my project.
When you call socket.connect(), you should set sync disconnect on unload parameter of your connection to false (it is true by default):
var conn_options = {
'sync disconnect on unload':false
};
socket = io.connect(url, conn_options);
You can find more connection options here: https://github.com/LearnBoost/socket.io/wiki/Configuring-Socket.IO
P.S. Hope it's still actual for you :)
UPD.
Since the doc was changed, false is now the default value of sync disconnect on unload
You might not be able to avoid the problem as there are no other events triggering before "beforeunload" at window close that i know of. However,you could work around it by asking the socket to reconnect in the callback of the window close dialog when the user chooses to not exit the page. Reconnecting is pretty easy, just:
socket.connect()
Here's another question that describes reconnecting in more detail:
How to reconnect as soon as disconnect happens

If I Rapidly Click the Browser Back Button Twice, The User is Logged Out in Our Cake App

This is a weird bug, and I'm not even sure how to begin figuring out what's going on.
We are using Cake 1.3.8 with our sessions in the database. I am not using ACL or any other access control. If we navigate into the application and click around a bit, and then rapidly click the browser back button twice (I've tried in Firefox and Chrome) the user is logged out more often than not and receives the error message 'You are not authorized to access that location'.
All of my searches thus far have involved people wanting to make the page inaccessible if a user logged out and then used the back button. I'm not seeing anything reported with regards to the issue I'm seeing.
Does anybody know if this is a Cake issue or have any thoughts on debugging what is going wrong?
Update: I found where the problem is. I have the security set to high, because we need the session to be closed whenever somebody closes the browser. I also have the timeout set very high because we do large binary uploads to S3, and don't want the user logged out while it's uploading or downloading. The specific block of code in cake_sessions.php that's causing the problem is:
$time = $this->read('Config.time');
$this->write('Config.time', $this->sessionTime);
if (Configure::read('Security.level') === 'high') {
$check = $this->read('Config.timeout');
$check -= 1;
$this->write('Config.timeout', $check);
if (time() > ($time - (Security::inactiveMins() * Configure::read('Session.timeout')) + 2) || $check < 1) {
$this->renew();
$this->write('Config.timeout', 10);
}
}
$this->valid = true;
I would guess this is because session IDs are regenerated between requests when security = high. Source:
http://book.cakephp.org/compare/44/CakePHP-Core-Configuration-Variables/cakephp/cakephp1x
You only need one out of sync request, say for a missing image and you will lose the session. I've generally found it unworkable because it's not possible to prevent users double-clicking on links and buttons and invalidating their session.
I would think about using medium security, setting the session timeout fairly short and using an AJAX script to refresh the session at regular intervals (eg every 60s). That way the user will be logged out quickly if the tab/window is closed.
If security is a priority I would suggest hacking the core to make sure the session cookies are set to http_only to help guard against session hijacking by XSS attacks. Cakephp 1.x supports PHP4 so probably isn't setting this by default.
http://php.net/manual/en/function.setcookie.php
It's possible that the session is erased and before it can be written again, the back button is clicked removing the auth from the session variables.
Page loads -> Back Button Clicks -> sessions is erased (but before session is rewritten) -> Back button clicks -> Session checks no existing session.
The only thing that I can think is happening is that when you're going back a page too quickly your code can't validate the person quickly enough (round trip from checking credentials) and throws an error that gets displayed on the next page that is loaded (second backed-to page).
Are you sure the person is actually logged out, or is it just the error being thrown?
Without seeing any code, it will be difficult to nail it down any further.

Resources