Using URLSession with PUT and fragments of Content-Range in Swift

I am still learning Swift 4. I’ve successfully managed to call the Microsoft OneDrive API to fetch user information and create basic text files using URLSession.

For files over 4mb, you have to upload them in fragments. What I can’t work out how to do is use URLSession to do this.

https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/driveitem_createuploadsession

The example request format is:

PUT https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337
Content-Length: 26
Content-Range: bytes 0-25/128

<bytes 0-25 of the file>

I’ve been trying to find examples of this online, but not having much luck.

@jthake Thanks very much for your question!

By sending fragments, do you mean sending a multi-part request? If so, perhaps try this (in this example, I’m uploading an image):

let request  = URLRequest(url: URL(string: "https://myURL.com")!)
request.httpMethod = "PUT"
let boundary = "Boundary-\(UUID().uuidString)"//not sure if this line is necessary
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

Perhaps that will get you started.

I hope this helps.

All the best!

Hi @jthake,
on the link you have posted, it says

Upload bytes to the upload session

To upload the file, or a portion of the file, your app makes a PUT request to the uploadUrl value received in the createUploadSession response. You can upload the entire file, or split the file into multiple byte ranges, as long as the maximum bytes in any given request is less than 60 MiB.

The fragments of the file must be uploaded sequentally in order. Uploading fragments out of order will result in an error.

Note: If your app splits a file into multiple byte ranges, the size of each byte range MUST be a multiple of 320 KiB (327,680 bytes). Using a fragment size that does not divide evenly by 320 KiB will result in errors committing some files.

There are a couple of takeaways from that,

  1. The max file size in one go or a file fragment is 60MB not 4 MB
  2. If you split the file into byte ranges, then the size of each byte range is a multiple of 320KB otherwise it will result in an error.

If you do still want to upload the data in fragments, then you will have to do so in a loop, where the first loop will send data as you have above and you wait for a 202, and you ensure that you get a JSON response with the content

{
  "expirationDateTime": "2015-01-29T09:21:55.523Z",
  "nextExpectedRanges": ["26-"]
}

where the nextExpectedRanges tells you what you need to send because it can ask for arbitrary ranges like


{
  "expirationDateTime": "2015-01-29T09:21:55.523Z",
  "nextExpectedRanges": [
  "12345-55232",
  "77829-99375"
  ]
}

Most importantly, you would be using the POST method rather than PUT

cheers,

Jayant

Thanks for the info. Sorry thats a nice catch on the 60Mb. I’m uploading videos recorded on teh iphone so my tests have shown i’ll hit that pretty quickly so may as well do for all.

The question I have is, i’ve quickly spiked this together using URLSession uploadTask on github.

Is there a way where it is looping over each fragment that rather than using a sleep (line 201) I can have it wait for a response? If I don’t have the sleep in there, they get uploaded in the wrong order and start to fail.

At some point I’ll want in the UI a progress bar so I’m assuming I have to call back on the main thread using

DispatchQueue.main.async {

Sorry new to this and learning through digging into documentation and the video courses on here.

Thank you

Hi @jthake,
Yes, if you want to update the UI, you will have to do that on the main thread as you have correctly found.

I would also recommend that you have a look at OperationQueues or another way is basically to create a queue or a linked list and when one part completes, you trigger the next rather than sleep for an arbitrary long time.

cheers,

Jayant

This topic was automatically closed after 166 days. New replies are no longer allowed.