Brandon J. Boone
Brandon J. Boone

Reputation: 16472

GZipping Javascript from .ashx returns decoding error in browser

Background

I'm setting up a generic handler to:

I'm working in MonoDevelop v2.8.2 on OSX 10.7.2

Problem

Since I want to Cache the GZipped version, I need to GZip without using a response filter

Using this code, I can compress and decompress a string on the server successfully, but when I serve it to the client I get:

Relevant Code

string sCompiled =null;
if(bCanGZip)
{
    context.Response.AddHeader("Content-Encoding", "gzip");
    bHasValue = CurrentCache.CompiledScripts.TryGetValue(context.Request.Url.ToString() + "GZIP", out sCompiled);
}

//...
//Process files if bHasVale is false
//Compress result of file concatination/minification

//Compression method
public static string CompressString(string text)
{
    UTF8Encoding encoding = new UTF8Encoding(false);

    byte[] buffer = encoding.GetBytes(text);
    using(MemoryStream memoryStream = new MemoryStream()){
        using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
        {
            gZipStream.Write(buffer, 0, buffer.Length);

        }
        memoryStream.Position = 0;

        byte[] compressedData = new byte[memoryStream.Length];
        memoryStream.Read(compressedData, 0, compressedData.Length);

        byte[] gZipBuffer = new byte[compressedData.Length + 4];
        Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length);
        Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4);
        return Convert.ToBase64String(gZipBuffer);

    }

}

//...
//Return value
switch(Type){
    case FileType.CSS:
        context.Response.ContentType = "text/css";  
        break;
    case FileType.JS:
        context.Response.ContentType = "application/javascript"; 
        break;
}
context.Response.AddHeader("Content-Length", sCompiled.Length.ToString());
context.Response.Clear();

context.Response.Write(sCompiled);  

Attempts to Resolve

Since I'm not sure what the lines:

byte[] gZipBuffer = new byte[compressedData.Length + 4];
Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length);
Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4);

are accomplishing, I tried removing them.

I tried playing with different Encodings/options.

At this point I'm really not sure how to attack the problem since I don't know the source of the error (Encoding/Compression/other).

Any help would be very appreciated!

Other Resources I've found on the subject

Upvotes: 3

Views: 1303

Answers (1)

Brandon J. Boone
Brandon J. Boone

Reputation: 16472

This is one of those things where once you explain you problem, you quickly find the answer.

I need to write out the response as Binary. So modifying the compression algorithum to return a byte array:

public static byte[] CompressStringToArray(string text){
    UTF8Encoding encoding = new UTF8Encoding(false);

    byte[] buffer = encoding.GetBytes(text);
    using(MemoryStream memoryStream = new MemoryStream()){
        using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
        {
            gZipStream.Write(buffer, 0, buffer.Length);

        }
        memoryStream.Position = 0;

        byte[] compressedData = new byte[memoryStream.Length];
        memoryStream.Read(compressedData, 0, compressedData.Length);

        return compressedData;
    }
}

and then calling:

//Writes a byte buffer without encoding the response stream
context.Response.BinaryWrite(GZipTools.CompressStringToArray(sCompiled));

Solves the issue. Hopefully this helps others who will face the same problem.

Upvotes: 3

Related Questions