"Transfer-Encoding: chunked", or, Chunky HTTP!
August 8th, 2008
Providing a web service for a bunch of browsers is a relatively straightforward affair. It’s really only once you jump out of the back-end and into the front-end side of things where issues like browser incompatibilities start to become a problem. Thankfully, I feel like I’m in the position where I think I’ve got my head wrapped around what’s involved in providing solutions to these problems.
And then mobile phones came along.
The service I’m working on at the moment is consumed by a bunch of clients, including but not limited to web browsers, WAP browsers, the Flash player, iPhones, J2ME devices. It’s the last one that’s causing headaches at the moment.
You see, despite the fact that HTTP/1.1 is about 9 years old, not all web servers support the features that were introduced. The particular one I’m talking about is chunked tranfer encoding, but I’m sure there are many others.
To give you a general idea, the HTTP implementations on many mobile handsets will decide to use a chunked transfer encoding if the payload of a PUT/POST request is over an arbitrary threshold. This causes issues with servers like Nginx, Lighttpd, Mongrel, and Thin, since most of those assume that an incoming HTTP request with a payload will also include a Content-Length header.
Well guess what? As of 9 years ago, that hasn’t been the case.

Take a look at this request:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
POST /search.json HTTP/1.1 User-Agent: curl/7.16.4 (i486-pc-linux-gnu) libcurl/7.16.4 OpenSSL/0.9.8e zlib/1.2.3.3 libidn/1.0 Host: ooboontoo Accept: */* Transfer-Encoding: chunked Content-Type: multipart/form-data; boundary=----------------------------ab5090ac7869 92 ------------------------------ab5090ac7869 Content-Disposition: form-data; name="query" zoooom ------------------------------ab5090ac7869-- 0 |
Notice anything? If not, try and find a Content-Length header. Pre-HTTP/1.1 you’d expect to get an HTTP 411 error (length required), but after HTTP/1.1 it’s pretty clear what the HTTP/1.1 applications are obliged to do:
All HTTP/1.1 applications that receive entities MUST accept the “chunked” transfer-coding (section 3.6), thus allowing this mechanism to be used for messages when the message length cannot be determined in advance.
That’s why I find it so surprising that hacks are involved in allowing mobile clients to POST/PUT to what I’d traditionally thought of as HTTP/1.1 compliant web servers.
But anyway, you want to see the solution right?
Well, our initial solution involved Gerald writing a little web server in Python which went by the name of “Dechunker”. You can imagine what it did, but we quickly found that while it was the simplest way to avoid the problem, it also meant that over time we would end up needing to implement the functionality that was already available in most other web servers. Servers like Apache2 and Lighttpd have become incredibly hardy over the years, and we’re not going to achieve that overnight.
So I then took another look at Apache2, knowing that some modules do support chunked transfer encoding while others don’t. What I discovered was that Apache’s mod_proxy module could be used in front of anything that doesn’t support chunked encoding, since it can be configured to “dechunk” requests before passing them to a backend.
It looks a little something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
ProxyRequests Off
<Proxy http://localhost:81>
Order deny,allow
Allow from all
</Proxy>
<VirtualHost *:80>
SetEnv proxy-sendcl 1
ProxyPass / http://localhost:81/
ProxyPassReverse / http://localhost:81/
ProxyPreserveHost On
ProxyVia Full
<Directory proxy:*>
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
Listen 81
<VirtualHost *:81>
ServerName ooboontoo
DocumentRoot /path/to/my/rails/root/public
RailsEnv development
</VirtualHost> |
As you can see I’ve got Apache2 listening on port 80, which uses the “proxy-sendcl” environment variable available in mod_proxy to repack the HTTP body and add a Content-Length header to the request. This request is then passed back to a virtual host running on port 81, which is configured to use Phusion Passenger.
Turns out it’s pretty simple, and from what I’ve seen there haven’t been any negative performance impacts by proxying all requests. It’s not a permanent solution, and as soon as Phusion Passenger fixes the chunked encoding bug, I’ll drop mod_proxy from our configuration.
Hope that helps someone!
September 5th, 2008 at 10:46 AM
ya, i’ve dealt with this a few times before. and again now. my problem is that there’s a nice compliant apache2 server sitting there waiting to properly handle my chunks, but in front of it is a big fat stupid squid proxy. squid claims to support chunked encoding, but very promptly eats sht when I post through it. *sigh solution? none. I don’t have access to the server, I’m just the j2me developer.
there’s a lot of talk about why this happens and some possible issues with the sun wtk emulator sending poorly formatted chunks, but it still happens on a real phone, so thats kind of moot.
oh ya, real solution… use http 1.0. then it works like a charm because chunked isn’t supported! tada! except that you can’t specify the http version on an actual phone.
/frustrated
September 15th, 2008 at 05:32 PM
@pandora: One solution (albeit dirty) would be to do the same thing I’m doing…use mod_proxy to repackage the requests as regular non-chunked POST requests. To do this, your setup would be as follows:
Makes me cringe, but at least it would work with minimal fuss.
October 16th, 2008 at 11:25 AM
Don’t forget:
RequestHeader edit Transfer-Encoding Chunked chunked early
For iPhone support :)
October 16th, 2008 at 07:48 PM
@Dave: Yep, I’m actually writing that up as a separate article right now :).
November 14th, 2008 at 05:18 AM
Great piece of information. Too bad that it took quite a lot of googling to get here, because without figuring out that mod_proxy would do the dechunking, I wasn’t able to find neither your page nor any outher useful source. I could only find fellow j2me developers complaining about this very same problem on public forums without any usable answer.
I hope my comment will help google to find this page when someone is looking for a solution how to dechunk POST requests directed to CGI scripts by j2me MIDlets ;)).
November 28th, 2008 at 09:43 PM
@Atleta: I’ll add a new article linking to this one, with a hopefully less cryptic title :).
March 11th, 2009 at 06:41 AM
Thanks for this idea, it certainly helped us. There’s a slight epilogue to our story, based on a problem with using the 1.0.3 MIDP environment (nothing later available on the Mac :I ). So if someone is having funny IOExceptions, this might be useful:
http://www.screditcrunch.com/?p=86
March 13th, 2009 at 09:10 AM
Thanks very much for this post! Was extremely helpful.
May 1st, 2009 at 05:14 AM
Hi there. Is possible that this problem cause php to receive an incomplete image? Thanks.
May 4th, 2009 at 01:45 PM
Hi Gardner,
Usually if your web server (or application server running within your web server) does not support “chunked” transfers, it will respond with a “411 Length Required” header. I’ve not seen anything accept partial POST requests, but I wouldn’t be surprised. Your best bet would be to use something like Wireshark to follow the HTTP connections being made to and from your client and server.