Example: Chunked File Upload to OneDrive

This example demonstrates how to use the Uniface UHTTP component to upload a file to OneDrive by submitting a request to the OneDrive API.

To use the OneDrive API, you need to have an app to sign into. You must register your app and when you do, you receive an ID and a secret. The user must interactively sign in and enable and allow certain access levels. Further credentials are then obtained.

Users sign in with the REST API. The GET and POST methods can be used, and responses are in JSON.

For information about the OneDrive API, see https://developer.microsoft.com/en-us/onedrive

Upload a Large File to OneDrive, in Chunks

Note:  This example does not show or document the steps required to register your OneDrive application or the authentication protocol that is required to obtain the access token. It assumes that the access token is assigned to a component variable (vAccessToken)

  1.  Create an instance of the UHTTP component and set its processing flag to 15. This instructs UHTTP to ignore host and peer verification, and send headers on all methods when the SEND operation is used.
  2.  Specify the location and file to upload.
  3.  Get the size of the file. This is needed in order to specify the Range header.

    In this example, POST is used to create a session for the download and obtain information such as the upload URL. The information is returned in JSON.

  4.  You need to declare a chunked file upload to OneDrive by creating an upload session using the URL https://api.onedrive.com/v1.0/drive/root:/file:/upload.createSession. You will need to set authorization headers.
  5.  Send the request for a chunked upload session to OneDrive using the SEND operation.
variables
 ; Component variables:
 ; handle vUhttp
 ; string vAccessToken
 string vFileDir, vFile, vCloudFile               ; source and target information for upload file
 string vUrl, vContents, vMethod, vResponseStatus ; parameters for SEND operation 
 string vSendStatus, vFileStatus                  ; status variables for error handling
	struct vReply
endvariables

; Create UHTTP instance and set its processing flags Callout 1
newinstance "UHTTP", $vUhttp$
$vUhttp$->SET_FLAGS(15)

; Specify the directory and file name to upload Callout 2
vFileDir = "<Upload Directory>"
vFile = "<Very Big File>"
vCloudFile = vFile

; Get the file size
vContents = $fileproperties("%%vDirUsed%%%%%vFile", "FILESIZE")
vTotal = "*"
if (vContents[1,8] = "FILESIZE")
	vTotal = vContents[10, 99999]
endif

; ********** Create an upload session **************
; Prepare the SEND parameters to create a chunked upload session Callout 3
vUrl = $concat("https://api.onedrive.com/v1.0", "drive/root:/", vCloudFile, ":/upload.createSession")
vMethod = "POST"
vContents = ""
vResponseStatus = ""
vHeaders = ""
putitem/id/case vHeaders, "Authorization", "Bearer %%$vAccessToken$"
putitem/id/case vHeaders, "Host", "api.onedrive.com"
putitem/id/case vHeaders, "Connection", "Keep-Alive"
putitem/id/case vHeaders, "Content-Length", "0"

; Send the request for a chunked upload session  Callout 4
$vUhttp$->SEND(vUrl, vMethod, "", "", vHeaders, vContents, vResponseStatus)
vSendStatus = $status

; Handle possible errors and define the target URL for the upload file
if (vSendStatus < 0)
	putmess "Local error. $status=%%vSendStatus"
else
	if (vSendStatus < 200 || vSendStatus > 299)
		putmess "Unexpected reply. %%vSendStatus%%% %%vContents"
		return
	else
		jsonToStruct vReply, vContents 
		vUrl = vReply->uploadUrl 
	endif
endif

; **********    Upload the file      **************

; Define the chunk size 
vOptions = "chunk=320k"

; Upload the file, repeating for each chunk
repeat
	; load the file contents
	$vUhttp$->LOAD_FILE_CONTENTS("%%vFileDir%%%%%vFile", vOptions)
	vFileStatus = $status
	if (vFileStatus < 0)
		putmess "Could not load contents from file %%$status"
		return
	endif
	
	; get the range
	$vUhttp$->GET_INFO("range", vRange)
	if ($status < 0)
		putmess "Could not get range of file chunk %%$status"
		return
	endif
	
 ; Add the total length 
	vRange = $concat(vRange, "/", vTotal)

	; Prepare the SEND parameters
 vMethod = "PUT"
	vContents = ""
 vResponseStatus = ""
	vHeaders = ""
	putitem/id/case vHeaders, "Authorization", "Bearer %%$vAccessToken$"
	putitem/id/case vHeaders, "Host", "api.onedrive.com"
	putitem/id/case vHeaders, "Content-Length", "%%vFileStatus"
	putitem/id/case vHeaders, "Content-Type", "application/octet-stream"
	putitem/id/case vHeaders, "Content-Range", "%%vRange"
	putitem/id/case vHeaders, "Connection", "Keep-Alive"

; Send the upload fragment
	$vUhttp$->SEND(vUrl, vMethod, "", "", vHeaders, vContents, vResponseStatus)
	vSendStatus = $status

	; status 201 means finished and 202 is fragment received

	if (vSendStatus = 201 || vSendStatus = 202)
		jsonToStruct vReply, vContents
		if (vSendStatus = 202)
			vRange = vReply->nextExpectedRanges
			putmess "%%vSendStatus%%% nextExpectedRanges %%vRange"
		elseif (vSendStatus = 201)
			vCloudFile = vReply->name
			$vUhttp$->CLOSE_FILE()
			putmess "New file created %%vCloudFile%%%, %%(vReply->id)"
			break
		endif
	else
		putmess "Upload fragment error $status=%%vSendStatus"
		$vUhttp$->CLOSE_FILE()

		; cancel the session
		return
	endif
until (1 != 1)		; forever