/ScriptResource.axd : Invalid viewstate

Yet again I am back to this topic. Internet Explorer 8 (IE 8) is causing a lot of intermintent "/ScriptResource.axd : Invalid viewstate" errors with our web site. Since our web site makes automatic error logs that send us for the pages with error I have the request information. One thing I noticed was that we are getting a lot of request that look like this: /ScriptResource.axd?d=vSlJhKauG_vkeppFuk4O%2fseparator.gif A correct reference to /ScriptResource.axd looks a lot like this: /ScriptResource.axd?d=KPD5hEMt5pl2DUlO-HtW7uGyz9QToptIaomjT4Xh2Elw9iR4V4XA10Vyl8rymXiSQ2llJ9D-oDEkrTRdelC7CR5Q4yGTQBrdaeyHxDcCQ3w1&t=633251016437037680 Notice that there is a query string token that starts d= with a value that is a encrypted or hashed value. My hunch was that on the page request the web server was sending back HTML somewhat like this:
<script src="/ScriptResource.axd?d=KPD5hEMt5pl2DUlO-HtW7uGyz9QToptIaomjT4Xh2Elw9iR4V4XA10Vyl8rymXiSQ2llJ9D-oDEkrTRdelC7CR5Q4yGTQBrdaeyHxDcCQ3w1&amp;t=633251016437037680" type="text/javascript"></script>
However, the d value was encrypted in such a way that browser couldn't parse the token correctly. Maybe the token contained a raw > or a quote? So I started up reflector and start looking in the CLR for the line of code that outputted this string. Note that this is CLR 2.0: I found that line in: Assembly System.WebExtensions.dll, Namespace System.Web.Handlers, in a class called ScriptResourceHandler, which implemented the GetScriptResourceUrl of the System.Web.Handlers.IScriptResourceHandler interface. The code in c# looks like this:
      if (assembly.GlobalAssemblyCache)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(first.Name);
            builder.Append(',');
            builder.Append(first.Version);
            builder.Append(',');
            if (first.CultureInfo != null)
            {
                builder.Append(first.CultureInfo);
            }
            builder.Append(',');
            builder.Append(HexParser.ToString(first.GetPublicKeyToken()));
            name = builder.ToString();
        }
        else
        {
            name = first.Name;
        }
        if (_absoluteScriptResourceUrl == null)
        {
            _absoluteScriptResourceUrl = VirtualPathUtility.ToAbsolute("~/ScriptResource.axd");
        }
        str = string.Concat(new object[] { _absoluteScriptResourceUrl, "?d=", ScriptResourceHandler.EncryptString((zip ? (notifyScriptLoaded ? "Z" : "z") : (notifyScriptLoaded ? "U" : "u")) + name + "|" + resourceName + "|" + culture.ToString()), "&t=", second.Ticks });
Notice that the first letter of the d value is a flag for requesting zipped and flagging the notification of the script loading, the next part is the assemble name that the resource is in (delimited by a |), then the culture string. This is all sent to Page.EncryptString to encrypt.
internal static string EncryptString(string s)
{
    byte[] bytes = Encoding.UTF8.GetBytes(s);
    return HttpServerUtility.UrlTokenEncode(MachineKeySection.EncryptOrDecryptData(true, bytes, null, 0, bytes.Length));
}
Page.EncryptString does these things: 1) UTF8 encodes the string to a byte array 2) Encrypts the byte array using the Machine Key 3) Calls the UrlTokenEncode method of HttpServerUtility MSDN defines UrlTokenEncode as: Encodes a byte array into its equivalent string representation using base 64 digits, which is usable for transmission on the URL. So I took a look at UrlTokenEncode method, which takes a Byte array and calls ToBase64String(). The output of ToBase64String() then is parsed for characters that would cause problems in a value of a URL querystring parameters. These characters are subsituted for a charcters that are safe for the querystring value. Looking over the character set of Base64 there is upper and lower case alpha, all the numbers, and +, / =. Note: http://www.ietf.org/rfc/rfc1421.txt. In UrlTokenEncode + and / are hanlded correctly. However, Base64 uses the = (equal) as padding. Which means it should only be on the end of the string, and the UrlTokenEncode method handles the = at the end. However, there is a very odd case in the UrlTokenEncode method. If there is an = in the middle of the string Base64 string then an = is outputted. When does Base64 return a = in the middle of the string? And if this is the case would this cause IE not to work correctly? {6230289B-5BEE-409e-932A-2F01FA407A92}

Comments

  1. I'm seeing this on some of my sites too.

    ReplyDelete
  2. This is a very detailed article on the root cause of this issue and it is surprising that not many people have visited this. There's post at https://connect.microsoft.com/IE/feedback/ViewFeedback.aspx?FeedbackID=467062 which, I think, discusses this very issue and it seems is related to IE8 [My site's facing this too]. However the workaround is not working since my pages do have a Content-Type: text/html; charset=utf-8 set.

    regards
    Harish

    ReplyDelete
  3. Well, it seems to me like bug in .net, why it appear only in IE8?

    ReplyDelete
  4. Anyone has any luck with this? I'm seeing the same issue as well. Only with IE 8.

    Here is a sample request that is bad:

    2009-08-27 18:25:33 W3SVC1035779783 192.168.2.20 GET /ScriptResource.axd d=v-8ylczdJ9KxecFpVmASrtD7QB1aF409Rqeqq9uxqLbm4HY0bkZWABJyCjZePu2G1qoellspacing= 443 - 69.87.137.139 Mozilla/4.0+(compatible;+MSIE+8.0;+Windows+NT+5.1;+Trident/4.0;+InfoPath.2;+.NET+CLR+2.0.50727;+.NET+CLR+1.1.4322;+OfficeLiveConnector.1.3;+OfficeLivePatch.0.0;+.NET+CLR+3.0.4506.2152;+.NET+CLR+3.5.30729) 302 0 0

    ReplyDelete
  5. you should set the content-type in the http header to utf-8 and text/html

    i did it in the web.config.
    it does minify the bug but does not totally resolve it...

    ReplyDelete

Post a Comment

Popular posts from this blog

Simple WP7 Mango App for Background Tasks, Toast, and Tiles: Code Explanation

Yet once more into the breech (of altered programming logic)

Error : /ScriptResource.axd : Invalid viewstate.