]
Brian Leathem updated RF-13674:
-------------------------------
Fix Version/s: (was: 4.5.0.Beta1)
a4j:push broken on WebLogic 12c in Chrome
-----------------------------------------
Key: RF-13674
URL:
https://issues.jboss.org/browse/RF-13674
Project: RichFaces
Issue Type: Bug
Security Level: Public(Everyone can see)
Components: component-push/poll
Affects Versions: 4.2.0.Final
Environment: WebLogic 12c
Reporter: Val Blant
Attachments: atmosphere-weblogic12c-bug-0.8.4-sources.jar,
atmosphere-weblogic12c-bug-0.8.4.war, RichFacesPushFixFilter.java
<a4j:push /> works properly on Tomcat 7, but fails on WebLogic 12c in Chrome
(Firefox works fine).
{code:title=Page.xhtml|borderStyle=solid}
<a4j:push address="systemLinks" >
<a4j:ajax event="dataavailable" render="systemLinksPanel" />
</a4j:push>
<a4j:outputPanel id="systemLinksPanel">
stuff here
</a4j:outputPanel>
{code}
{code:title=Java Code}
TopicKey topicKey = new TopicKey("systemLinks");
TopicsContext topicsContext = TopicsContext.lookup();
topicsContext.publish(topicKey, "fly, you fools!");
{code}
On Tomcat 7 this work perfectly, and always refreshes '_systemLinksPanel_' when
data is published.
On Weblogic 12c the data is not flushed correctly. If you use Wireshark, you'd see
the following response coming back from the server:
{panel:title=Tomcat 7}
3b
<"topic":"systemLinks","data":"fly, you
fools!","number":0>
0
{panel}
{panel:title=Weblogic 12c}
003b
<"topic":"systemLinks","data":"fly, you
fools!","number":0>
{panel}
*Note the missing zero terminator line in the WebLogic response!*
I narrowed down the problem to the following:
{code:title=org.richfaces.application.push.impl.RequestImpl}
public synchronized void onBroadcast(AtmosphereResourceEvent<HttpServletRequest,
HttpServletResponse> event) {
MessageDataScriptString serializedMessages = (MessageDataScriptString)
event.getMessage();
getSession().clearBroadcastedMessages(serializedMessages.getLastSequenceNumber());
hasActiveBroadcaster = false;
if (isPolling()) {
event.getResource().resume(); // <= THIS LINE
} else {
postMessages();
}
}
{code}
There is nothing wrong with this in principle, but it does not work due to a bug in
Atmosphere 0.8.4. Calling _AtmosphereResource.resume()_ at this point seems reasonable,
since it is supposed to properly finish/commit the _HttpServletResponse_. However, this
does not work on WebLogic 12c and leads to incorrectly flushed data demonstrated above.
The underlying problem seems to be the fact that _AtmosphereResource.resume()_ method
interrupts the thread which flushed the socket Writer before a call to
_asyncContext.complete()_ is made:
{code}
public AtmosphereResource resume() {
....
if (!b.isDestroyed()) {
b.removeAtmosphereResource(event.getResource());
}
....
asyncSupport.action(this); // <= This is where asyncContext.complete() is called
}
{code}
I have verified that calling _asyncContext.complete()_ before we clean up Atmosphere
resources fixes the problem.
Here's the fix, which needs to go into _RequestImpl.onBroadcast_:
{code:title=org.richfaces.application.push.impl.RequestImpl}
public synchronized void onBroadcast(AtmosphereResourceEvent<HttpServletRequest,
HttpServletResponse> event) {
..............
if (isPolling()) {
// This is the workaround. Completing AsyncContext before cleaning up Atmosphere
resources
// seems to make this work everywhere.
//
AsyncContext asyncContext = (AsyncContext)
event
.getResource()
.getRequest()
.getAttribute("org.atmosphere.container.asyncContext");
if ( asyncContext != null ) {
asyncContext.complete();
}
event.getResource().resume();
} else {
postMessages();
}
}
..............
{code}
I am attaching a very simple WAR file that demonstrates the problem clearly. The demo app
does not use Richfaces, b/c I wanted to remove all unnecessary complexity. Instead I
created a couple of simple classes that mimic the behavior of
_org.richfaces.webapp.PushHandlerFilter_ and
_org.richfaces.application.push.impl.RequestImpl_. In the demo app, _MeteorRequest =
RequestImpl_, which is where the fix needs to go.
Please note that this issue is fixed in Atmosphere 2.1. I ran the demo jar with v2.1.5,
and it works correctly, so the easiest fix on the RichFaces side could be to simply
upgrade the underlying Atmosphere framework. The API differences, at least as far as the
PushHandlerFilter is concerned are minimal.
Now, the reason why only Chrome is effected has to do with processing of chunked
responses by the XMLHttpRequest. Unlike other browsers, Chrome is not capable of handling
improperly terminated chunked responses. So:
{noformat}
HTTP/1.1 200 OK
Cache-Control: no-store, no-cache, must-revalidate
Date: Wed, 18 Jun 2014 05:37:55 GMT
Pragma: no-cache
Transfer-Encoding: chunked <<--- THIS IS IMPORTANT
Content-Type: text/plain
Expires: -1
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
X-Powered-By: Servlet/3.0 JSP/2.2
0841
<!-- ----------------------------------------------------------------
http://github.com/Atmosphere
------------------------------------------------------------------------ -->
<!-- Welcome to the Atmosphere Framework. To work with all the browsers when
suspending connection, Atmosphere must output some data to makes WebKit based browser
working.-->
<!--
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
-->
<!--
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
-->
<!--
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
-->
<!--
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
-->
<!--
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
-->
<!--
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
-->
<!-- --------------------001c
Wed Jun 18 13:37:57 CST 201
<<--- MISSING 0 TERMINATOR
{noformat}
This can be fixed by explicitly setting Content-Length in the response, as per these
discussions:
http://stackoverflow.com/questions/22219565/iis-chrome-failed-to-load-res...
http://www.rahulsingla.com/blog/2010/06/asp-net-sets-the-transfer-encodin...
However, that does not seem to be feasible here, since we must reply with a header of
known length, followed by the data of unknown length.