We recently came across an issue with one of our components (ASPRedirector.NET) where a customer who had installed Windows 2003 SP1 started getting errors on their website. The errors only happened if they used a certain encoding in the globalisation settings:
public class Filter : Stream
{
private Encoder encoder;
private Decoder decoder;
private Stream baseStream;
public Filter(HttpContext context)
{
Encoding encoding = context.Response.ContentEncoding;
this.encoder = encoding.GetEncoder();
this.decoder = encoding.GetDecoder();
this.baseStream = context.Response.Filter;
}
public override bool CanRead
{
get { return false; }
}
public override bool CanWrite
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override void Close()
{
baseStream.Close();
}
public override void Flush()
{
baseStream.Flush();
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
// get number of characters that the byte array will be decoded into
int charCount = this.decoder.GetCharCount(buffer, offset, count);
// create character array to hold them
char[] chars = new char[charCount];
// decode byte array into characters
int charCountDecoded = decoder.GetChars(buffer, offset, count, chars, 0);
// we now have characters and can process them
// converting to a string should be the readable content
string content = new string(chars);
// get number of bytes that the character array will be encoded into
int byteCount = encoder.GetByteCount(chars, 0, charCountDecoded, true);
// create byte array to hold them
byte[] bytes = new byte[byteCount];
// encode character array into bytes
int byteCountEncoded = encoder.GetBytes(chars, 0, charCountDecoded, bytes, 0, true);
// write bytes to output stream - this should be exactly what came in
baseStream.Write(bytes, 0, byteCountEncoded);
}
}
This fails if the responseEncoding is set to "iso-8859-15" after Windows 2003 SP1 has been applied but works before SP1 and if a different encoding is used (the default "utf-8" for instance).
So what's the problem? I found a lone post in a newsgroup that explained it:
SP1 of Windows Server introduced a new "feature" in the GlobalizationConfig class called EnableBestFitResponseEncoding.
Effect is that when you set anything other than UTF8 in web.config, e.g. <globalization requestEncoding="iso-8859-1" responseEncoding="iso-8859-1" />, many functions will break (including HttpUtility.URLDecode) with a MethodNotImplementedExecption in the new internal class CodePageNoBestFitEncoding.
Analyzing with the reflector reveals, that new code was added to the HttpResponse.ContentEncoding property:
if (!this._encoding.Equals(Encoding.UTF8))
{
string text1 = this._encoding.GetType().FullName;
if ((config1 == null) || !config1.EnableBestFitResponseEncoding)
{
if (text1 == "System.Text.MLangCodePageEncoding")
{
this._encoding = Encoding.GetEncoding("mlang");
}
else if ((text1 == "System.Text.CodePageEncoding") || (text1 == "System.Text.Latin1Encoding"))
{
int num1 = this._encoding.CodePage;
this._encoding = new CodePageNoBestFitEncoding(num1);
}
}
Assuming that EnableBestFitResponseEncoding is false by default, this property will return a new instance of CodePageNoBestFitEncoding when you set a responseEncoding="iso-8859-1" in web.config.
Many of the normal Encoding methods in CodePageNoBestFitEncoding will throw the MethodNotImplemented exception which explains the above mentioned bahavior.
Some additional analysis reveals that there is a new attribute for <globalization > called "enableBestFitResponseEncoding". After setting this attribute to "true", everthing works again as normal with a responseEncoding other than UTF8.
A search in Microsoft's site for "enableBestFitResponseEncoding" returns 0 hits. Thank you Microsoft!