Fraser Speirs ([info]fraserspeirs) wrote,
@ 2006-04-24 09:47:00
Previous Entry  Add to memories!  Tell a Friend  Next Entry
HTTP Nerdery, or, Why NSURLConnection Sucks For POST.
I spent some time at the weekend re-plumbing a major component of FlickrExport. There's one class that does all the hard work of hauling your images up to Flickr, it's called FKPhotoUploadRequest and it uses NSURLConnection behind the scenes. NSURLConnection is a great class and I love it to bits, at least when I'm attempting an HTTP GET. FlickrExport, unfortunately but necessarily, uses HTTP POST to send images and NSURLConnection is distinctly buggy when used in this mode of operation.

At the nerd level, the problem can be seen by running tcpflow whilst uploading in FlickrExport. Just occasionally, you'll see the headers being sent and then .... nothing. Where there should be a very large MIME-encoded body, there's just nothing. At the user level, the problem manifests as FlickrExport just stopping and never making progress. This is because it's waiting on NSURLConnection to tell it that the post succeeded or failed. When this bug bites, the connection goes off into an interminable waiting state and never calls back success or failure. It's not that NSURLConnection is erroring and we're not catching it.

It appears to be a total heisenbug. I have innumerable support emails saying things like "FlickrExport stalls at image 7!" or "I can never get past image 2!!" - each time a different number, but the same problem.

Anyway, I took matters into my own hands and wrote a replacement class, built on the super-duper SmallSockets. It's not a perfect replacement - it's mostly designed around the needs of uploading rather than downloading - but it's already more reliable than NSURLConnection for this problem.

Another flaw in NSURLConnection, and this time by design, is that it only reports progress in retrieving large objects from the server. It tells you nothing until it's sent the entire NSURLRequest and only then starts to call back about the number of bytes that have come down. When you're POSTing requests containing images which may be 3-4Mb, this can be a very long delay between starting the upload and getting any feedback. This is why FlickrExport doesn't report to you the progress of uploading any individual image, only the overall progress. I don't like this and users don't like it either.

In my new HTTP class, I made it call back every time it uploads 10k of the request, as well as calling back on download progress. This means we can do a fine-grained progress meter for each image as it uploads as well as an overall progress meter for the batch.



(7 comments) - (Post a new comment)


[info]sajego
2006-04-24 12:08 pm UTC (link)
I have seen this bug, I figured it was just my internet connection being glitchy. Can't wait to try your fix :)

(Reply to this)


[info]jazzmasterson
2006-04-24 04:12 pm UTC (link)
This is why FlickrExport doesn't report to you the progress of uploading any individual image, only the overall progress. I don't like this and users don't like it either.

So that's why! I figured it had to be something like that...

(Reply to this) (Thread)


[info]fraserspeirs
2006-04-24 05:20 pm UTC (link)
Yeah, I have had a bug open with Apple about this for some time (and the other part where NSURLConnection does't work in a modal runloop, leading to some elaborate haques in FE) but neither are going to appear on a rapid timescale, certainly not before Leopard. Time to engineer around them.

(Reply to this) (Parent)

Core HTTP
[info]benzado
2006-04-24 09:22 pm UTC (link)
Did you look at the CFHTTP calls (what LJKit uses)?

(Reply to this) (Thread)

Re: Core HTTP
[info]fraserspeirs
2006-04-24 09:33 pm UTC (link)
No, I didn't - primarily because I already had 95% of the solution implemented from a previous project. Otherwise, I definitely would have.

(Reply to this) (Parent)(Thread)

Re: Core HTTP
[info]benzado
2006-04-25 02:47 am UTC (link)
Sound reasoning... I don't get a commission for promoting CFHTTP, I was just wondering if it was any better/worse for this sort of thing.

(Reply to this) (Parent)(Thread)

Re: Core HTTP
[info]fraserspeirs
2006-04-25 05:40 am UTC (link)
The two big wins with NSURLConnection are that: (a) it's integrated with the runloop, so you don't have to manage your own thread and (b) it transparently detects and uses the system-wide proxy settings.

With CFHTTP, I think you have to handle both yourself? Of course, with my approach, you have to handle both and handle the HTTP protocol messages, but they're not the most complex messages ever. Generating the MIME-encoded body is harder, and you have to do that yourself, even with NSURLConnection.

(Reply to this) (Parent)


(7 comments) - (Post a new comment)

Create an Account
Forgot your login or password?
Login w/ OpenID
English • Español • Deutsch • Русский…