The specified call count is not a number: null
Acegi + DWR + IE6 - ActiveX = Boom!
Today we had an interesting bug in a small web application developed for a customer in the financial industry. The application is based on the Spring Framework, secured by Acegi Security and makes heavy use of AJAX (powered by DWR).
Everything went fine while testing with different browsers from Firefox to Safari and Internet Explorer in different versions. Finally we have started testing in the target environment - well locked down and without support for ActiveX controls from untrusted sites. IE6 needs ActiveX for its implementation of XMLHttpRequest (XHR) - the heart of AJAX. If XHR is not available DWR automatically switches to using IFrames to emulate XHR. This usually works well and has already been used in the previous version. Nevertheless the application just didn't work: Every remote call failed with a not so user friendly error message: "The specified call count is not a number: null".
Remote debugging of Tomcat showed that DWR is trying the read the request data using req.getInputStream() to parse it. When using IFrames reading from the request's input stream fails immediately and returns null, when using XHR it works fine. The main difference is the content type of the requests "application/x-www-form-urlencoded" for IFrames and "text/plain" for XHR. As IFrames do work without Acegi but fail with the Acegi filters in place I guess Acegi does mess with the requests when it wraps them in its SavedRequestAwareWrapper.
I didn't have the time to further track it down, but I created a small workaround that falls back to using req.getParameter() if reading the stream fails.
The following snippet shows the modification made to DWR's ParseUtil.java:
in = new BufferedReader(new InputStreamReader(req.getInputStream()));
while (true)
{
String line = in.readLine();
if (line == null)
{
if (paramMap.isEmpty())
{
Enumeration nameEnum = req.getParameterNames();
while(nameEnum.hasMoreElements())
{
String name = (String) nameEnum.nextElement();
paramMap.put(name, req.getParameter(name));
}
}
break;
}
...
And who is to blame? Well, as with many interesting problems that's hard to decide. It's just a combination of multiple pieces of software mixed with environment constraints. I guess it's something that just happens and reminds us that testing is not useless.
Update 2008-02-22
Joe has just released DWR 2.0.3 that includes a fix for this issue.
Re: The specified call count is not a number: null
Thanks for the working digging into this. I agree that it's not easy to work out who got it wrong. Deep down we're all working around issues with how poorly the web itself is defined, so I think that's where the problem lies.
Anyway I've added some similar code that should go into DWR 2.0.3 and DWR 3.
Joe.
Re: The specified call count is not a number: null
Very good post. Helped me to solve my problem with testing Web Application. While sending the request-XHR(using httpunit) server response was always 'The specified call count is not a number'. However change of header field 'Content-Type' from 'application/x-www-form-urlencoded' to 'plain-text' solved the problem. Hope this helps someone who is testing web applications powered by Ajax.
Re: The specified call count is not a number: null
Here is what we found :
# "callCount" basically represents the no. of DWR function calls the client is requesting.
# this info is required by DWR so, it can construct a list of calls and execute them one after the other.
# dwr gets the inputstream on the request and reads each lines.. it expects to get parameters and their values like "callCount=1", "scriptName=DiscountCalculator", "methodName=calculateDiscount", "httpSessioId=FH65865GHFG" etc. each time it reads a line (a parameter=value pair).
# in our case the whole string went in as one line "callCount=1scriptName=DiscountCalculatormethodName=calculateDiscounthttpSessioId=FH65865GHFG"....
# so, dwr thought that the value for parameter "callCount" was "1scriptName=DiscountCalculatormethodName=calculateDiscounthttpSessioId=FH65865GHFG"... which obviously, is not a number. so this exception.
# The other thing that one can do is, add a "&" between "parameter=value" pairs. dwr understands that as well and will work fine. like "callCount=1&scriptName=DiscountCalculator&methodName=calculateDiscount&httpSessioId=FH65865GHFG"
Hope understanding this will help you resolve the problem you are facing.
Re: The specified call count is not a number: null
We use Jive Clearspace which uses inside DWR, running on Suse Linux (VMware) and Tomcat in a cluster of two servers. Stopping one as mentioned in DWR discussions didn't help.
Any suggestions how to isolate to area causing the problem?
~Wolfgang