PureBasic
PureBasic
Upload File in Blocks (with Content-MD5 header) and Commit the Block List
See more Azure Cloud Storage Examples
Demonstrates how to upload a file in blocks and then commit the block list. This example includes a Content-MD5 header for each block.Chilkat PureBasic Downloads
IncludeFile "CkBinData.pb"
IncludeFile "CkFileAccess.pb"
IncludeFile "CkXml.pb"
IncludeFile "CkCrypt2.pb"
IncludeFile "CkAuthAzureStorage.pb"
IncludeFile "CkRest.pb"
IncludeFile "CkStringBuilder.pb"
Procedure ChilkatExample()
success.i = 0
; Azure Blob Service Example: Upload a file in blocks, and then commit the block list.
; See also: https://msdn.microsoft.com/en-us/library/azure/dd135726.aspx
; This example requires the Chilkat API to have been previously unlocked.
; See Global Unlock Sample for sample code.
rest.i = CkRest::ckCreate()
If rest.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
; Connect to the Azure Storage Blob Service
bTls.i = 1
port.i = 443
bAutoReconnect.i = 1
; In this example, the storage account name is "chilkat".
success = CkRest::ckConnect(rest,"chilkat.blob.core.windows.net",port,bTls,bAutoReconnect)
If success <> 1
Debug CkRest::ckLastErrorText(rest)
CkRest::ckDispose(rest)
ProcedureReturn
EndIf
; Provide Azure Cloud credentials for the REST call.
azAuth.i = CkAuthAzureStorage::ckCreate()
If azAuth.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkAuthAzureStorage::setCkAccessKey(azAuth, "AZURE_ACCESS_KEY")
; The account name used here should match the 1st part of the domain passed in the call to Connect (above).
CkAuthAzureStorage::setCkAccount(azAuth, "chilkat")
CkAuthAzureStorage::setCkScheme(azAuth, "SharedKey")
CkAuthAzureStorage::setCkService(azAuth, "Blob")
; This causes the "x-ms-version: 2021-08-06" header to be automatically added.
CkAuthAzureStorage::setCkXMsVersion(azAuth, "2021-08-06")
success = CkRest::ckSetAuthAzureStorage(rest,azAuth)
; Note: The application does not need to explicitly set the following
; headers: Content-Length, x-ms-date, Authorization. These headers
; are automatically set by Chilkat.
; As the blocks are uploaded, we'll keep an XML block list for the subsequent commit..
xml.i = CkXml::ckCreate()
If xml.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkXml::setCkTag(xml, "BlockList")
; Any type of file can be uploaded in this way. It can a text file, binary file, anything...
; This example will upload an XML file that is approximately 275K in size. It can be downloaded
; at http://www.chilkatsoft.com/hamlet.xml
fac.i = CkFileAccess::ckCreate()
If fac.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
success = CkFileAccess::ckOpenForRead(fac,"qa_data/xml/hamlet.xml")
; Assuming success for the example..
; We'll upload in 16K blocks (normally a program would upload in larger block sizes than this,
; but this is just an example...)
blockSize.i = 16384
; How many 16K blocks? (Including 1 for the last partial block)
numBlocks.i = CkFileAccess::ckGetNumBlocks(fac,blockSize)
crypt.i = CkCrypt2::ckCreate()
If crypt.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
CkCrypt2::setCkHashAlgorithm(crypt, "md5")
sbResponseBody.i = CkStringBuilder::ckCreate()
If sbResponseBody.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
uriPath.i = CkStringBuilder::ckCreate()
If uriPath.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
blockId.s
dataBlock.i = CkBinData::ckCreate()
If dataBlock.i = 0
Debug "Failed to create object."
ProcedureReturn
EndIf
contentMd5.s
i.i = 0
While i < numBlocks
CkBinData::ckClear(dataBlock)
success = CkFileAccess::ckReadBlockBd(fac,i,blockSize,dataBlock)
If success = 0
Debug CkFileAccess::ckLastErrorText(fac)
CkRest::ckDispose(rest)
CkAuthAzureStorage::ckDispose(azAuth)
CkXml::ckDispose(xml)
CkFileAccess::ckDispose(fac)
CkCrypt2::ckDispose(crypt)
CkStringBuilder::ckDispose(sbResponseBody)
CkStringBuilder::ckDispose(uriPath)
CkBinData::ckDispose(dataBlock)
ProcedureReturn
EndIf
; Generate a base64 block ID.
; (Chilkat provides a helper method named GenBlockId to make this easy)
; A pre-base64 encoded block ID length of 4 is sufficient in this case because
; this file certainly won't have more than 99,999 blocks..
blockId = CkFileAccess::ckGenBlockId(fac,i,4,"base64")
; Add this blockId to the list of blocks to be committed.
CkXml::ckNewChild2(xml,"Latest",blockId)
; Build the URI path
CkStringBuilder::ckClear(uriPath)
success = CkStringBuilder::ckAppend(uriPath,"/mycontainer/hamlet.xml?comp=block&blockId=")
success = CkStringBuilder::ckAppend(uriPath,blockId)
contentMd5 = CkCrypt2::ckHashBdENC(crypt,dataBlock)
CkRest::ckAddHeader(rest,"Content-MD5",contentMd5)
; Upload this block..
CkStringBuilder::ckClear(sbResponseBody)
success = CkRest::ckFullRequestBd(rest,"PUT",CkStringBuilder::ckGetAsString(uriPath),dataBlock,sbResponseBody)
If success = 0
Debug CkRest::ckLastErrorText(rest)
CkRest::ckDispose(rest)
CkAuthAzureStorage::ckDispose(azAuth)
CkXml::ckDispose(xml)
CkFileAccess::ckDispose(fac)
CkCrypt2::ckDispose(crypt)
CkStringBuilder::ckDispose(sbResponseBody)
CkStringBuilder::ckDispose(uriPath)
CkBinData::ckDispose(dataBlock)
ProcedureReturn
EndIf
; Verify that we received a 201 status code.
If CkRest::ckResponseStatusCode(rest) <> 201
; Examine the request/response to see what happened.
Debug "response status code = " + Str(CkRest::ckResponseStatusCode(rest))
Debug "response status text = " + CkRest::ckResponseStatusText(rest)
Debug "response header: " + CkRest::ckResponseHeader(rest)
Debug "response body (if any): " + CkStringBuilder::ckGetAsString(sbResponseBody)
Debug "---"
Debug "LastRequestStartLine: " + CkRest::ckLastRequestStartLine(rest)
Debug "LastRequestHeader: " + CkRest::ckLastRequestHeader(rest)
CkRest::ckDispose(rest)
CkAuthAzureStorage::ckDispose(azAuth)
CkXml::ckDispose(xml)
CkFileAccess::ckDispose(fac)
CkCrypt2::ckDispose(crypt)
CkStringBuilder::ckDispose(sbResponseBody)
CkStringBuilder::ckDispose(uriPath)
CkBinData::ckDispose(dataBlock)
ProcedureReturn
EndIf
i = i + 1
Wend
CkFileAccess::ckFileClose(fac)
; Now commit the blocks.
; Let's have a look at the XML that will commit the blocks:
xmlStr.s = CkXml::ckGetXml(xml)
Debug xmlStr
; The XML will look like this:
; <?xml version="1.0" encoding="utf-8" ?>
; <BlockList>
; <Latest>MDAwMA==</Latest>
; <Latest>MDAwMQ==</Latest>
; <Latest>MDAwMg==</Latest>
; <Latest>MDAwMw==</Latest>
; <Latest>MDAwNA==</Latest>
; <Latest>MDAwNQ==</Latest>
; <Latest>MDAwNg==</Latest>
; <Latest>MDAwNw==</Latest>
; <Latest>MDAwOA==</Latest>
; <Latest>MDAwOQ==</Latest>
; <Latest>MDAxMA==</Latest>
; <Latest>MDAxMQ==</Latest>
; <Latest>MDAxMg==</Latest>
; <Latest>MDAxMw==</Latest>
; <Latest>MDAxNA==</Latest>
; <Latest>MDAxNQ==</Latest>
; <Latest>MDAxNg==</Latest>
; <Latest>MDAxNw==</Latest>
; </BlockList>
; --------------------------------------------------------------------------
; IMPORTANT: Remove the Content-MD5 header previously set in the loop above.
; --------------------------------------------------------------------------
CkRest::ckRemoveHeader(rest,"Content-MD5")
; Send the PUT Block List...
responseStr.s = CkRest::ckFullRequestString(rest,"PUT","/mycontainer/hamlet.xml?comp=blocklist",xmlStr)
If CkRest::ckLastMethodSuccess(rest) <> 1
Debug CkRest::ckLastErrorText(rest)
CkRest::ckDispose(rest)
CkAuthAzureStorage::ckDispose(azAuth)
CkXml::ckDispose(xml)
CkFileAccess::ckDispose(fac)
CkCrypt2::ckDispose(crypt)
CkStringBuilder::ckDispose(sbResponseBody)
CkStringBuilder::ckDispose(uriPath)
CkBinData::ckDispose(dataBlock)
ProcedureReturn
EndIf
; When successful, the Azure Storage service will respond with a 201 response status code,
; with no response body.
If CkRest::ckResponseStatusCode(rest) <> 201
; Examine the request/response to see what happened.
Debug "response status code = " + Str(CkRest::ckResponseStatusCode(rest))
Debug "response status text = " + CkRest::ckResponseStatusText(rest)
Debug "response header: " + CkRest::ckResponseHeader(rest)
Debug "response body (if any): " + responseStr
Debug "---"
Debug "LastRequestStartLine: " + CkRest::ckLastRequestStartLine(rest)
Debug "LastRequestHeader: " + CkRest::ckLastRequestHeader(rest)
CkRest::ckDispose(rest)
CkAuthAzureStorage::ckDispose(azAuth)
CkXml::ckDispose(xml)
CkFileAccess::ckDispose(fac)
CkCrypt2::ckDispose(crypt)
CkStringBuilder::ckDispose(sbResponseBody)
CkStringBuilder::ckDispose(uriPath)
CkBinData::ckDispose(dataBlock)
ProcedureReturn
EndIf
Debug "Success."
CkRest::ckDispose(rest)
CkAuthAzureStorage::ckDispose(azAuth)
CkXml::ckDispose(xml)
CkFileAccess::ckDispose(fac)
CkCrypt2::ckDispose(crypt)
CkStringBuilder::ckDispose(sbResponseBody)
CkStringBuilder::ckDispose(uriPath)
CkBinData::ckDispose(dataBlock)
ProcedureReturn
EndProcedure