Thursday, June 5, 2008

HTTP PUT and NSMutableURLRequest

I've been struggling with a problem with NSMutableURLRequest for an article I'm writing about writing Cocoa clients for RESTful web services. Whenever I use HTTP PUT requests, the form parameters do not appear to be getting passed to the server in the request body. If I did two requests, exactly the same, using PUT and POST, the parameters came up in the POST request, but not the PUT request.

I wrote up a sample Ruby on Rails server and Xcode project to demonstrate the problem and submitted it as "PUT parameters not being passed in body when using NSMutableURLRequest". After being told by Apple that this wasn't happening, I re-tested, thinking perhaps that 10.5.3 release had fixed it. Nope! 

Well, I spent several years working at a large software company fixing reported defects. so I knew that merely re-submitting the same post was unlikely to yield a different result.  Defects are generally not closed lightly, and certainly not arbitrarily, so I dug out wireshark and did a little digging.

It turns out, the PUT parameters are being passed in the body. My description of the problem was not technically correct, even though the code I submitted clearly showed a problem with PUT requests. I took the captured requests for a  PUT and a POST request and noticed a difference: the PUT requests had no content-type header. This is clearly a bug, but it's not the bug I described. I'm going to submit a new defect today, but since I've found a simple workaround for the problem, I thought I'd post it. Here it is:

When using NSMutableURLRequest to do an HTTP PUT request, add the following line of code (req is the NSMutableURLRequest):
[req setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
That's all there is to it. If you add this line of code, your PUT requests will work just fine.





8 comments:

Adrian Kosmaczewski said...

I have used the NSMutableURLRequest myself in a previous project with REST APIs and Cocoa clients http://kosmaczewski.net/2008/03/26/playing-with-http-libraries/ (at the bottom of the article) but since I was sending a "content type" header I didn't come accross your bug. Interesting and good to know! :)

Have you tried having your services return "application/plist" instead of raw XML? If you are under control of your service, and if you do it with Python / Django, there's a library that spits "application/plist" for you, it's very handy to deserialize later, just a couple of lines of code and you're done.

See you at WWDC!

Jeff LaMarche said...

Hey, Adrian!

I actually encountered this while writing an article on accessing web services, so I was in complete control of the web service, but that's an interesting point - I'll have to look into how common application/plist is - if it's common enough, I may mention it in the article.

Just a few days left... got closed out of a few of the parties I wanted to attend, unfortunately... had hoped to get into Ars Technica & Gizmodos, but it was way popular, almost as many people watching as able to go. *sigh*

Mark said...

Thanks for this bit of code... I've been trying to get PUT requests to work on the iPhone simulator and post to a page that just outputs the posted variables to no avail.

After changing my Content-Type header to your suggestion, it's working as expected.

Thanks!

trebla said...

I have a different twist of the problem. I need to remove some headers from a request, e.g. Accept etc. It seems like there are no APIs to remove headers. Any suggestions? Thanks.

danimata said...

Great post¡

On the other hand you can also change the mime-types that your Rails application protects against forgery. If you type Mime::Type.unverifiable_types in a console, you can see what types are not checked.

nanduu said...

Thanks....
that was the exact code that I was looking for.....

JeansPilot said...

JeansPilot offers the chance to buy a large variety of men’s and women’s jeans clothing from the world famous Italian Brands.
Online jeans clothing store looks for original fashion clothing sales and clearances of worldwide known designers. We participate in fashion auctions to get the lowest possible price for Top quality Clothes, Shoes and Accessories.
Buy Jeans

h4ns said...

What youre saying is completely true. I know that everybody must say the same thing, but I just think that you put it in a way that everyone can understand. I also love the images you put in here. They fit so well with what youre trying to say. Im sure youll reach so many people with what youve got to say.

Arsenal vs Huddersfield Town live streaming
Arsenal vs Huddersfield Town live streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Wolverhampton Wanderers vs Stoke City Live Streaming
Notts County vs Manchester City Live Streaming
Notts County vs Manchester City Live Streaming
Bologna vs AS Roma Live Streaming
Bologna vs AS Roma Live Streaming
Juventus vs Udinese Live Streaming
Juventus vs Udinese Live Streaming
Napoli vs Sampdoria Live Streaming
Napoli vs Sampdoria Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
Fulham vs Tottenham Hotspur Live Streaming
AS Monaco vs Marseille Live Streaming
AS Monaco vs Marseille Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Alajuelense vs Perez Zeledon Live Streaming
Technology News | News Today | Live Streaming TV Channels