Bill Lovett

Using Deflate Compression in Ruby

Posted on April 19th, 2006

When I realized that my homemade Ruby-based blogging script wasn't compressing pages, I wanted to do something about it. Normally this is something that could be handled at the web server level-- under Apache 1.3 that would mean mod_gzip, under Apache 2 it would probably mean mod_deflate. In a shared hosting setup, neither of those may be available. It falls to your application to handle the details by itself.

The Accept-Encoding HTTP header reveals which compression schemes a particular browser supports. Opera, Internet Explorer, Firefox, and Safari all know how to handle gzip compression and deflate compression. People have tried to compare the two to answer seemingly weighty questions like, "Which is better, gzip or deflate?" but the results seem pretty close so a better question for my purposes is, "Which is easier to implement?"

Ruby's zlib library supports both types of compression, and deflate ended up being the winner. Provide a string, call the deflate method on it, get back the compressed version. Just like this:

unless @cgi.accept_encoding.nil? or
  @cgi.accept_encoding.index("deflate") == nil then
  deflated = Zlib::Deflate.deflate(content,9)
  @cgi.out("Content-Encoding"=>"deflate",
           "Vary"=>"Accept-Encoding",
           "Content-type"=>"#{content_type}; charset=utf-8")
	   {deflated[2..-5]}
else
  @cgi.out("Content-type"=>"#{content_type}; charset=utf-8")
  {content}
end

So why the [2..-5] there? Initially I didn't have that, and discovered that Firefox and Opera could understand the output but Internet Explorer and Safari could not. After a lot of thrashing around, I ended up writing a test script in PHP and then comparing its output to an equivalent script in Ruby:

header('Content-Encoding: deflate');
$mystring = "testing testing";
$compressed = gzdeflate($mystring, 9);
print $compressed;

The output of the PHP script and the Ruby script didn't match, but once I trimmed off a bit from the front and the end of the Ruby scripts output, everything was wine and roses.

It seems that there's a header and a footer to the deflated output that needed to get stripped away. Not that there was any mention of this in the Ruby zlib documentation. Weak.

Back to the index of all blog entries