Firefox 7.0 failing with WebSocket and large payload?

162 views
Skip to first unread message

neek

unread,
Sep 30, 2011, 5:13:13 AM9/30/11
to cometd-users
Just wanted to bring this to people's attention. I've employed the
websocket transport in our app for the first time and it ran fine on
Chrome and IE9, but failed on Firefox (both 6.2 and 7.0). I find that
when our app tries to return a large amount of data (100K or more) it
causes Firefox to close the MozWebSocket object. I then see a failure
reported in the cometd library as a /meta/connect failure.

I've chatted with Simone on IRC and it seems this is probably a
Firefox bug, not a cometd or jetty issue. Wireshark shows correct
network traffic to/from jetty, it all goes pear shaped when the data
hits Firefox.

Cometd 2.4.0beta2
Jetty 7.5.1
Firefox 7.0

about:config shows network.websocket.max-message-size = 16000000

I've built a test app that reproduced this behaviour, it simply
connects to a cometd server, handshakes, subscribes to a response
channel for the response data, then sends a request for some data.
The AbstractService-derived class in the java app server receives the
request, and generates an amount of data, and delivers it to the
response channel. When the amount of data returned is too large, I
see Firefox fail before any cometd handlers are called to handle the
received websocket message.

I've seen this behaviour on both my Linux laptop (fedora 15) and
Windows 7.

Here comes two files of code.. the cometdrawtest.html, a raw test of
cometd without my app's framework around it, and GenerateDataService,
an AbstractService that's set up in the server side framework. I have
to pass some handshake ext data in because our server authenticates
handshakes, please ignore that, it's irrelevant to this test.

cometdrawtest.html:

<!DOCTYPE html>
<html>
<head>
<title>Cometd Raw Test</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="../resources/dojo/dojo/
dojo.js"></script>
<script type="text/javascript">
dojo.require("dojox.cometd");

var hHandshakeListener;

dojo.ready(function() {

dojox.cometd.websocketEnabled = true;

dojox.cometd.configure( {
url: 'http://ourserver.com:8080/winesdemo/cometd',
logLevel: 'debug'
});

hHandshakeListener = dojox.cometd.addListener("/meta/handshake",
function(data) {
console.log("/meta/handshake data: ", data);
if (data.successful === false) {
console.error("Handshake error! ", data);
console.dir(data);
} else {
console.debug("Handshake OK!");

// We'll need to know when our subscribe is complete, so we may
publish safely
dojox.cometd.addListener("/meta/subscribe", function(data) {
console.log("/meta/subscribe listener saw data: ", data);
if (data.successful === true && data.subscription === '/
generateddata/receive') {
// We're ready to go, enable the buttons.
dojo.query('button').forEach(function(b) { dojo.attr(b,
'disabled', false) });
}
});

// When we publish, the response will come back via this
channel.
dojox.cometd.subscribe('/generateddata/receive', function(data)
{
console.log("receive got: ", data);
});

}
});

dojox.cometd.handshake();
});

function request(amount) {
dojox.cometd.publish('/generateddata/go', { amount: amount });
}

function requestTenK() {
console.log("Publishing request for 10K");
request(10000);
}

function requestAThousandK() {
console.log("Publishing request for 1000K");
request(1000000);
}

function requestAmount() {
var am = parseInt(dojo.byId('amountField').value);
console.log("Publishing request for " + am);
request(am);
}
</script>
</head>
<body>
<p>This is a simple test page to request the cometd server send us
various amounts of data. The buttons are disabled until handshake and
subscription are seen to succeed. I find that 10000 (10K) is safe,
but 1000000 (1000K) is not safe.</p>
This works easily: <button type="button" onClick="requestTenK()"
disabled>Request 10K</button>
This does not work: <button type="button"
onClick="requestAThousandK()" disabled>Request 1000K</button>
<br/>These seem to be the limits: 67519 is fine, 67520 is not.
<button type="button" onClick="request(67519)" disabled>Request 67519</
button> <button type="button" onClick="request(67520)"
disabled>Request 67520</button>
Or type a value in here and click 'Request Amount': <input
id="amountField"/>
<button type="button" onClick="requestAmount()" disabled>Request
Amount</button>
</body>
</html>



GenerateDataService.java:

package ltd.yavin.liveauction.bayeux;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import javax.servlet.ServletContext;

import org.apache.commons.lang.StringUtils;
import org.cometd.bayeux.server.BayeuxServer;
import org.cometd.bayeux.server.ServerSession;
import org.cometd.server.AbstractService;

public class GenerateDataService extends AbstractService {
private static final Logger logger =
Logger.getLogger(GenerateDataService.class.getName());

public GenerateDataService(BayeuxServer bayeux)
{
super(bayeux, "generator");

addService("/generateddata/go", "_ctl");
}

public void destroy(ServletContext servletContext) {
}

@SuppressWarnings("unchecked")
public void _ctl(ServerSession remote, Map<String, Object> data) {

Object amountObj = data.get("amount");
long amount = 10000;
if (amountObj instanceof Long) {
amount = (Long)amountObj;
} else {
logger.severe("Unknown type of amount argument: " + amountObj +
" (" + amountObj.getClass().getName() + ")");
}

String generatedData = StringUtils.repeat("*", (int)amount);

Map<String, Object> returnObject = new HashMap<String, Object>();
returnObject.put("data", generatedData);

logger.info("Returning " + amount + " characters of data.");

remote.deliver(getServerSession(), "/generateddata/receive",
returnObject, null);
}

}

neek

unread,
Sep 30, 2011, 7:13:59 AM9/30/11
to cometd-users
I've raised this as a bug against Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=690703

neek

unread,
Sep 30, 2011, 9:55:20 AM9/30/11
to cometd-users
https://bugzilla.mozilla.org/show_bug.cgi?id=690703 has been updated
with advice to use an (apparently) undocumented cometd servlet init-
param that allows us to increase a buffer size so the websocket
traffic is not fragmented, avoiding this buggy behaviour in firefox
6.x and 7.x.

I cannot say whether this larger buffer size would cause any other
problems. I'm going to reengineer my app to send smaller data anyway,
the amount I'm sending is leading to a pretty unwieldy user experience.
Reply all
Reply to author
Forward
0 new messages