Unfortunately Lucee has no cloud support like ACF ...
# lucee
h
Unfortunately Lucee has no cloud support like ACF starting with 2021. For AWS there is a great library by John Berquist called cfml_aws. But I found only an old repo for Azure by Paul Klinkenberg: https://github.com/paulklinkenberg/lucee-azure-provider Do you know if there are other libraries I am not aware of? I need the functionality to work with Azure blobs. I am aware of the Azure Java SDK, this would be the solution if no ColdFusion library exists.
Lucee also has this extension: https://github.com/lucee/extension-s3 But unfortunately no extension for Azure Blobs
e
You really do not need an extension for azure blobs
Copy code
<cfset azureStorageAccount = "your_storage_account">
<cfset azureStorageKey = "your_storage_key">
<cfset containerName = "your_container_name">
<cfset blobName = "your_blob_name">
<cfset filePath = "path_to_your_file">

<cfhttp method="PUT" url="https://#azureStorageAccount#.blob.core.windows.net/#containerName#/#blobName#" 
    result="httpResponse">
    <cfhttpparam type="header" name="x-ms-blob-type" value="BlockBlob">
    <cfhttpparam type="header" name="Authorization" value="SharedKey #azureStorageAccount#:#azureStorageKey#">
    <cfhttpparam type="file" file="#filePath#">
</cfhttp>

<cfoutput>#httpResponse.StatusCode#</cfoutput>
h
Wow, thanks! Will try your code sample soon
b
If Azure blobs use the same API as S3, the Ortus module s3sdk works quite well
I know Digital Ocean and others offer S3 API compatibility so tools will work, but I haven't used Azure's blob stuff.
h
@Evil Ware Unfortunately your sample code doesn't work - I get the result "403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature." Are you sure the Authorization header is so easy to build? <cfhttpparam type="header" name="Authorization" value="SharedKey #azureStorageAccount#:#azureStorageKey#">
ChatGPT generated this code for me, which doesn't work either ...
Copy code
<cfscript>
// Azure Storage Account Details
storageAccount = "your_storage_account_name";
storageKey = "your_storage_account_key";
containerName = "your_container_name";
blobName = "your_blob_name";
filePath = "path_to_your_local_file";

// Generate Authorization Header
private string function generateAuthorizationHeader(required string method, required string storageAccount, required string containerName, required string blobName, required string content = "", required string contentType = "application/octet-stream") {
    var x_ms_date = DateFormat(Now(), 'ddd, dd mmm yyyy') & " " & TimeFormat(Now(), 'HH:mm:ss') & " GMT";
    var canonicalizedHeaders = "x-ms-blob-type:BlockBlob";
    var canonicalizedResource = "/" & storageAccount & "/" & containerName & "/" & blobName;

    var stringToSign = method & "\n\n\n" & Len(content) & "\n\n" & contentType & "\n\n\n\n\n\n\n" & x_ms_date & "\n" & canonicalizedHeaders & "\n" & canonicalizedResource;
    
    // Java-based HMACSHA256 hashing
    var mac = createObject("java", "javax.crypto.Mac").getInstance("HmacSHA256");
    var key = createObject("java", "javax.crypto.spec.SecretKeySpec").init(storageKey.getBytes("UTF-8"), "HmacSHA256");
    mac.init(key);
    var signatureBytes = mac.doFinal(stringToSign.getBytes("UTF-8"));
    var signature = toBase64(signatureBytes);

    return "SharedKey " & storageAccount & ":" & signature;
}

// Read file content
fileContent = FileRead(filePath);

// Upload Blob Function
function uploadBlob(required string storageAccount, required string containerName, required string blobName, required string fileContent) {
    var url = "https://" & storageAccount & ".<http://blob.core.windows.net/|blob.core.windows.net/>" & containerName & "/" & blobName;
    
    var request = new http(url=url, method="PUT", charset="utf-8");
    var x_ms_date = DateFormat(Now(), 'ddd, dd mmm yyyy') & " " & TimeFormat(Now(), 'HH:mm:ss') & " GMT";
    var x_ms_version = "2024-10-10";
    
    request.addParam(type="header", name="x-ms-version", value=" " & x_ms_version); // Include a space before the version
    request.addParam(type="header", name="x-ms-date", value=x_ms_date);
    request.addParam(type="header", name="Content-Type", value="application/octet-stream");
    request.addParam(type="header", name="Authorization", value=generateAuthorizationHeader("PUT", storageAccount, containerName, blobName, fileContent, "application/octet-stream"));
    request.body = fileContent;

    var result = request.send().getPrefix();
    
    // Check the status code in the response
    if (result.statusCode == 201) {
        writeOutput("File uploaded successfully to Azure Blob.");
    } else {
        writeOutput("File upload failed. Error: " & result.statusCode & " - " & result.fileContent);
    }
}

// Call the uploadBlob function
uploadBlob(storageAccount, containerName, blobName, fileContent);
</cfscript>
File upload failed. Error: 400 The value for one of the HTTP headers is not in the correct format. - `InvalidHeaderValue`The value for one of the HTTP headers is not in the correct format. RequestId:62d9f730-f01e-0022-116d-1661bb000000 Time2024 10 04T1452:53.0848687Zx-ms-version2024-10-10
e
dump your header to file before sending the request, as it has a space or invalid character. The entire request for a graph should be on a single line. So what was posted is a starting point; what you need is to take the above, write an excellent output filter, and for debugging, write everything first to a file, and open up the file in a text editor that will display all characters, including special markup characters such as new line breaks and end of file marks. The output must be free of control characters, extra whitespace, or marks.
h
Thanks, will try to debug
👍 1