Monday, March 10, 2008

Sun's version of "640k": 2GB ServletResponse Content-Length

Whether or not Bill Gates ever actually said that 640k should be enough for everyone, Sun certainly seems to have recreated their own version with javax.servlet.ServletResponse.

I was working on a custom Java servlet to return files out of a zip file stored on a web server (ZipServlet), was trying to implement RFC 2616 as completely and accurately as possible, and noticed an issue with the setContentLength(int len) method. Java's int data type is 32 bits, and all Java data types are signed, meaning that this imposes a maximum declared response length of 2,147,483,647 bytes, or 2 GB.

To be fair, this was probably generous back in 1998. I believe the first 2GB+ file I ever downloaded was a Linux installation DVD .iso, and even today, this type of use is still probably a bit out-of-place for a Java Servlet.

What makes this interesting is the number of other Java classes that already utilize longs (64-bit signed) over ints. java.io.File and java.util.zip.ZipEntry are two examples that come to mind.

I did find a bug entry on this issue, http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4187336, opened in 1998. The evaluator's comment is a bit discouraging. I understand the need to maintain API compatibility, but this didn't seem to prevent Sun from fixing a similar bug elsewhere. (I recalled - but am now unable to locate - another java.* class with 2 methods something like int getLength() and long getLongLength(), the later having been introduced later to overcome the size limitation of an int.)

Fortunately, I did find one possible work-around:

javax.servlet.http.HttpServletResponse response;
long length;
…
if(length <= Integer.MAX_VALUE){
  response.setContentLength((int)length);
}else{
  response.addHeader("Content-Length", Long.toString(length));
}

Unfortunately, it probably only serves as informational to the client. The servlet container probably won't make use of this, and resort to sending the content as chunked.

2 comments:

Matt Rutkowski said...

While exploring the possibility of a server implementation using HTTP 1.1 to stream large video content I was dismayed to find this had never been addressed. Especially since HTTP/1.1 range requests allow a client to request portions of a resource. It would seem the complete solution would be to provide a long content length and additional information (normalized via Java APIs) about the available, optimal and cached chunks. Consider a home media server that serves up BlueRay HD movies around a home network. Of course there are other protocols (e.g. RTP), but why restrict HTTP especially with 1.1 features and when there is no need for "lossy" packet assumptions and retry is available.

Phani said...

I too agree that it's a very disappointing response from the reviewer. Things have changed a lot in technology since that bug was posted and the response to it.
It's definitely high time Sun digs back into this and have this fixed.
I posted a comment on the bug on their site, and would ask my entire sea of Java developer friends to do the same.
Atleast that might cause Sun to scratch its head