<< January 23, 2008 | Home | January 25, 2008 >>

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.