In a JavaScript class, an XMLHttpRequest connect to the server. The server is sending data, slowly. This work fine in Chromium, but Firefox close the connection after random time (between ~4s and ~70s).
Why Firefox close the connection? and How to avoid that?
Simplified JS code:
var options = {};
options['header']=
{ 'Cache-Control':'no-cache, max-age=0',
'Content-type': 'application/octet-stream',
'Content-Disposition': 'inline'
};
// Get request information
this.http = new XMLHttpRequest();
this.http.onreadystatechange = _streamingResponse.bind(this);
this.http.open('post', url, true);
for (var i in options['header'])
{
this.http.setRequestHeader(i, options['header'][i]);
}
this.http.send('');
for the PHP part, something like:
sleep(200); //wait long time, so firefox close the socket.
If the server send something every few seconds (<5s) the connection stay alive "forever". But if no data is sent, Firefox close the connection.
The connection close with: - readyState = 4 - status = 0
The server seem to be correct, as in Chromium it work correctly.
Full test code:
test.html
<html>
<header>
</header>
<body>
</body>
<script type="application/javascript">
function log( msg )
{
document.body.appendChild(document.createElement('div').appendChild(document.createTextNode(msg)));
document.body.appendChild(document.createElement('br'));
}
function request(url)
{
function _streamingResponse()
{
if (4==this.http.readyState)
{
log('Done: ' + this.http.status);
}
else if (3==this.http.readyState)
{
var text = this.http.response.substr(this.lastRequestPos);
this.lastRequestPos = this.http.response.length;
log('Update: ' + text);
}
}
var options = {};
options['header']=
{ 'Cache-Control':'no-cache, max-age=0',
'Content-type': 'application/octet-stream',
'Content-Disposition': 'inline'
};
this.lastRequestPos=0;
// Get request information
this.http = new XMLHttpRequest();
this.http.onreadystatechange = _streamingResponse.bind(this);
this.http.open('post', url, true);
for (var i in options['header'])
{
this.http.setRequestHeader(i, options['header'][i]);
}
this.http.send('');
log('Request sent!');
}
req = new request('./test.php');
</script>
</html>
test.php
<?php
$timer = 60;
ignore_user_abort(true);
set_time_limit(0);
// Turn off output buffering and compression
ini_set('output_buffering', 'off');
ini_set('zlib.output_compression', false);
ini_set('implicit_flush', true);
ob_implicit_flush(true);
while (ob_get_level() > 0) {
$level = ob_get_level();
ob_end_clean();
if (ob_get_level() == $level) break;
}
if (function_exists('apache_setenv')) {
apache_setenv('no-gzip', '1');
apache_setenv('dont-vary', '1');
}
// Set header for streaming
header('Content-type: application/octet-stream');
flush();
// Send information
sleep($timer);
echo '<yes></yes>';
flush();
?>
Additional note: Firefox 43.0.03, Chromium 47.0.2526
EDITED:
Setting a callback for timeout it do not trigger. I conclude it is not a timeout.
this.http.timeout = 2000;
this.http.ontimeout = _streamingTimeout.bind(this);
After searching further, I found a Bug in Mozilla which seem the responsible of this behaviour. It should be solved in the version 45, but until then, we have to lead with it.
Even if the bug seem related only to Ipv6, I have the same issue using 127.0.0.1. However, with Firefox Developer Edition (V 45) the problem seem solved.
Why Firefox close the connection?
It should not. ref: https://bugzilla.mozilla.org/show_bug.cgi?id=1240319
How to solve it?
Except to send data every 3-4 seconds to maintain the connection open, I have no idea.
Sounds an awful lot like garbage collection.
I see you have tried timeout. But I'm not sure I understand your conclusion: Setting a callback for timeout it do not trigger.
Just be absolutely certain that you follow these rules:
4.2 Garbage collection
An XMLHttpRequest object must not be garbage collected if its state is either opened with the send() flag set, headers received, or loading, and it has one or more event listeners registered whose type is one of readystatechange, progress, abort, error, load, timeout, and loadend.
If an XMLHttpRequest object is garbage collected while its connection is still open, the user agent must terminate the request.
xhr.spec.whatwg.org
Check which state, send() flag and event listeners are set while no data is sent.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With