0

I'm using NSURLSession's uploadTaskWithRequest:FromFile: to upload a file in the background. This works, however I'd like to upload only a certain part of the file. So I am trying to get the upload task to only upload a certain range of the file.

I've tried setting the Content-Range and Range headers, e.g.:

[request addValue:@"bytes 2367488-7056719/7056719" forHTTPHeaderField:@"Content-Range"];
[request addValue:@"4689232" forHTTPHeaderField:@"Content-Length"];

However this does not work - the upload session sends the entire file anyway. It preserves the Range header and overwrites the Content-Length header with the entire file's size.

Does anyone know if this can be done?

I've seen references to upload resume not being possible with background upload task, which is essentially the same thing (for instance this question). But no direct reference to sending a certain range.

My only solution thus far is to write a chopped version of the file to disk.. I'd like to avoid that.

Amos Joshua
  • 1,356
  • 15
  • 23
  • I'm looking at the RFC and I see no evident that the Range header can be used for uploads. Can you prove that what you're doing is legal? – matt Nov 17 '17 at 16:17
  • @matt - according to https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.16 one may use a Content-Range with a PUT for a "partial body entity", which is what I'm doing. I've tried setting both Range and Content-Range but neither had any effect – Amos Joshua Nov 17 '17 at 16:56
  • I've amended the question to show the Content-Range header which I believe is more correct – Amos Joshua Nov 17 '17 at 16:57
  • OK but now I've no clear idea what you're doing. Can you show the entirety of the resulting headers? – matt Nov 17 '17 at 16:59

1 Answers1

0

NSURLSession doesn't care about the headers when deciding what to send. It sends the blob you gave it, and in the case of a file, also sets Content-Length to the size of the file (as encoded/compressed, where applicable).

If you want it to send n bytes out of the middle of a file, you need to either write those bytes to their own file or use a streaming request to let you provide only those bytes.

To do the latter approach, create an upload request with a file stream, and use a bound pair of CFStream objects cast to NSStream objects. Then, open the stream, and when the stream delegate is asked to provide more bytes, provide them, and check the return value of the write call to determine how many bytes to skip the next time it asks for bytes.

dgatwood
  • 9,519
  • 1
  • 24
  • 48
  • Just to clarify, the streaming approach will not work with background http transfers, or do you know a way to make that work? Thank you – Amos Joshua Nov 20 '17 at 05:36
  • To the best of my knowledge, streaming requests (created with `uploadTaskWithStreamedRequest:`) are *supposed* to work even in background tasks. The OS dark-wakes/background-relaunches your app to provide a new stream if a retry is necessary. If that isn't working for you, file a bug against the functionality, and then file a second bug against the documentation. I think there might have been a bug in early iOS 7 updates that prevented streamed uploads from working in background sessions, but AFAIK, that was a bug. – dgatwood Nov 20 '17 at 17:57