Issue with IE9

792 views
Skip to first unread message

papune SMETeam

unread,
Mar 2, 2011, 8:42:15 AM3/2/11
to gwt-comet
Has anyone tried comet with IE9 ...

When I tried I got the following issue
1. On server side doComet was called but after some time
cometTerminated got called with serverInitiated as false
2. On client side got a JavaScriptException : (Error): Permission
denied

Anyone has any idea around this

Richard Zschech

unread,
Mar 15, 2011, 6:44:11 AM3/15/11
to gwt-comet
Hi Papune,

I've not tried IE9 yet :-(

As it is a permissions error I'm guessing that IE9 has tighter
security than IE8. Are you running this on a proper domain? or just
your development machine? You might have to add a security rule for
your development machine to get it working.

From Richard.

Icky

unread,
May 10, 2011, 4:31:11 AM5/10/11
to gwt-comet
Hi everyone,

I am also having this issue - it *only* happens on IE9. (I have a prod
system that runs great on other browsers, thnx for this library!)
I've tracked the problem to this line:

iframe.setSrc("");

within IEHTMLFileCometTransport.disconnect()
are there any work arounds or experiments that anyone can think of?
I'm happy to try everything :)

I dont really understand why iframe.setSrc("") would trigger
permission problems under this scenario

Thanks,
icky

Icky

unread,
May 10, 2011, 8:40:02 AM5/10/11
to gwt-comet
Hi,

I've found a bit more info:

so it seems the first time i get a reference to the iframe, i am
permitted to setSrc.
However once that iframe has been populated with the result then all
calls to setSrc will trigger ie9's "permission denied".

To prove that, i've updated IEHTMLFileCometTransport to create a FRESH
htmlfile activeXobject everytime it needs to setSrc, and that worked.
Does that trigger any ideas?

Thanks,
Icky

Icky

unread,
May 11, 2011, 7:15:14 AM5/11/11
to gwt-comet
Hi guys,

So I don't have a fix, but I do have a work around using IE's
XDomainRequest.

This is what I did, (from reading atmosphere code):

1) Introduced a IEXDRCometTransport that extends the existing
RawDataCometTransport
public class IEXDRCometTransport extends RawDataCometTransport {

private static final String SEPARATOR = "\n";

private int read;
private XDomainRequest transportRequest;
private XDomainRequestListener xDomainRequestListener = new
XDomainRequestListener() {

@Override
public void onError(XDomainRequest request) {
if (isCurrent(request)) {
expectingDisconnection = true;
listener.onError(new
StatusCodeException(Response.SC_INTERNAL_SERVER_ERROR, ""), true);
transportRequest = null;
}
}

@Override
public void onLoad(XDomainRequest request, String
responseText) {
request.clearListener();
if (isCurrent(request)) {
transportRequest = null;
if (!disconnecting) {
onReceiving(Response.SC_OK, responseText, false);
}
}
}

@Override
public void onProgress(XDomainRequest request, String
responseText) {
if (!disconnecting && isCurrent(request)) {
onReceiving(Response.SC_OK, responseText, true);
} else {
request.clearListener();
request.abort();
if (isCurrent(request)) {
transportRequest = null;
}
}
}

@Override
public void onTimeout(XDomainRequest request) {
if (isCurrent(request)) {
if (!expectingDisconnection) {
listener.onError(new RequestException("Unexpected
connection timeout " + request.getTimeout()),
false);
}
}
}

public boolean isCurrent(XDomainRequest request) {
return request == transportRequest;
}
};

@Override
public void connect(int connectionCount) {
super.connect(connectionCount);
read = 0;
transportRequest = XDomainRequest.create();
try {
transportRequest.setListener(xDomainRequestListener);
transportRequest.openGET(getUrl(connectionCount));
transportRequest.send();

} catch (JavaScriptException ex) {
if (transportRequest != null) {
transportRequest.abort();
transportRequest = null;
}
listener.onError(new RequestException(ex.getMessage()),
false);
}
}

@Override
public void disconnect() {
super.disconnect();
if (transportRequest != null) {
transportRequest.clearListener();
transportRequest.abort();
transportRequest = null;
}
listener.onDisconnected();
}

private void onReceiving(int statusCode, String responseText,
boolean connected) {
if (statusCode != Response.SC_OK) {
if (!connected) {
super.disconnect();
listener.onError(new StatusCodeException(statusCode,
responseText), connected);
}
} else {
int index = responseText.lastIndexOf(SEPARATOR);
if (index > read) {
List<Serializable> messages = new
ArrayList<Serializable>();

JsArrayString data =
split(responseText.substring(read, index), SEPARATOR);
int length = data.length();
for (int i = 0; i < length; i++) {
if (disconnecting) {
return;
}

String message = data.get(i);
if (!message.isEmpty()) {
parse(message, messages);
}
}
read = index + 1;
if (!messages.isEmpty()) {
listener.onMessage(messages);
}
}

if (!connected) {
super.disconnected();
}
}
}

native static JsArrayString split(String string, String
separator) /*-{
return string.split(separator);
}-*/;

static String unescape(String string) {
return string.replace("\\n", "\n").replace("\\\\", "\\");
}
}

2. introduce GWT representation of XDomainRequest objects:
public class XDomainRequest extends JavaScriptObject {

public static native XDomainRequest create() /*-{
// XDomainRequest object does not play well with GWT
JavaScriptObject so store in local variable
var me = new Object();
me.request = new XDomainRequest();
return me;
}-*/;

public native static boolean isSupported() /*-{
if ($wnd.XDomainRequest) {
return true;
} else {
return false;
}
}-*/;

public final native void setListener(XDomainRequestListener
listener) /*-{
var self = this;
this.request.onload = function() {

listener.@net.zschech.gwt.comet.client.impl.XDomainRequestListener::onLoad(Lnet/
zschech/gwt/comet/client/impl/XDomainRequest;Ljava/lang/String;)
(self,self.request.responseText);
};
this.request.onprogress = function() {

listener.@net.zschech.gwt.comet.client.impl.XDomainRequestListener::onProgress(Lnet/
zschech/gwt/comet/client/impl/XDomainRequest;Ljava/lang/String;)
(self,self.request.responseText);
};
this.request.ontimeout = function() {

listener.@net.zschech.gwt.comet.client.impl.XDomainRequestListener::onTimeout(Lnet/
zschech/gwt/comet/client/impl/XDomainRequest;)(self);
};
this.request.onerror = function() {

listener.@net.zschech.gwt.comet.client.impl.XDomainRequestListener::onError(Lnet/
zschech/gwt/comet/client/impl/XDomainRequest;)(self);
};
}-*/;

public final native void clearListener() /*-{
var self = this;
$wnd.setTimeout(function() {
// Using a function literal here leaks memory on ie6
// Using the same function object kills HtmlUnit
self.request.onload = new Function();
self.request.onprogress = new Function();
self.request.ontimeout = new Function();
self.request.onerror = new Function();
}, 0);
}-*/;

public final native String getContentType() /*-{
return this.request.contentType;
}-*/;

/**
*
* @return the body of the response returned by the server.
*/
public final native String getResponseText() /*-{
return this.request.responseText;
}-*/;

/**
* set the timeout in milliseconds
*
* @param timeout
*/
public final native void setTimeout(int timeout) /*-{
this.request.timeout = timeout;
}-*/;

public final native int getTimeout() /*-{
return this.request.timeout;
}-*/;

/**
* The abort method terminates a pending send.
*/
public final native void abort() /*-{
this.request.abort();
}-*/;

/**
* Creates a connection with a domain's server.
*
* @param url
*/
public final native void openGET(String url) /*-{
this.request.open("GET", url);
}-*/;

/**
* Creates a connection with a domain's server.
*
* @param url
*/
public final native void openPOST(String url) /*-{
this.request.open("POST", url);
}-*/;

/**
* Transmits a empty string to the server for processing.
*/
public final native void send() /*-{
this.request.send();
}-*/;

/**
* Transmits a data string to the server for processing.
*
* @param data
*/
public final native void send(String data) /*-{
this.request.send(data);
}-*/;

protected XDomainRequest() {
}
}

public interface XDomainRequestListener {

/**
* Raised when there is an error that prevents the completion of
the
* cross-domain request.
*/
public void onError(XDomainRequest request);

/**
* Raised when the object has been completely received from the
server.
*
* @param responseText
*/
public void onLoad(XDomainRequest request, String responseText);

/**
* Raised when the browser starts receiving data from the server.
*
* @param responseText
* partial data received
*/
public void onProgress(XDomainRequest request, String
responseText);

/**
* Raised when there is an error that prevents the completion of
the
* request.
*/
public void onTimeout(XDomainRequest request);
}

3. Next implement the server side for this IEXDRCometTransport by
extending the existing RawDataCometServletResponse
public class IEXDRCometServletResponse extends
RawDataCometServletResponse {

// so much padding...
private static final int PADDING_REQUIRED = 2048;

public IEXDRCometServletResponse(HttpServletRequest request,
HttpServletResponse response,
SerializationPolicy serializationPolicy, ClientOracle
clientOracle, CometServlet servlet,
AsyncServlet async, int heartbeat) {
super(request, response, serializationPolicy, clientOracle,
servlet, async, heartbeat);
}

@Override
protected void setupHeaders(HttpServletResponse response) {
super.setupHeaders(response);
response.setContentType("application/comet");
response.setCharacterEncoding("UTF-8");

String origin = getRequest().getHeader("Origin");
if (origin != null) {
response.setHeader("Access-Control-Allow-Origin", origin);
}
}

@Override
protected OutputStream getOutputStream(OutputStream outputStream)
{
return setupCountOutputStream(outputStream);
}

@Override
protected int getPaddingRequired() {
return PADDING_REQUIRED;
}
}

4. finally we need to make GWT-COMET select this new implementation
for IE9:
I wasn't sure how to get the right user.agent for gwt.xml to do
dynamic binding (i'm not on latest gwt), so I overrode CometClient to:
public CometClientTransportWrapper() {
if (EventSource.isSupported()) {
transport = new EventSourceCometTransport();
} else if (XDomainRequest.isSupported()) {
transport = new IEXDRCometTransport();
} else {
transport = GWT.create(CometTransport.class);
}
transport.initiate(CometClient.this, this);
}

and then overrode CometServlet to:
protected CometServletResponseImpl
createCometServletResponse(HttpServletRequest request,
HttpServletResponse response, SerializationPolicy
serializationPolicy, ClientOracle clientOracle,
int requestHeartbeat) {
String userAgent = request.getHeader("User-Agent");
System.out.println("UA: " + userAgent);
if (userAgent.contains("MSIE 9.0")) {
return new IEXDRCometServletResponse(request, response,
serializationPolicy, clientOracle, this, async, heartbeat);
} else {
return super.createCometServletResponse(request, response,
serializationPolicy, clientOracle, requestHeartbeat);
}
}

It seems to be working for me.

Thanks,
Icky

Moreno Ambrosin

unread,
May 11, 2011, 5:16:20 PM5/11/11
to gwt-comet
Hi,

may I make you a question?
Did you change library code or you just added subclasses?
Cause in CometServlet class the method createCometServletResponse is
private...

thanks,
Moreno
> listen...@net.zschech.gwt.comet.client.impl.XDomainRequestListener::onLoad(Lnet/
> zschech/gwt/comet/client/impl/XDomainRequest;Ljava/lang/String;)
> (self,self.request.responseText);
>                 };
>                 this.request.onprogress = function() {
>
> listen...@net.zschech.gwt.comet.client.impl.XDomainRequestListener::onProgress(Lnet/
> zschech/gwt/comet/client/impl/XDomainRequest;Ljava/lang/String;)
> (self,self.request.responseText);
>                 };
>                 this.request.ontimeout = function() {
>
> listen...@net.zschech.gwt.comet.client.impl.XDomainRequestListener::onTimeout(Lnet/
> zschech/gwt/comet/client/impl/XDomainRequest;)(self);
>                 };
>                 this.request.onerror = function() {
>
> listen...@net.zschech.gwt.comet.client.impl.XDomainRequestListener::onError(Lnet/
> ...
>
> leggi tutto

Icky

unread,
May 12, 2011, 2:32:56 AM5/12/11
to gwt-comet
Hi Moreno,

I had to change the library code :(
because it is private as you said

so I made an override (same package, same class name) by copying
source from gwt-comet's CometClient and put it in a classpath before
gwt-comet's jars, then updated the method in question from private to
protected.

regards,
Icky
> ...
>
> read more »

Pierre Havelaar

unread,
May 12, 2011, 5:44:54 AM5/12/11
to gwt-...@googlegroups.com
Hi guys,

I wrote this implementation for the Atmosphere project and can confirm
that it works.
However I did have some issue's with the detection on the serverside,
because IE9 can operate in IE8 compatibility mode which causes the user
agent not to show as IE9. In the atmoshere project I solved it by
letting the client code decide which implementation to use base on whats
available in the browser and let the server know this when making the
connection. In fact XDomainRequest is also available for IE8.

Good luck!
Pierre

>>> if (!disconnecting&& isCurrent(request)) {

>> read more �

Moreno Ambrosin

unread,
May 12, 2011, 11:53:48 AM5/12/11
to gwt-comet
Hi!

it works!Great job :D!
Last question; in my project, i make different http requests using
gwt's rpc. It seems that the http session associated with requests
made
by rpc calls is different from the session associated with the GET
request used for comet stream implementation (XDomainObject).
Is it due to the use of this particular Javascript Object?

Thank u very much !!

Moreno
> ...
>
> leggi tutto

Pierre Havelaar

unread,
May 13, 2011, 3:19:25 AM5/13/11
to gwt-...@googlegroups.com
There are some constraints to using the XDomainObject which are
documented on the Microsoft website.
To be able to use sessions I created the following override to include
the session on the GET url, should also work for PHP sessions:

@Override
public String getUrl(int connectionCount) {
String url = super.getUrl(connectionCount);
// Detect if we have a session in a cookie and pass it on the
url, because XDomainRequest does not
// send cookies
if (url.toLowerCase().contains(";jsessionid") == false) {
String sessionid = Cookies.getCookie("JSESSIONID");
if (sessionid != null) {
String parm = ";jsessionid=" + sessionid;
int p = url.indexOf('?');
if (p > 0) {
return url.substring(0, p) + parm + url.substring(p);
} else {
return url + parm;
}
}
}
if (!url.toUpperCase().contains("PHPSESSID")) {
String sessionid = Cookies.getCookie("PHPSESSID");
if (sessionid != null) {
int p = url.indexOf('?');
String param = "PHPSESSID=" + sessionid;
if (p > 0) {
return url.substring(0, p + 1) + param + "&" +
url.substring(p + 1);
} else {
return url + "?" + param;
}
}
}

return url;
}

Pierre

Icky

unread,
May 13, 2011, 10:59:28 PM5/13/11
to gwt-comet
BRILLIANCE!!! thank you so much!
> ...
>
> read more »

papune SMETeam

unread,
May 17, 2011, 3:28:14 AM5/17/11
to gwt-comet
So the above code needs to be integrated in my gwt project and comet
library also needs to change rite

Any idea when a new gwt-comet version will release which supports IE9
without any changes reqd on our side.

Neways Thanks for the efforts will try and use it in my code
> ...
>
> read more »

Geoff Froud

unread,
Jun 20, 2011, 5:11:59 AM6/20/11
to gwt-comet
Are there any plans to release a new gwt-comet which supports IE9?
> > > >>>>>                   for...
>
> read more »

Richard Zschech

unread,
Jun 26, 2011, 8:21:57 PM6/26/11
to gwt-comet
Hi Guys,

Sorry for the delay, I'll work on integrating this in the next few
days.

From Richard.
> > > > >>>>>               }...
>
> read more »

chill_hus

unread,
Jun 29, 2011, 1:18:29 AM6/29/11
to gwt-comet
Hi Richard,
Thank you so much for this news. Have been waiting for making my code
run on IE9
> ...
>
> read more »

NitinB

unread,
Jul 8, 2011, 10:49:17 AM7/8/11
to gwt-comet
Hi Richard,
Thanks for the great lib.
Do you have a planned date to release support for IE9. Sorry but we
are blocked and eagerly waiting for the IE9 support.

-NitinB
> > > > > > >>>>>               listener.onError(new RequestException(ex.getMessage()),...
>
> read more »

Bob

unread,
Aug 2, 2011, 12:51:50 PM8/2/11
to gwt-comet
Hi Richard,

Thanks so much for your efforts. Any update on when and which gwt-
comet release will support IE9?
> ...
>
> read more »

Bob

unread,
Aug 31, 2011, 12:00:28 PM8/31/11
to gwt-comet
Any update on when this fix for IE 9 will be available?
> ...
>
> read more »

Richard Zschech

unread,
Sep 10, 2011, 6:24:05 PM9/10/11
to gwt-comet
Sorry guys, I've not had a chance to spend much time on this. I
initially tried the technique described by Icky above but it was
failing some of my test cases.

From Richard.
> > > > > > > >>>>>               transportRequest.openGET(getUrl(connectionCount));...
>
> read more »

Bob

unread,
Sep 28, 2011, 9:54:43 AM9/28/11
to gwt-comet
Thanks for the update. Any idea when you will have a fix available?
> ...
>
> read more »

pradyumna

unread,
Nov 11, 2011, 3:19:43 AM11/11/11
to gwt-comet
Any update on this yet?
> ...
>
> read more »

stephan...@gmail.com

unread,
May 30, 2012, 5:55:37 AM5/30/12
to gwt-...@googlegroups.com
Is there any idea on the next version of the API that takes into account this fix please?

Thanks in advance

stephan...@gmail.com

unread,
May 30, 2012, 8:46:33 AM5/30/12
to gwt-...@googlegroups.com
What is the status of this update, please?
Do I fix this bug alone or is there a patch provided?

Thanks in advance.

João Marques

unread,
Oct 17, 2012, 1:16:18 PM10/17/12
to gwt-...@googlegroups.com, pune...@gmail.com
Thanks for the work-around. It's works (well, almost) for me.

With the IE9, i was able to make the connection to server (Jetty 6) but my request doesn't always reached the client :(

After debugging i realize that my message (with the same content) doesn't always have the same format, i've printed the message in IEXDRCometTransport@onReceiving and the result was:

-  *************************[3,2,1,["net.zschech.gwt.chat.client.ChatMessage/2915388376","4","teste"],0,7]" <-- Incorrect (doesn't send the message)
-  [3,2,1,["net.zschech.gwt.chat.client.ChatMessage/2915388376","4","teste"],0,7]" <-- Correct (doesn't send the message)

For this reason I had to grab my hammer and...

if (!message.isEmpty()) {
//Outch
String hammerMsg = message;
if (message.indexOf("[") != -1) {
hammerMsg = message.substring(message.indexOf("["));
}
parse(hammerMsg, messages);
}

It's ugly but it works and I haven't found an better solution. Does anyone have a solution to prevent this?

Thanks.

kapil...@gmail.com

unread,
Jun 30, 2014, 10:18:00 AM6/30/14
to gwt-...@googlegroups.com, pune...@gmail.com
Changes are working fine with this change in IE 9 with commet, but when I tried to access the HttpSession.getLastAccessedTime(), though I dont use the session to send any request the last accessed time it is getting changed. I suspect comet is changing the session's last accessed time by sending some requests. It happens only in IE 9, other versions and browsers its fine. Does anyone know how can we restrict/bypass commet making such calls and changing the last accessed time?

-

kapil...@gmail.com

unread,
Jun 30, 2014, 10:18:54 AM6/30/14
to gwt-...@googlegroups.com

kapil...@gmail.com

unread,
Jun 30, 2014, 10:19:20 AM6/30/14
to gwt-...@googlegroups.com
Changes are working fine with this change in IE 9 with commet, but when I tried to access the HttpSession.getLastAccessedTime(), though I dont use the session to send any request the last accessed time it is getting changed. I suspect comet is changing the session's last accessed time by sending some requests. It happens only in IE 9, other versions and browsers its fine. Does anyone know how can we restrict/bypass commet making such calls and changing the last accessed time?

On Wednesday, 11 May 2011 16:45:14 UTC+5:30, Icky wrote:
Reply all
Reply to author
Forward
0 new messages