Sample code for 30+ languages & platforms
C++

OneDrive -- Upload Large Files with an Upload Session

See more OneDrive Examples

Demonstrates how to upload large files with an upload session. See OneDrive Upload Session for more general information.

Chilkat C++ Downloads

C++
#include <CkJsonObject.h>
#include <CkHttp.h>
#include <CkHttpResponse.h>
#include <CkFileAccess.h>
#include <CkUrl.h>
#include <CkHttpRequest.h>
#include <CkStringBuilder.h>

void ChilkatSample(void)
    {
    bool success = false;

    // This example requires the Chilkat API to have been previously unlocked.
    // See Global Unlock Sample for sample code.

    // This example uses the OAuth client credentials flow.
    // See How to Create an Azure App Registration for OAuth 2.0 Client Credentials

    // Use your client ID, client secret, and tenant ID in the following lines
    CkJsonObject json;
    json.UpdateString("client_id","2871da2c-8176-4b7f-869b-2311aa82e743");
    json.UpdateString("client_secret","2hu9Q~r5QuryUcEkNbg1btLtnfU1VUXzhSCG6brH");
    json.UpdateString("scope","https://graph.microsoft.com/.default");
    json.UpdateString("token_endpoint","https://login.microsoftonline.com/114d7ed6-71bf-4dbe-a866-748364121bf2/oauth2/v2.0/token");

    CkHttp http;
    http.put_AuthToken(json.emit());

    // ----------------------------------------------------------------------------
    // Step 1: Create an upload session

    // To begin a large file upload, your app must first request a new upload session. This creates a 
    // temporary storage location where the bytes of the file will be saved until the complete file is uploaded. 
    // Once the last byte of the file has been uploaded the upload session is completed and the final file is shown 
    // in the destination folder.

    // Send the following POST to create an upload session:
    // If not using "me", then the path should be /v1.0/users/{id | userPrincipalName}/...
    // POST /v1.0/users/{user_id}/drive/root:/{path_to_item}:/createUploadSession

    http.SetUrlVar("path_to_item","/somefolder/big.zip");
    http.SetUrlVar("user_id","4fe732c3-322e-4a6b-b729-2fd1eb5c6104");
    const char *url = "https://graph.microsoft.com/v1.0/users/{$user_id}/drive/root:/{$path_to_item}:/createUploadSession";
    CkHttpResponse resp;
    success = http.HttpStr("POST",url,"{}","utf-8","application/json",resp);
    if (success == false) {
        std::cout << http.lastErrorText() << "\r\n";
        return;
    }

    // If successful, a 200 status code is returned, with the session details (in JSON format).
    CkJsonObject jsonSession;
    jsonSession.put_EmitCompact(false);
    jsonSession.Load(resp.bodyStr());

    if (resp.get_StatusCode() != 200) {

        std::cout << jsonSession.emit() << "\r\n";
        std::cout << "Response status = " << resp.get_StatusCode() << "\r\n";
        return;
    }

    std::cout << jsonSession.emit() << "\r\n";

    // A sample response:

    // 	{
    // 	  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.uploadSession",
    // 	  "uploadUrl": "https://api.onedrive.com/rup/3a33fceb9b74cc15/eyJSZXNvdXJjZUlEI ... 65yDYUiS3JTDnnhqCHxw",
    // 	  "expirationDateTime": "2017-06-11T12:40:23.239Z",
    // 	  "nextExpectedRanges": [
    // 	    "0-"
    // 	  ]
    // 	}
    // 

    // ----------------------------------------------------------------------------
    // Step 2: Upload Data in Segments (a.k.a. Fragments or Chunks)

    // Microsoft states this requirement: Use a fragment size that is a multiple of 320 KiB (320 * 1024 bytes). 
    // Failing to use a fragment size that is a multiple of 320 KiB can result in large file transfers failing after the 
    // last fragment is uploaded.  (Note: This is a detail imposed by Microsoft's OneDrive server-side implementation.)

    int fragSize = 320 * 1024;
    const char *localFilePath = "qa_data/zips/big.zip";

    // Upload the file big.zip in 320KiB segments.
    // Note: The FileSize method returns a signed 32-bit integer.  If the file is potentially larger than 2GB, call FileSizeStr instead to return
    // the size of the file as a string, then convert to an integer value.
    CkFileAccess fac;
    int fileSize = fac.FileSize(localFilePath);

    // Open the file to get the number of fragments.
    success = fac.OpenForRead(localFilePath);
    if (success == false) {
        std::cout << fac.lastErrorText() << "\r\n";
        return;
    }

    int numFragments = fac.GetNumBlocks(fragSize);
    fac.FileClose();

    int i = 0;

    std::cout << "fileSize = " << fileSize << "\r\n";
    std::cout << "numFragments = " << numFragments << "\r\n";

    CkUrl uploadUrl;
    uploadUrl.ParseUrl(jsonSession.stringOf("uploadUrl"));

    json.put_EmitCompact(false);

    CkHttpRequest req;
    req.put_HttpVerb("PUT");
    req.put_Path(uploadUrl.pathWithQueryParams());
    req.put_ContentType("application/octet-stream");

    CkStringBuilder sbOffset;
    CkStringBuilder sbNumBytes;
    CkStringBuilder sbRange;

    // IMPORTANT: The uploadUrl is a temporary URL to be used to upload the fragment.
    // It requires no authentication (because the URL itself could only have been obtained from an authenticated
    // request to start the upload session).  Therefore, do not allow the upload URL to be publicly seen,
    // otherwise anybody could upload to your OneDrive.
    http.put_AuthToken("");

    int bytesRemaining = fileSize;
    while (i < numFragments) {

        // The success response code for intermediate chunks is 202,
        // whereas the final chunk will have a 201 success response where
        // the response body is the JSON DriveItem.
        int chunkSize = fragSize;
        int expectedStatusCode = 202;
        if (bytesRemaining < chunkSize) {
            chunkSize = bytesRemaining;
            expectedStatusCode = 201;
        }

        std::cout << "  this chunkSize = " << chunkSize << "\r\n";

        // Indicate the fragment in the local file to be streamed in the upload.
        sbOffset.Clear();
        sbOffset.AppendInt(i * fragSize);
        sbNumBytes.Clear();
        sbNumBytes.AppendInt(chunkSize);
        req.StreamChunkFromFile(localFilePath,sbOffset.getAsString(),sbNumBytes.getAsString());

        // The Content-Range header field must be set for this fragment.  For example:
        // Content-Range: bytes 0-25/128
        sbRange.SetString("bytes start-end/fileSize");
        int numReplaced = sbRange.ReplaceI("start",i * fragSize);
        numReplaced = sbRange.ReplaceI("end",i * fragSize + chunkSize - 1);
        numReplaced = sbRange.ReplaceI("fileSize",fileSize);
        req.AddHeader("Content-Range",sbRange.getAsString());
        std::cout << "  this content-range: " << sbRange.getAsString() << "\r\n";

        const char *domain = uploadUrl.host();
        success = http.HttpSReq(domain,443,true,req,resp);
        if (success == false) {
            std::cout << http.lastErrorText() << "\r\n";
            return;
        }

        json.Load(resp.bodyStr());
        // A 202 response status code indicates success.
        if (resp.get_StatusCode() != expectedStatusCode) {

            std::cout << json.emit() << "\r\n";
            std::cout << "Response status = " << resp.get_StatusCode() << "\r\n";
            return;
        }

        std::cout << json.emit() << "\r\n";
        std::cout << "---- Chunk " << i << " uploaded ----" << "\r\n";

        bytesRemaining = bytesRemaining - chunkSize;
        i = i + 1;
    }

    std::cout << "data uploaded." << "\r\n";

    // ----------------------------------------------------------------------------
    // Sample output for the above session:

    // {
    //   "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.uploadSession",
    //   "uploadUrl": "https://api.onedrive.com/rup/3a33fceb9b74cc15/eyJSZXNvd ... QoKK2iuh1A",
    //   "expirationDateTime": "2017-06-11T14:04:45.438Z",
    //   "nextExpectedRanges": [
    //     "0-"
    //   ]
    // }
    // 
    // fileSize = 1366807
    // numFragments = 5
    //   this chunkSize = 327680
    //   this content-range: bytes 0-327679/1366807
    // {
    //   "expirationDateTime": "2017-06-11T14:04:45.438Z",
    //   "nextExpectedRanges": [
    //     "327680-1366806"
    //   ]
    // }
    // 
    // ---- Chunk 0 uploaded ----
    //   this chunkSize = 327680
    //   this content-range: bytes 327680-655359/1366807
    // {
    //   "expirationDateTime": "2017-06-11T14:04:45.438Z",
    //   "nextExpectedRanges": [
    //     "655360-1366806"
    //   ]
    // }
    // 
    // ---- Chunk 1 uploaded ----
    //   this chunkSize = 327680
    //   this content-range: bytes 655360-983039/1366807
    // {
    //   "expirationDateTime": "2017-06-11T14:04:45.438Z",
    //   "nextExpectedRanges": [
    //     "983040-1366806"
    //   ]
    // }
    // 
    // ---- Chunk 2 uploaded ----
    //   this chunkSize = 327680
    //   this content-range: bytes 983040-1310719/1366807
    // {
    //   "expirationDateTime": "2017-06-11T14:04:45.438Z",
    //   "nextExpectedRanges": [
    //     "1310720-1366806"
    //   ]
    // }
    // 
    // ---- Chunk 3 uploaded ----
    //   this chunkSize = 56087
    //   this content-range: bytes 1310720-1366806/1366807
    // {
    //   "createdBy": {
    //     "application": {
    //       "displayName": "Chilkat",
    //       "id": "441c9990"
    //     },
    //     "user": {
    //       "id": "3a33fceb9b74cc15"
    //     }
    //   },
    //   "createdDateTime": "2017-06-04T14:04:47.247Z",
    //   "cTag": "aYzozQTMzRkNFQjlCNzRDQzE1ITQ4NjguMjU3",
    //   "eTag": "aM0EzM0ZDRUI5Qjc0Q0MxNSE0ODY4LjA",
    //   "id": "3A33FCEB9B74CC15!4868",
    //   "lastModifiedBy": {
    //     "application": {
    //       "displayName": "Chilkat",
    //       "id": "441c9990"
    //     },
    //     "user": {
    //       "id": "3a33fceb9b74cc15"
    //     }
    //   },
    //   "lastModifiedDateTime": "2017-06-04T14:04:47.247Z",
    //   "name": "big.zip",
    //   "parentReference": {
    //     "driveId": "3a33fceb9b74cc15",
    //     "id": "3A33FCEB9B74CC15!4862",
    //     "name": "someFolder",
    //     "path": "/drive/root:/someFolder"
    //   },
    //   "size": 1366807,
    //   "webUrl": "https://1drv.ms/u/s!ABXMdJvr_DM6pgQ",
    //   "file": {
    //     "hashes": {
    //       "sha1Hash": "252059AA13004220DB912B97D4D3FF9599CCD8D9"
    //     },
    //     "mimeType": "application/zip"
    //   },
    //   "fileSystemInfo": {
    //     "createdDateTime": "2017-06-04T14:04:47.246Z",
    //     "lastModifiedDateTime": "2017-06-04T14:04:47.246Z"
    //   },
    //   "tags": [
    //   ],
    //   "lenses": [
    //   ]
    // }
    // 
    // Response status = 201
    }