1414import com .azure .storage .blob .sas .BlobServiceSasSignatureValues ;
1515import com .azure .storage .blob .specialized .BlockBlobClient ;
1616import com .azure .storage .common .StorageSharedKeyCredential ;
17- import com .azure .storage .blob .options .BlobParallelUploadOptions ;
1817import com .genexus .StructSdtMessages_Message ;
1918import com .genexus .util .GXService ;
2019import com .genexus .util .StorageUtils ;
@@ -178,6 +177,7 @@ private boolean isPrivateAcl(ResourceAccessControlList acl) {
178177
179178 public String upload (String localFile , String externalFileName , ResourceAccessControlList acl ) {
180179 try {
180+ externalFileName = getExternalFileName (externalFileName );
181181 BlobClient blobClient = getBlobClient (externalFileName , acl );
182182 blobClient .uploadFromFile (localFile , true );
183183 return getResourceUrl (externalFileName , acl , defaultExpirationMinutes );
@@ -191,10 +191,9 @@ public String upload(String externalFileName, InputStream input, ResourceAccessC
191191 //https://docs.azure.cn/en-us/storage/blobs/storage-blob-upload-java
192192 try (ExternalProviderHelper .InputStreamWithLength streamInfo =
193193 ExternalProviderHelper .getInputStreamContentLength (input )) {
194-
194+ externalFileName = getExternalFileName ( externalFileName );
195195 BlockBlobClient blobClient =
196196 getBlobClient (externalFileName , acl ).getBlockBlobClient ();
197-
198197 String contentType =
199198 (externalFileName .endsWith (".tmp" ) &&
200199 "application/octet-stream" .equals (streamInfo .detectedContentType ))
@@ -224,6 +223,7 @@ public String upload(String externalFileName, InputStream input, ResourceAccessC
224223
225224 public String get (String externalFileName , ResourceAccessControlList acl , int expirationMinutes ) {
226225 try {
226+ externalFileName = getExternalFileName (externalFileName );
227227 if (exists (externalFileName , acl )) {
228228 return getResourceUrl (externalFileName , acl , expirationMinutes );
229229 }
@@ -235,6 +235,8 @@ public String get(String externalFileName, ResourceAccessControlList acl, int ex
235235 }
236236
237237 private String getResourceUrl (String externalFileName , ResourceAccessControlList acl , int expirationMinutes ) {
238+
239+ externalFileName = getExternalFileName (externalFileName );
238240 if (isPrivateAcl (acl )) {
239241 return getPrivate (externalFileName , expirationMinutes );
240242 } else {
@@ -244,14 +246,14 @@ private String getResourceUrl(String externalFileName, ResourceAccessControlList
244246 ////https://github.com/Azure/azure-sdk-for-java/issues/21610
245247
246248 String url = blobClient .getBlobUrl ();
247-
248- //Decode only when not SAS
249- return safeDecodeUrl (url );
249+ return url ;
250+ //return safeDecodeUrl(url);
250251 }
251252 }
252253
253254 private String getPrivate (String externalFileName , int expirationMinutes ) {
254255 try {
256+ externalFileName = getExternalFileName (externalFileName );
255257 BlobClient blobClient = privateContainerClient .getBlobClient (externalFileName );
256258 expirationMinutes = expirationMinutes > 0 ? expirationMinutes : defaultExpirationMinutes ;
257259 OffsetDateTime expiryTime = OffsetDateTime .now ().plusMinutes (expirationMinutes );
@@ -616,6 +618,15 @@ private static String safeDecodeUrl(String uri) {
616618 }
617619 }
618620
621+ private String getExternalFileName (String externalFileName )
622+ {
623+ //Defensive code, as externalFileName may have a leading / and this causes a double / at blob uri
624+ //The latest Azure SDK is strict at uri format and encodes special characters
625+ if (externalFileName == "" )
626+ return externalFileName ;
627+ return externalFileName .startsWith ("/" ) ? externalFileName .substring (1 ) : externalFileName ;
628+ }
629+
619630 private void handleAndLogException (String message , Exception ex ) {
620631 if (ex instanceof BlobStorageException ) {
621632 logger .error ("Azure Storage error: {} (Status: {}, Code: {})" ,
0 commit comments