ajaxwcfjsongzipwebhttpbinding

WCF service returns incorrect Content-Length when using gzip encoding


I have a web page containing a filtering text box and a list box. Modifications to the text box trigger an AJAX request, which returns an array of values with which to populate the list box.

I had problems with these calls failing sometimes, dependent on the size of the data returned. Small-sized returned data would result in an error, large-size data was returned and processed succesfully.

This problem only happens when I use a jQuery version greater than 4.2. If I use jQuery version 4.2, I don't have the problem.


Here is the code of the call:

        jQuery.ajax(
            {
                cache: false,
                url: "../Services/CmsWebService.svc/GetAvailableVideosForCompany",
                type: "GET",
                complete: function (jqXHR, textStatus) {
                    var responseText = jqXHR.responseText;
                    jQuery('#debugConsole').text(responseText);
                    availableVideosPopulationState.isRunning = false;
                    setTimeout(populateAvailableVideosListBox, 100);
                },
                data: { "companyIdString": queryParameters.companyIdField,
                    "textFilter": queryParameters.filterText
                },
                dataType: 'json',
                error: function (jqXHR, textStatus, errorThrown) {
                    var errorString = 'Error thrown from ajax call: ' + textStatus + 'Error: ' + errorThrown;
                    alert(errorString);
                },
                success: function (data, textStatus, jqXHR) {
                    populateVideoListFromAjaxResults(data);
                }
            }
             );

Here is the contents of the debug console if two elements are returned:

{"d":[{"__type":"ListEntry:#WebsitePresentationLayer","Text":"SOJACKACT0310DSN1.mpg - [SOJACKACT0310DSN1]","Value":"5565_5565"},{"__type":"ListEntry:#WebsitePresentationLayer","Text":"SOJACKACT0310DSN1Q.mpg - [SOJACKACT0310DSN1Q]","Value":"5566_5566"}]}

But if one element is returned:

{"d":[{"__type":"

So, of course, we get an "Unterminated String Constant" error.


I have done some investigation using fiddler.

On all responses (even the succesful ones), fiddler displayed an error:

Fiddler has detected a protocol violation in session #n1.

Content-Length mismatch: Response Header indicated n2 bytes, but server sent n3 bytes.

If the response header indicates a size greater than than actual size, then the results could still be interpreted by the browser.

If the response header indicates a size less than the actual size, then the browser could not interpret the results.

The obvious assumption to make there is that the response handling code reads the Content-Length header and doesn't read any more data than that stipulated in the length.

The next step in my investigation is to compare the request/response headers for jQuery version 1.6.1 (which breaks) and version 1.4.2 (which does not break).

jQuery 1.6.1 request header:

GET /Web/Services/CmsWebService.svc/GetAvailableVideosForCompany?companyIdString=2&textFilter=3DSBDL2&_=1315869366142 HTTP/1.1
X-Requested-With: XMLHttpRequest
Accept: application/json, text/javascript, */*; q=0.01
Referer: http://localhost:52200/Web/Admin/PlayerGroupEditor.aspx?groupid=76
Accept-Language: en-au
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Host: localhost:52200
Connection: Keep-Alive
Cookie: .ASPXAUTH=CE853BBD860F40F0026400610074006D006500640069006100310000002B5387799D71CC01002B5B5D62C771CC0100002F0000006B119589A7305098A560E57515498C56ECB332035F300427CDA2B28205D5E6B6

jQuery 1.6.1 response headers

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Mon, 12 Sep 2011 23:02:36 GMT
X-AspNet-Version: 4.0.30319
Content-Encoding: gzip
Content-Length: 140
Cache-Control: private
Content-Type: application/json; charset=utf-8
Connection: Close

And here is the request header when I use jQuery 1.4.1. Notice that the Accept header is different from the jQuery 1.6.1 value.

GET /Web/Services/CmsWebService.svc/GetAvailableVideosForCompany?_=1315870305531&companyIdString=2&textFilter=3DSBDL2 HTTP/1.1
Referer: http://localhost:52200/Web/Admin/PlayerGroupEditor.aspx?groupid=76
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Accept: application/json, text/javascript, */*
Accept-Language: en-au
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Host: localhost:52200
Connection: Keep-Alive
Cookie: .ASPXAUTH=CE853BBD860F40F0026400610074006D006500640069006100310000002B5387799D71CC01002B5B5D62C771CC0100002F0000006B119589A7305098A560E57515498C56ECB332035F300427CDA2B28205D5E6B6

And the response back to jQuery 4.1.1:

HTTP/1.1 200 OK
Server: ASP.NET Development Server/10.0.0.0
Date: Mon, 12 Sep 2011 23:31:46 GMT
X-AspNet-Version: 4.0.30319
Content-Length: 131
Cache-Control: private
Content-Type: application/json; charset=utf-8
Connection: Close

So the obvious difference is that when the call is made via jQuery 1.6.1 the response is compressed using gzip, and when the call is made via jQuery 1.4.2 the response is not compressed.


So now I can do a work around solution, which is to override the default Accept header to ensure it does not contain the "q=0.01" string. (The best explanation I can find for "q=0.01" is here, but I fail to see why my service implementation is interpreting this as a request to zip up the response badly.)

        // Make the AJAX call, passing in the company id and the filter string
        jQuery.ajax(
            {
                accepts: 'application/json, text/javascript, */*',
                cache: false,
                url: "../Services/CmsWebService.svc/GetAvailableVideosForCompany",
                type: "GET",
                complete: function (jqXHR, textStatus) {
                    var responseText = jqXHR.responseText;
                    jQuery('#debugConsole').text(responseText);
                    availableVideosPopulationState.isRunning = false;
                    setTimeout(populateAvailableVideosListBox, 100);
                },
                data: { "companyIdString": queryParameters.companyIdField,
                    "textFilter": queryParameters.filterText
                },
                dataType: 'json',
                error: function (jqXHR, textStatus, errorThrown) {
                    var errorString = 'Error thrown from ajax call: ' + textStatus + 'Error: ' + errorThrown;
                    alert(errorString);
                },
                success: function (data, textStatus, jqXHR) {
                    populateVideoListFromAjaxResults(data);
                }
            }
             );

So after all this investigation, the remaining question is why is there a disparity between the content length header and the actual content length when the response is GZIP compressed?

I'm using a WCF service with webHttpBinding.


Solution

  • First of all-Very good question. This question provided me with enough information to reach a solution for my problem.

    I had a similar issue, and posting the fix here- so that it might help someone.

    1. Ajax get & post requests were returning null in IE

    2. Was working fine in rest of the browsers, but saw the 'Response Header indicated n bytes, but server sent nn bytes' message in fiddler for the request.

    The obvious assumption to make there is that the response handling code reads the Content-Length header and doesn't read any more data

    I think so too!

    In this case, I was clear with one thing. Something was tampering the request/response. I tried switching back to older version of jQuery (as mentioned in your question), but that didn't help.

    Fix- I opened up the web config of my application, and read through it. There was a 'RadCompression Module' from telerik included in modules, and on removal of it everything started working fine.

    RadCompression module is known to be buggy and cause multiple issues by compressing the Response.

    If you are having similar issues, try checking what might be intercepting your request/response.