Memory issues with NSMutableURLRequest's setHTTPBody: method in iPhoneOS 2.1

The iPhone developers at my work have been tearing their hair out over the last few days, trying to resolve the last few memory issues in our iPhone application before we send it off for approval by Apple. One of the problem areas they’ve noticed is when a photo is uploaded to our service via HTTP POST (both from the camera and otherwise).

Not sure who had the bright idea, but one of the developers decided to try passing in the HTTP body as an NSInputStream (via -[NSMutableURLRequest setHTTPBodyStream:]), rather than as NSMutableData (via -[NSMutableURLRequest setHTTPBody:]). Magically, this seems to have solved the memory leak issues.

Unfortunately, it created another issue.

You might remember that 3 months ago I wrote an article on how much of a pain in the arse it was to accept HTTP POST requests from user agents specifying a Transfer-Encoding HTTP header value of chunked (resulting in a POST request with no Content-Length header). In that article, I proposed a solution using Apache 2 and mod_proxy’s proxy-sendcl option to get things working again. This worked fine for our J2ME clients, but when our iPhone application started blowing chunks at us, our server crapped out with the dreaded 500 error I thought I’d fixed for good:

Chunked Transfer-Encoding is not supported

After whipping out Wireshark, we realised that there was a tiny difference between between what our J2ME client was doing and what the iPhone was doing.

This is the header the J2ME app was sending:

Transfer-Encoding: chunked

And this is the header the iPhone was sending:

Transfer-Encoding: Chunked

As much as I’d like to think the different casing of chunked and Chunked wouldn’t affect the behaviour of mod_proxy, it seems it does. Fortunately, we can work around this problem too by using Apache’s mod_headers module. This allows us to do the following:

RequestHeader edit Transfer-Encoding Chunked chunked early

When combined with the solution from my previous article, this leaves us with the following complete solution:

Apache configuration to reconstitute “chunked” HTTP requests
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
29
30
31
32
33
ProxyRequests Off

<Proxy http://localhost:81>
  Order deny,allow
  Allow from all
</Proxy>

Listen 80

<VirtualHost *:80>

  RequestHeader edit Transfer-Encoding Chunked chunked early

  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>