diff --git a/azure/pom.xml b/azure/pom.xml
index cd018873dc3..29d2e67afd3 100644
--- a/azure/pom.xml
+++ b/azure/pom.xml
@@ -22,7 +22,7 @@
azure
- 8.6.6
+ 12.30.0
@@ -39,8 +39,8 @@
${project.version}
- com.microsoft.azure
- azure-storage
+ com.azure
+ azure-storage-blob
${azure-storage-version}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureAclPermissionFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureAclPermissionFeature.java
index d75ef6e1e8e..7ab1a2352eb 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureAclPermissionFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureAclPermissionFeature.java
@@ -1,21 +1,18 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.Acl;
@@ -23,49 +20,42 @@
import ch.cyberduck.core.Path;
import ch.cyberduck.core.PathContainerService;
import ch.cyberduck.core.exception.BackgroundException;
-import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.features.AclPermission;
import ch.cyberduck.core.transfer.TransferStatus;
import org.jets3t.service.acl.Permission;
-import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.blob.BlobContainerPermissions;
-import com.microsoft.azure.storage.blob.BlobContainerPublicAccessType;
-import com.microsoft.azure.storage.blob.CloudBlobContainer;
+import com.azure.core.exception.HttpResponseException;
+import com.azure.storage.blob.BlobContainerClient;
+import com.azure.storage.blob.models.BlobContainerAccessPolicies;
+import com.azure.storage.blob.models.PublicAccessType;
/**
- * By default, a container and any blobs within it may be accessed only by the owner of the storage account.
- * If you want to give anonymous users read permissions to a container and its blobs, you can set the container
- * permissions to allow public access. Anonymous users can read blobs within a publicly accessible container without authenticating the request.
- * Containers provide the following options for managing container access:
+ * By default, a container and any blobs within it may be accessed only by the owner of the storage account. If you want
+ * to give anonymous users read permissions to a container and its blobs, you can set the container permissions to allow
+ * public access. Anonymous users can read blobs within a publicly accessible container without authenticating the
+ * request. Containers provide the following options for managing container access:
*
- * Full public read access: Container and blob data can be read via anonymous request. Clients can enumerate
- * blobs within the container via anonymous request, but cannot enumerate containers within the storage account.
+ * Full public read access: Container and blob data can be read via anonymous request. Clients can enumerate blobs
+ * within the container via anonymous request, but cannot enumerate containers within the storage account.
*
- * Public read access for blobs only: Blob data within this container can be read via anonymous request, but
- * container data is not available. Clients cannot enumerate blobs within the container via anonymous request.
+ * Public read access for blobs only: Blob data within this container can be read via anonymous request, but container
+ * data is not available. Clients cannot enumerate blobs within the container via anonymous request.
*
* No public read access: Container and blob data can be read by the account owner only.
*/
public class AzureAclPermissionFeature implements AclPermission {
private final AzureSession session;
-
- private final OperationContext context;
-
private final PathContainerService containerService
= new DirectoryDelimiterPathContainerService();
- public AzureAclPermissionFeature(final AzureSession session, final OperationContext context) {
+ public AzureAclPermissionFeature(final AzureSession session) {
this.session = session;
- this.context = context;
}
@Override
@@ -76,7 +66,7 @@ public List getAvailableAclRoles(final List files) {
@Override
public List getAvailableAclUsers() {
- return new ArrayList(Collections.singletonList(
+ return new ArrayList<>(Collections.singletonList(
new Acl.GroupUser(Acl.GroupUser.EVERYONE, false))
);
}
@@ -85,22 +75,21 @@ public List getAvailableAclUsers() {
public Acl getPermission(final Path file) throws BackgroundException {
try {
if(containerService.isContainer(file)) {
- final CloudBlobContainer container = session.getClient()
- .getContainerReference(containerService.getContainer(file).getName());
- final BlobContainerPermissions permissions = container.downloadPermissions(null, null, context);
+ final BlobContainerClient client = session.getClient()
+ .getBlobContainerClient(containerService.getContainer(file).getName());
+ final BlobContainerAccessPolicies accessPolicy = client.getAccessPolicy();
final Acl acl = new Acl();
- if(permissions.getPublicAccess().equals(BlobContainerPublicAccessType.BLOB)
- || permissions.getPublicAccess().equals(BlobContainerPublicAccessType.CONTAINER)) {
- acl.addAll(new Acl.GroupUser(Acl.GroupUser.EVERYONE, false), new Acl.Role(Acl.Role.READ));
+ if(accessPolicy.getBlobAccessType() != null) {
+ if(accessPolicy.getBlobAccessType().equals(PublicAccessType.BLOB)
+ || accessPolicy.getBlobAccessType().equals(PublicAccessType.CONTAINER)) {
+ acl.addAll(new Acl.GroupUser(Acl.GroupUser.EVERYONE, false), new Acl.Role(Acl.Role.READ));
+ }
}
return acl;
}
return Acl.EMPTY;
}
- catch(URISyntaxException e) {
- throw new NotfoundException(e.getMessage(), e);
- }
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Failure to read attributes of {0}", e, file);
}
}
@@ -109,23 +98,21 @@ public Acl getPermission(final Path file) throws BackgroundException {
public void setPermission(final Path file, final TransferStatus status) throws BackgroundException {
try {
if(containerService.isContainer(file)) {
- final CloudBlobContainer container = session.getClient()
- .getContainerReference(containerService.getContainer(file).getName());
- final BlobContainerPermissions permissions = container.downloadPermissions(null, null, context);
+ final BlobContainerClient client = session.getClient()
+ .getBlobContainerClient(containerService.getContainer(file).getName());
+ if(status.getAcl().asList().isEmpty()) {
+ client.setAccessPolicy(null, Collections.emptyList());
+ }
for(Acl.UserAndRole userAndRole : status.getAcl().asList()) {
if(userAndRole.getUser() instanceof Acl.GroupUser) {
if(userAndRole.getUser().getIdentifier().equals(Acl.GroupUser.EVERYONE)) {
- permissions.setPublicAccess(BlobContainerPublicAccessType.BLOB);
+ client.setAccessPolicy(PublicAccessType.BLOB, Collections.emptyList());
}
}
}
- container.uploadPermissions(permissions, null, null, context);
}
}
- catch(URISyntaxException e) {
- throw new NotfoundException(e.getMessage(), e);
- }
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Cannot change permissions of {0}", e, file);
}
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureAttributesFinderFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureAttributesFinderFeature.java
index 1295519de8a..4d87ef5225b 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureAttributesFinderFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureAttributesFinderFeature.java
@@ -1,21 +1,18 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.CancellingListProgressListener;
@@ -26,41 +23,36 @@
import ch.cyberduck.core.PathContainerService;
import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.exception.ListCanceledException;
-import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.features.AttributesAdapter;
import ch.cyberduck.core.features.AttributesFinder;
import ch.cyberduck.core.io.Checksum;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
-import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
-import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
-import com.microsoft.azure.storage.AccessCondition;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.blob.BlobContainerProperties;
-import com.microsoft.azure.storage.blob.BlobProperties;
-import com.microsoft.azure.storage.blob.BlobRequestOptions;
-import com.microsoft.azure.storage.blob.CloudBlob;
-import com.microsoft.azure.storage.blob.CloudBlobContainer;
+import com.azure.core.exception.HttpResponseException;
+import com.azure.storage.blob.BlobContainerClient;
+import com.azure.storage.blob.models.BlobContainerProperties;
+import com.azure.storage.blob.models.BlobItemProperties;
+import com.azure.storage.blob.models.BlobProperties;
-public class AzureAttributesFinderFeature implements AttributesFinder, AttributesAdapter {
+public class AzureAttributesFinderFeature implements AttributesFinder, AttributesAdapter {
+ private static final Logger log = LogManager.getLogger(AzureAttributesFinderFeature.class);
private final AzureSession session;
- private final OperationContext context;
private final PathContainerService containerService
= new DirectoryDelimiterPathContainerService();
public static final String KEY_BLOB_TYPE = "blob_type";
- public AzureAttributesFinderFeature(final AzureSession session, final OperationContext context) {
+ public AzureAttributesFinderFeature(final AzureSession session) {
this.session = session;
- this.context = context;
}
@Override
@@ -71,23 +63,20 @@ public PathAttributes find(final Path file, final ListProgressListener listener)
try {
if(containerService.isContainer(file)) {
final PathAttributes attributes = new PathAttributes();
- final CloudBlobContainer container = session.getClient().getContainerReference(containerService.getContainer(file).getName());
- container.downloadAttributes(null, null, context);
- final BlobContainerProperties properties = container.getProperties();
- attributes.setETag(properties.getEtag());
- attributes.setModificationDate(properties.getLastModified().getTime());
+ final BlobContainerClient client = session.getClient().getBlobContainerClient(containerService.getContainer(file).getName());
+ final BlobContainerProperties properties = client.getProperties();
+ attributes.setETag(properties.getETag());
+ attributes.setModificationDate(properties.getLastModified().toInstant().toEpochMilli());
return attributes;
}
if(file.isFile() || file.isPlaceholder()) {
try {
- final CloudBlob blob = session.getClient().getContainerReference(containerService.getContainer(file).getName())
- .getBlobReferenceFromServer(containerService.getKey(file));
- final BlobRequestOptions options = new BlobRequestOptions();
- blob.downloadAttributes(AccessCondition.generateEmptyCondition(), options, context);
- return this.toAttributes(blob);
+ final BlobProperties properties = session.getClient().getBlobContainerClient(containerService.getContainer(file).getName())
+ .getBlobClient(containerService.getKey(file)).getBlockBlobClient().getProperties();
+ return this.toAttributes(properties);
}
- catch(StorageException e) {
- switch(e.getHttpStatusCode()) {
+ catch(HttpResponseException e) {
+ switch(e.getResponse().getStatusCode()) {
case HttpStatus.SC_NOT_FOUND:
if(file.isPlaceholder()) {
// Ignore failure and look for common prefix
@@ -98,9 +87,11 @@ public PathAttributes find(final Path file, final ListProgressListener listener)
}
}
}
- // Check for common prefix
+ if(log.isDebugEnabled()) {
+ log.debug(String.format("Search for common prefix %s", file));
+ }
try {
- new AzureObjectListService(session, context).list(file, new CancellingListProgressListener());
+ new AzureObjectListService(session).list(file, new CancellingListProgressListener());
return PathAttributes.EMPTY;
}
catch(ListCanceledException l) {
@@ -108,27 +99,33 @@ public PathAttributes find(final Path file, final ListProgressListener listener)
return PathAttributes.EMPTY;
}
}
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Failure to read attributes of {0}", e, file);
}
- catch(URISyntaxException e) {
- throw new NotfoundException(e.getMessage(), e);
- }
}
- @Override
- public PathAttributes toAttributes(final CloudBlob blob) {
+ public PathAttributes toAttributes(final BlobProperties properties) {
final PathAttributes attributes = new PathAttributes();
- final BlobProperties properties = blob.getProperties();
- attributes.setSize(properties.getLength());
- attributes.setModificationDate(properties.getLastModified().getTime());
- if(StringUtils.isNotBlank(properties.getContentMD5())) {
- attributes.setChecksum(Checksum.parse(Hex.encodeHexString(Base64.decodeBase64(properties.getContentMD5()))));
+ attributes.setSize(properties.getBlobSize());
+ attributes.setModificationDate(properties.getLastModified().toInstant().toEpochMilli());
+ if(properties.getContentMd5() != null) {
+ attributes.setChecksum(Checksum.parse(Hex.encodeHexString(Base64.decodeBase64(properties.getContentMd5()))));
}
- attributes.setETag(properties.getEtag());
+ attributes.setETag(properties.getETag());
final Map custom = new HashMap<>();
custom.put(AzureAttributesFinderFeature.KEY_BLOB_TYPE, properties.getBlobType().name());
attributes.setCustom(custom);
return attributes;
}
+
+ public PathAttributes toAttributes(final BlobItemProperties properties) {
+ final PathAttributes attributes = new PathAttributes();
+ attributes.setSize(properties.getContentLength());
+ attributes.setModificationDate(properties.getLastModified().toInstant().toEpochMilli());
+ attributes.setETag(properties.getETag());
+ if(properties.getContentMd5() != null) {
+ attributes.setChecksum(Checksum.parse(Hex.encodeHexString(Base64.decodeBase64(properties.getContentMd5()))));
+ }
+ return attributes;
+ }
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureContainerListService.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureContainerListService.java
index 1e33c4a01b2..f69048afd17 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureContainerListService.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureContainerListService.java
@@ -1,21 +1,18 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2015 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.AttributedList;
@@ -29,49 +26,35 @@
import java.util.EnumSet;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.ResultContinuation;
-import com.microsoft.azure.storage.ResultSegment;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.blob.BlobRequestOptions;
-import com.microsoft.azure.storage.blob.CloudBlobContainer;
-import com.microsoft.azure.storage.blob.ContainerListingDetails;
+import com.azure.core.exception.HttpResponseException;
+import com.azure.storage.blob.models.BlobContainerItem;
+import com.azure.storage.blob.models.BlobContainerListDetails;
+import com.azure.storage.blob.models.ListBlobContainersOptions;
public class AzureContainerListService implements RootListService {
private final AzureSession session;
- private final OperationContext context;
- public AzureContainerListService(final AzureSession session, final OperationContext context) {
+ public AzureContainerListService(final AzureSession session) {
this.session = session;
- this.context = context;
}
@Override
public AttributedList list(final Path directory, final ListProgressListener listener) throws BackgroundException {
- ResultSegment result;
- ResultContinuation token = null;
try {
final AttributedList containers = new AttributedList<>();
- do {
- final BlobRequestOptions options = new BlobRequestOptions();
- result = session.getClient().listContainersSegmented(null, ContainerListingDetails.NONE,
- HostPreferencesFactory.get(session.getHost()).getInteger("azure.listing.chunksize"), token,
- options, context);
- for(CloudBlobContainer container : result.getResults()) {
- final PathAttributes attributes = new PathAttributes();
- attributes.setETag(container.getProperties().getEtag());
- attributes.setModificationDate(container.getProperties().getLastModified().getTime());
- containers.add(new Path(PathNormalizer.normalize(container.getName()),
- EnumSet.of(Path.Type.volume, Path.Type.directory), attributes));
- }
+ for(BlobContainerItem container : session.getClient().listBlobContainers(new ListBlobContainersOptions()
+ .setMaxResultsPerPage(HostPreferencesFactory.get(session.getHost()).getInteger("azure.listing.chunksize"))
+ .setDetails(new BlobContainerListDetails().setRetrieveDeleted(false).setRetrieveMetadata(true)), null)) {
+ final PathAttributes attributes = new PathAttributes();
+ attributes.setETag(container.getProperties().getETag());
+ attributes.setModificationDate(container.getProperties().getLastModified().toInstant().toEpochMilli());
+ containers.add(new Path(PathNormalizer.normalize(container.getName()), EnumSet.of(Path.Type.volume, Path.Type.directory), attributes));
listener.chunk(directory, containers);
- token = result.getContinuationToken();
}
- while(result.getHasMoreResults());
return containers;
}
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Listing directory {0} failed", e, directory);
}
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureCopyFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureCopyFeature.java
index e7891df1c5a..f0598d31407 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureCopyFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureCopyFeature.java
@@ -1,87 +1,74 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.ConnectionCallback;
import ch.cyberduck.core.DirectoryDelimiterPathContainerService;
import ch.cyberduck.core.LocaleFactory;
import ch.cyberduck.core.Path;
+import ch.cyberduck.core.PathAttributes;
import ch.cyberduck.core.PathContainerService;
import ch.cyberduck.core.exception.BackgroundException;
-import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.exception.UnsupportedException;
import ch.cyberduck.core.features.Copy;
import ch.cyberduck.core.io.StreamListener;
-import ch.cyberduck.core.preferences.HostPreferencesFactory;
import ch.cyberduck.core.transfer.TransferStatus;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import java.net.URI;
-import java.net.URISyntaxException;
import java.text.MessageFormat;
+import java.time.Duration;
import java.util.Optional;
-import com.microsoft.azure.storage.AccessCondition;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.blob.BlobRequestOptions;
-import com.microsoft.azure.storage.blob.CloudBlob;
+import com.azure.core.exception.HttpResponseException;
+import com.azure.core.util.polling.SyncPoller;
+import com.azure.storage.blob.BlobClient;
+import com.azure.storage.blob.models.BlobCopyInfo;
+import com.azure.storage.blob.options.BlobBeginCopyOptions;
public class AzureCopyFeature implements Copy {
private static final Logger log = LogManager.getLogger(AzureCopyFeature.class);
private final AzureSession session;
- private final OperationContext context;
-
private final PathContainerService containerService
= new DirectoryDelimiterPathContainerService();
- public AzureCopyFeature(final AzureSession session, final OperationContext context) {
+ public AzureCopyFeature(final AzureSession session) {
this.session = session;
- this.context = context;
}
@Override
public Path copy(final Path source, final Path copy, final TransferStatus status, final ConnectionCallback callback, final StreamListener listener) throws BackgroundException {
try {
- final CloudBlob target = session.getClient().getContainerReference(containerService.getContainer(copy).getName())
- .getAppendBlobReference(containerService.getKey(copy));
- final CloudBlob blob = session.getClient().getContainerReference(containerService.getContainer(source).getName())
- .getBlobReferenceFromServer(containerService.getKey(source));
- final BlobRequestOptions options = new BlobRequestOptions();
- options.setStoreBlobContentMD5(HostPreferencesFactory.get(session.getHost()).getBoolean("azure.upload.md5"));
- final URI s = session.getHost().getCredentials().isTokenAuthentication() ?
- URI.create(blob.getUri().toString() + session.getHost().getCredentials().getToken()) : blob.getUri();
- final String id = target.startCopy(s,
- AccessCondition.generateEmptyCondition(), AccessCondition.generateEmptyCondition(), options, context);
- log.debug("Started copy for {} with copy operation ID {}", copy, id);
+ final BlobClient client = session.getClient().getBlobContainerClient(containerService.getContainer(copy).getName())
+ .getBlobClient(containerService.getKey(copy));
+ final SyncPoller poller = client.beginCopy(
+ new BlobBeginCopyOptions(session.getClient().getBlobContainerClient(containerService.getContainer(source).getName())
+ .getBlobClient(containerService.getKey(source)).getBlobUrl()).setPollInterval(Duration.ofSeconds(1)));
+ if(log.isDebugEnabled()) {
+ log.debug(String.format("Started copy for %s", copy));
+ }
+ poller.waitForCompletion();
listener.sent(status.getLength());
- return copy;
+ return new Path(copy).withAttributes(PathAttributes.EMPTY);
}
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Cannot copy {0}", e, source);
}
- catch(URISyntaxException e) {
- throw new NotfoundException(e.getMessage(), e);
- }
}
@Override
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureDeleteFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureDeleteFeature.java
index 4ef935d4b48..8774cbd6fa1 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureDeleteFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureDeleteFeature.java
@@ -1,21 +1,18 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.DirectoryDelimiterPathContainerService;
@@ -23,40 +20,30 @@
import ch.cyberduck.core.Path;
import ch.cyberduck.core.PathContainerService;
import ch.cyberduck.core.exception.BackgroundException;
-import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.features.Delete;
import ch.cyberduck.core.transfer.TransferStatus;
import org.apache.http.HttpStatus;
-import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import com.microsoft.azure.storage.AccessCondition;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.blob.BlobRequestOptions;
-import com.microsoft.azure.storage.blob.DeleteSnapshotsOption;
+import com.azure.core.exception.HttpResponseException;
public class AzureDeleteFeature implements Delete {
private final AzureSession session;
-
- private final OperationContext context;
-
private final PathContainerService containerService
= new DirectoryDelimiterPathContainerService();
- public AzureDeleteFeature(final AzureSession session, final OperationContext context) {
+ public AzureDeleteFeature(final AzureSession session) {
this.session = session;
- this.context = context;
}
@Override
public void delete(final Map files, final PasswordCallback prompt, final Callback callback) throws BackgroundException {
- final List containers = new ArrayList();
+ final List containers = new ArrayList<>();
for(Path file : files.keySet()) {
if(containerService.isContainer(file)) {
containers.add(file);
@@ -64,13 +51,11 @@ public void delete(final Map files, final PasswordCallback
else {
callback.delete(file);
try {
- final BlobRequestOptions options = new BlobRequestOptions();
- session.getClient().getContainerReference(containerService.getContainer(file).getName())
- .getBlockBlobReference(containerService.getKey(file)).delete(
- DeleteSnapshotsOption.INCLUDE_SNAPSHOTS, AccessCondition.generateEmptyCondition(), options, context);
+ session.getClient().getBlobContainerClient(containerService.getContainer(file).getName())
+ .getBlobClient(containerService.getKey(file)).delete();
}
- catch(StorageException e) {
- switch(e.getHttpStatusCode()) {
+ catch(HttpResponseException e) {
+ switch(e.getResponse().getStatusCode()) {
case HttpStatus.SC_NOT_FOUND:
if(file.isPlaceholder()) {
// Ignore failure with no placeholder object found
@@ -79,24 +64,16 @@ public void delete(final Map files, final PasswordCallback
}
throw new AzureExceptionMappingService().map("Cannot delete {0}", e, file);
}
- catch(URISyntaxException e) {
- throw new NotfoundException(e.getMessage(), e);
- }
}
}
for(Path file : containers) {
callback.delete(file);
try {
- final BlobRequestOptions options = new BlobRequestOptions();
- session.getClient().getContainerReference(containerService.getContainer(file).getName()).delete(
- AccessCondition.generateEmptyCondition(), options, context);
+ session.getClient().getBlobContainerClient(containerService.getContainer(file).getName()).delete();
}
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Cannot delete {0}", e, file);
}
- catch(URISyntaxException e) {
- throw new NotfoundException(e.getMessage(), e);
- }
}
}
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureDirectoryFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureDirectoryFeature.java
index 56a3172a8e4..704cba53595 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureDirectoryFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureDirectoryFeature.java
@@ -1,21 +1,18 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.DirectoryDelimiterPathContainerService;
@@ -23,8 +20,8 @@
import ch.cyberduck.core.Path;
import ch.cyberduck.core.PathContainerService;
import ch.cyberduck.core.exception.BackgroundException;
+import ch.cyberduck.core.exception.InteroperabilityException;
import ch.cyberduck.core.exception.InvalidFilenameException;
-import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.features.Directory;
import ch.cyberduck.core.features.Write;
import ch.cyberduck.core.transfer.TransferStatus;
@@ -33,52 +30,43 @@
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.StringUtils;
-import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.EnumSet;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.blob.BlobRequestOptions;
-import com.microsoft.azure.storage.blob.CloudBlobContainer;
+import com.azure.core.exception.HttpResponseException;
public class AzureDirectoryFeature implements Directory {
+ private final AzureSession session;
private final PathContainerService containerService
= new DirectoryDelimiterPathContainerService();
- private final AzureSession session;
- private final OperationContext context;
-
private Write writer;
- public AzureDirectoryFeature(final AzureSession session, final OperationContext context) {
+ public AzureDirectoryFeature(final AzureSession session) {
this.session = session;
- this.context = context;
- this.writer = new AzureWriteFeature(session, context);
+ this.writer = new AzureWriteFeature(session);
}
@Override
public Path mkdir(final Path folder, final TransferStatus status) throws BackgroundException {
try {
- final BlobRequestOptions options = new BlobRequestOptions();
if(containerService.isContainer(folder)) {
// Container name must be lower case.
- final CloudBlobContainer container = session.getClient().getContainerReference(containerService.getContainer(folder).getName());
- container.create(options, context);
- return folder;
+ session.getClient().getBlobContainerClient(containerService.getContainer(folder).getName()).create();
+ return new Path(folder.getParent(), folder.getName(), folder.getType());
}
else {
final EnumSet type = EnumSet.copyOf(folder.getType());
type.add(Path.Type.placeholder);
- return new AzureTouchFeature(session, context).withWriter(writer).touch(folder.withType(type),
+ return new AzureTouchFeature(session).withWriter(writer).touch(folder.withType(type),
status.setChecksum(writer.checksum(folder, status).compute(new NullInputStream(0L), status)));
}
}
- catch(URISyntaxException e) {
- throw new NotfoundException(e.getMessage(), e);
+ catch(IllegalArgumentException e) {
+ throw new InteroperabilityException();
}
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Cannot create folder {0}", e, folder);
}
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureExceptionMappingService.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureExceptionMappingService.java
index 98cccb44c0d..b1b8d2997f8 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureExceptionMappingService.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureExceptionMappingService.java
@@ -1,61 +1,54 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.AbstractExceptionMappingService;
import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.exception.LoginFailureException;
-import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.http.DefaultHttpResponseExceptionMappingService;
import ch.cyberduck.core.ssl.SSLExceptionMappingService;
import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.apache.http.client.HttpResponseException;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
import javax.net.ssl.SSLException;
-import java.net.UnknownHostException;
+import java.util.Map;
-import com.microsoft.azure.storage.StorageException;
+import com.azure.core.exception.HttpResponseException;
-public class AzureExceptionMappingService extends AbstractExceptionMappingService {
- private static final Logger log = LogManager.getLogger(AzureExceptionMappingService.class);
+public class AzureExceptionMappingService extends AbstractExceptionMappingService {
@Override
- public BackgroundException map(final StorageException failure) {
- log.warn("Map failure {}", failure.toString());
+ public BackgroundException map(final HttpResponseException failure) {
final StringBuilder buffer = new StringBuilder();
- this.append(buffer, failure.getMessage());
- if(ExceptionUtils.getRootCause(failure) instanceof UnknownHostException) {
- return new NotfoundException(buffer.toString(), failure);
+ switch(failure.getResponse().getStatusCode()) {
+ case 403:
+ if(failure.getValue() instanceof Map) {
+ final Map messages = (Map) failure.getValue();
+ if(messages.containsKey("Message")) {
+ this.append(buffer, messages.get("Message").toString());
+ }
+ }
+ return new LoginFailureException(buffer.toString(), failure);
}
+ this.append(buffer, failure.getMessage());
for(Throwable cause : ExceptionUtils.getThrowableList(failure)) {
if(cause instanceof SSLException) {
return new SSLExceptionMappingService().map(buffer.toString(), (SSLException) cause);
}
}
- switch(failure.getHttpStatusCode()) {
- case 403:
- return new LoginFailureException(buffer.toString(), failure);
- default:
- return new DefaultHttpResponseExceptionMappingService().map(new HttpResponseException(failure.getHttpStatusCode(), buffer.toString()));
- }
+ return new DefaultHttpResponseExceptionMappingService().map(failure, buffer, failure.getResponse().getStatusCode());
}
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureFindFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureFindFeature.java
index 5bab17ff577..f7d3bf5aa26 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureFindFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureFindFeature.java
@@ -1,56 +1,42 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
-import ch.cyberduck.core.CancellingListProgressListener;
import ch.cyberduck.core.DirectoryDelimiterPathContainerService;
import ch.cyberduck.core.ListProgressListener;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.PathContainerService;
import ch.cyberduck.core.exception.BackgroundException;
-import ch.cyberduck.core.exception.ListCanceledException;
import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.features.Find;
-import org.apache.http.HttpStatus;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import java.net.URISyntaxException;
-
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.blob.CloudBlob;
-import com.microsoft.azure.storage.blob.CloudBlobContainer;
-
public class AzureFindFeature implements Find {
private static final Logger log = LogManager.getLogger(AzureFindFeature.class);
private final AzureSession session;
- private final OperationContext context;
-
+ private final AzureAttributesFinderFeature attributes;
private final PathContainerService containerService
= new DirectoryDelimiterPathContainerService();
- public AzureFindFeature(final AzureSession session, final OperationContext context) {
+ public AzureFindFeature(final AzureSession session) {
this.session = session;
- this.context = context;
+ this.attributes = new AzureAttributesFinderFeature(session);
}
@Override
@@ -59,46 +45,12 @@ public boolean find(Path file, final ListProgressListener listener) throws Backg
return true;
}
try {
- try {
- if(containerService.isContainer(file)) {
- final CloudBlobContainer container = session.getClient().getContainerReference(containerService.getContainer(file).getName());
- return container.exists(null, null, context);
- }
- if(file.isFile() || file.isPlaceholder()) {
- try {
- final CloudBlob blob = session.getClient().getContainerReference(containerService.getContainer(file).getName())
- .getBlobReferenceFromServer(containerService.getKey(file));
- return blob.exists(null, null, context);
- }
- catch(StorageException e) {
- switch(e.getHttpStatusCode()) {
- case HttpStatus.SC_NOT_FOUND:
- if(file.isPlaceholder()) {
- // Ignore failure and look for common prefix
- break;
- }
- default:
- throw e;
- }
- }
- }
- log.debug("Search for common prefix {}", file);
- // Check for common prefix
- try {
- new AzureObjectListService(session, context).list(file, new CancellingListProgressListener());
- return true;
- }
- catch(ListCanceledException l) {
- // Found common prefix
- return true;
- }
- }
- catch(StorageException e) {
- throw new AzureExceptionMappingService().map("Failure to read attributes of {0}", e, file);
- }
- catch(URISyntaxException e) {
- return false;
+ final boolean found;
+ if(containerService.isContainer(file)) {
+ return session.getClient().getBlobContainerClient(containerService.getContainer(file).getName()).exists();
}
+ attributes.find(file, listener);
+ return true;
}
catch(NotfoundException e) {
return false;
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureListService.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureListService.java
index ee61da4c84b..6b5f180eda8 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureListService.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureListService.java
@@ -1,7 +1,7 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2018 iterate GmbH. All rights reserved.
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
* https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
@@ -21,25 +21,21 @@
import ch.cyberduck.core.Path;
import ch.cyberduck.core.exception.BackgroundException;
-import com.microsoft.azure.storage.OperationContext;
-
public class AzureListService implements ListService {
private final AzureSession session;
- private final OperationContext context;
- public AzureListService(final AzureSession session, final OperationContext context) {
+ public AzureListService(final AzureSession session) {
this.session = session;
- this.context = context;
}
@Override
public AttributedList list(final Path directory, final ListProgressListener listener) throws BackgroundException {
if(directory.isRoot()) {
- return new AzureContainerListService(session, context).list(directory, listener);
+ return new AzureContainerListService(session).list(directory, listener);
}
else {
- return new AzureObjectListService(session, context).list(directory, listener);
+ return new AzureObjectListService(session).list(directory, listener);
}
}
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureLoggingFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureLoggingFeature.java
index 0015e232427..41673226c3a 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureLoggingFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureLoggingFeature.java
@@ -1,21 +1,18 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.Path;
@@ -26,29 +23,25 @@
import java.util.Collections;
import java.util.EnumSet;
-import com.microsoft.azure.storage.LoggingOperations;
-import com.microsoft.azure.storage.LoggingProperties;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.ServiceProperties;
-import com.microsoft.azure.storage.StorageException;
+import com.azure.core.exception.HttpResponseException;
+import com.azure.storage.blob.models.BlobAnalyticsLogging;
+import com.azure.storage.blob.models.BlobRetentionPolicy;
+import com.azure.storage.blob.models.BlobServiceProperties;
public class AzureLoggingFeature implements Logging {
private final AzureSession session;
- private final OperationContext context;
-
- public AzureLoggingFeature(final AzureSession session, final OperationContext context) {
+ public AzureLoggingFeature(final AzureSession session) {
this.session = session;
- this.context = context;
}
@Override
public LoggingConfiguration getConfiguration(final Path container) throws BackgroundException {
try {
- final ServiceProperties properties = session.getClient().downloadServiceProperties(null, context);
+ final BlobServiceProperties properties = session.getClient().getProperties();
final LoggingConfiguration configuration = new LoggingConfiguration(
- !properties.getLogging().getLogOperationTypes().isEmpty(),
+ properties.getLogging().isRead() || properties.getLogging().isWrite() || properties.getLogging().isDelete(),
"$logs"
);
// When you have configured Storage Logging to log request data from your storage account, it saves the log data
@@ -58,7 +51,7 @@ public LoggingConfiguration getConfiguration(final Path container) throws Backgr
);
return configuration;
}
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Cannot read container configuration", e);
}
}
@@ -66,19 +59,18 @@ public LoggingConfiguration getConfiguration(final Path container) throws Backgr
@Override
public void setConfiguration(final Path container, final LoggingConfiguration configuration) throws BackgroundException {
try {
- final ServiceProperties properties = session.getClient().downloadServiceProperties(null, context);
- final LoggingProperties l = new LoggingProperties();
- if(configuration.isEnabled()) {
- l.setLogOperationTypes(EnumSet.allOf(LoggingOperations.class));
- }
- else {
- l.setLogOperationTypes(EnumSet.noneOf(LoggingOperations.class));
- }
- properties.setLogging(l);
- session.getClient().uploadServiceProperties(properties, null, context);
+ final BlobServiceProperties properties = session.getClient().getProperties();
+ properties.setLogging(new BlobAnalyticsLogging()
+ .setVersion("2.0")
+ .setRetentionPolicy(new BlobRetentionPolicy().setEnabled(false))
+ .setDelete(configuration.isEnabled())
+ .setRead(configuration.isEnabled())
+ .setWrite(configuration.isEnabled())
+ );
+ session.getClient().setProperties(properties);
}
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Failure to write attributes of {0}", e, container);
}
}
-}
\ No newline at end of file
+}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureMetadataFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureMetadataFeature.java
index 98869d7fd96..2aa863c5e28 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureMetadataFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureMetadataFeature.java
@@ -1,28 +1,24 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.DirectoryDelimiterPathContainerService;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.PathContainerService;
import ch.cyberduck.core.exception.BackgroundException;
-import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.features.Headers;
import ch.cyberduck.core.preferences.HostPreferencesFactory;
import ch.cyberduck.core.transfer.TransferStatus;
@@ -30,30 +26,23 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHeaders;
-import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
-import com.microsoft.azure.storage.AccessCondition;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.blob.BlobProperties;
-import com.microsoft.azure.storage.blob.BlobRequestOptions;
-import com.microsoft.azure.storage.blob.CloudBlob;
-import com.microsoft.azure.storage.blob.CloudBlobContainer;
+import com.azure.core.exception.HttpResponseException;
+import com.azure.storage.blob.BlobClient;
+import com.azure.storage.blob.models.BlobHttpHeaders;
+import com.azure.storage.blob.models.BlobProperties;
public class AzureMetadataFeature implements Headers {
private final AzureSession session;
- private final OperationContext context;
-
private final PathContainerService containerService
= new DirectoryDelimiterPathContainerService();
- public AzureMetadataFeature(final AzureSession session, final OperationContext context) {
+ public AzureMetadataFeature(final AzureSession session) {
this.session = session;
- this.context = context;
}
@Override
@@ -65,30 +54,23 @@ public Map getDefault() {
public Map getMetadata(final Path file) throws BackgroundException {
try {
if(containerService.isContainer(file)) {
- final CloudBlobContainer container = session.getClient().getContainerReference(containerService.getContainer(file).getName());
- container.downloadAttributes();
- return container.getMetadata();
+ return session.getClient().getBlobContainerClient(containerService.getContainer(file).getName()).getProperties().getMetadata();
}
else {
- final CloudBlob blob = session.getClient().getContainerReference(containerService.getContainer(file).getName())
- .getBlobReferenceFromServer(containerService.getKey(file));
- // Populates the blob properties and metadata
- blob.downloadAttributes(null, null, context);
- final Map metadata = new HashMap(blob.getMetadata());
- final BlobProperties properties = blob.getProperties();
- if(StringUtils.isNotBlank(properties.getCacheControl())) {
- metadata.put(HttpHeaders.CACHE_CONTROL, properties.getCacheControl());
- }
+ final BlobClient client = session.getClient().getBlobContainerClient(containerService.getContainer(file).getName())
+ .getBlobClient(containerService.getKey(file));
+ final BlobProperties properties = client.getProperties();
+ final Map metadata = properties.getMetadata();
if(StringUtils.isNotBlank(properties.getContentType())) {
metadata.put(HttpHeaders.CONTENT_TYPE, properties.getContentType());
}
+ if(StringUtils.isNotBlank(properties.getCacheControl())) {
+ metadata.put(HttpHeaders.CACHE_CONTROL, properties.getCacheControl());
+ }
return metadata;
}
}
- catch(URISyntaxException e) {
- throw new NotfoundException(e.getMessage(), e);
- }
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Failure to read attributes of {0}", e, file);
}
}
@@ -96,42 +78,31 @@ public Map getMetadata(final Path file) throws BackgroundExcepti
@Override
public void setMetadata(final Path file, final TransferStatus status) throws BackgroundException {
try {
- final BlobRequestOptions options = new BlobRequestOptions();
if(containerService.isContainer(file)) {
- final CloudBlobContainer container = session.getClient().getContainerReference(containerService.getContainer(file).getName());
- container.setMetadata(new HashMap<>(status.getMetadata()));
- container.uploadMetadata(AccessCondition.generateEmptyCondition(), options, context);
+ session.getClient().getBlobContainerClient(containerService.getContainer(file).getName())
+ .setMetadata(new HashMap<>(status.getMetadata()));
}
else {
- final CloudBlob blob = session.getClient().getContainerReference(containerService.getContainer(file).getName())
- .getBlobReferenceFromServer(containerService.getKey(file));
- // Populates the blob properties and metadata
- blob.downloadAttributes();
- // Replace metadata
+ final BlobClient client = session.getClient().getBlobContainerClient(containerService.getContainer(file).getName())
+ .getBlobClient(containerService.getKey(file));
final HashMap pruned = new HashMap<>();
for(Map.Entry m : status.getMetadata().entrySet()) {
- final BlobProperties properties = blob.getProperties();
if(HttpHeaders.CACHE_CONTROL.equalsIgnoreCase(m.getKey())) {
// Update properties
- properties.setCacheControl(m.getValue());
+ client.setHttpHeaders(new BlobHttpHeaders().setCacheControl(m.getValue()));
continue;
}
if(HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(m.getKey())) {
// Update properties
- properties.setContentType(m.getValue());
+ client.setHttpHeaders(new BlobHttpHeaders().setContentType(m.getValue()));
continue;
}
pruned.put(m.getKey(), m.getValue());
}
- blob.setMetadata(pruned);
- blob.uploadMetadata(AccessCondition.generateEmptyCondition(), options, context);
- blob.uploadProperties();
+ client.setMetadata(pruned);
}
}
- catch(URISyntaxException e) {
- throw new NotfoundException(e.getMessage(), e);
- }
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Failure to write attributes of {0}", e, file);
}
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureMoveFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureMoveFeature.java
index 71307c045bb..9fd914af5d8 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureMoveFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureMoveFeature.java
@@ -1,21 +1,18 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.ConnectionCallback;
@@ -29,16 +26,14 @@
import java.util.Collections;
import java.util.Optional;
-import com.microsoft.azure.storage.OperationContext;
-
public class AzureMoveFeature implements Move {
private final AzureCopyFeature proxy;
private final AzureDeleteFeature delete;
- public AzureMoveFeature(final AzureSession session, final OperationContext context) {
- this.proxy = new AzureCopyFeature(session, context);
- this.delete = new AzureDeleteFeature(session, context);
+ public AzureMoveFeature(final AzureSession session) {
+ this.proxy = new AzureCopyFeature(session);
+ this.delete = new AzureDeleteFeature(session);
}
@Override
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureObjectListService.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureObjectListService.java
index 50a22480873..2fbf35819fc 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureObjectListService.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureObjectListService.java
@@ -1,21 +1,18 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.AttributedList;
@@ -26,53 +23,43 @@
import ch.cyberduck.core.PathAttributes;
import ch.cyberduck.core.PathContainerService;
import ch.cyberduck.core.PathNormalizer;
-import ch.cyberduck.core.SimplePathPredicate;
import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.exception.NotfoundException;
-import ch.cyberduck.core.io.Checksum;
import ch.cyberduck.core.preferences.HostPreferencesFactory;
-import org.apache.commons.codec.binary.Base64;
-import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import java.net.URISyntaxException;
import java.util.EnumSet;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.ResultContinuation;
-import com.microsoft.azure.storage.ResultSegment;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.blob.BlobListingDetails;
-import com.microsoft.azure.storage.blob.BlobRequestOptions;
-import com.microsoft.azure.storage.blob.CloudBlob;
-import com.microsoft.azure.storage.blob.CloudBlobContainer;
-import com.microsoft.azure.storage.blob.CloudBlobDirectory;
-import com.microsoft.azure.storage.blob.ListBlobItem;
+import com.azure.core.exception.HttpResponseException;
+import com.azure.core.http.rest.PagedIterable;
+import com.azure.core.http.rest.PagedResponse;
+import com.azure.storage.blob.BlobContainerClient;
+import com.azure.storage.blob.models.BlobItem;
+import com.azure.storage.blob.models.BlobListDetails;
+import com.azure.storage.blob.models.ListBlobsOptions;
public class AzureObjectListService implements ListService {
private static final Logger log = LogManager.getLogger(AzureObjectListService.class);
private final AzureSession session;
- private final OperationContext context;
-
private final PathContainerService containerService
= new DirectoryDelimiterPathContainerService();
+ private final AzureAttributesFinderFeature attributes;
- public AzureObjectListService(final AzureSession session, final OperationContext context) {
+ public AzureObjectListService(final AzureSession session) {
this.session = session;
- this.context = context;
+ this.attributes = new AzureAttributesFinderFeature(session);
}
@Override
public AttributedList list(final Path directory, final ListProgressListener listener) throws BackgroundException {
try {
- final CloudBlobContainer container = session.getClient().getContainerReference(containerService.getContainer(directory).getName());
+ final BlobContainerClient containerClient = session.getClient().getBlobContainerClient(containerService.getContainer(directory).getName());
final AttributedList children = new AttributedList<>();
- ResultContinuation token = null;
- ResultSegment result;
+ PagedIterable result;
String prefix = StringUtils.EMPTY;
if(!containerService.isContainer(directory)) {
prefix = containerService.getKey(directory);
@@ -81,47 +68,49 @@ public AttributedList list(final Path directory, final ListProgressListene
}
}
boolean hasDirectoryPlaceholder = containerService.isContainer(directory);
- do {
- final BlobRequestOptions options = new BlobRequestOptions();
- result = container.listBlobsSegmented(prefix, false, EnumSet.noneOf(BlobListingDetails.class),
- HostPreferencesFactory.get(session.getHost()).getInteger("azure.listing.chunksize"), token, options, context);
- for(ListBlobItem object : result.getResults()) {
- if(new SimplePathPredicate(new Path(object.getUri().getPath(), EnumSet.of(Path.Type.directory))).test(directory)) {
- log.debug("Skip placeholder key {}", object);
+ String continuationToken = null;
+ for(PagedResponse response : containerClient.listBlobsByHierarchy(String.valueOf(Path.DELIMITER), new ListBlobsOptions()
+ .setDetails(new BlobListDetails().setRetrieveMetadata(true))
+ .setPrefix(prefix)
+ .setMaxResultsPerPage(HostPreferencesFactory.get(session.getHost()).getInteger("azure.listing.chunksize")), null).iterableByPage(continuationToken,
+ HostPreferencesFactory.get(session.getHost()).getInteger("azure.listing.chunksize"))) {
+ for(BlobItem item : response.getElements()) {
+ if(StringUtils.equals(prefix, item.getName())) {
+ if(log.isDebugEnabled()) {
+ log.debug(String.format("Skip placeholder key %s", item));
+ }
hasDirectoryPlaceholder = true;
continue;
}
- final PathAttributes attributes = new PathAttributes();
- if(object instanceof CloudBlob) {
- final CloudBlob blob = (CloudBlob) object;
- attributes.setSize(blob.getProperties().getLength());
- attributes.setModificationDate(blob.getProperties().getLastModified().getTime());
- attributes.setETag(blob.getProperties().getEtag());
- if(StringUtils.isNotBlank(blob.getProperties().getContentMD5())) {
- attributes.setChecksum(Checksum.parse(Hex.encodeHexString(Base64.decodeBase64(blob.getProperties().getContentMD5()))));
- }
+ final PathAttributes attr;
+ if(item.isPrefix()) {
+ attr = PathAttributes.EMPTY;
+ }
+ else {
+ attr = attributes.toAttributes(item.getProperties());
}
// A directory is designated by a delimiter character.
- final EnumSet types = object instanceof CloudBlobDirectory
+ final EnumSet types = null != item.isPrefix() && item.isPrefix()
? EnumSet.of(Path.Type.directory, Path.Type.placeholder) : EnumSet.of(Path.Type.file);
- final Path child = new Path(directory, PathNormalizer.name(object.getUri().getPath()), types, attributes);
+ final Path child = new Path(directory, PathNormalizer.name(item.getName()), types, attr);
children.add(child);
}
listener.chunk(directory, children);
- token = result.getContinuationToken();
+ continuationToken = response.getContinuationToken();
+ if(StringUtils.isBlank(continuationToken)) {
+ break;
+ }
}
- while(result.getHasMoreResults());
if(!hasDirectoryPlaceholder && children.isEmpty()) {
- log.warn("No placeholder found for directory {}", directory);
+ if(log.isWarnEnabled()) {
+ log.warn(String.format("No placeholder found for directory %s", directory));
+ }
throw new NotfoundException(directory.getAbsolute());
}
return children;
}
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Listing directory {0} failed", e, directory);
}
- catch(URISyntaxException e) {
- throw new NotfoundException(e.getMessage(), e);
- }
}
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureProtocol.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureProtocol.java
index ad8e937637b..a9745bb23c7 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureProtocol.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureProtocol.java
@@ -1,21 +1,18 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.AbstractProtocol;
@@ -24,16 +21,13 @@
import ch.cyberduck.core.LocaleFactory;
import ch.cyberduck.core.LoginOptions;
import ch.cyberduck.core.PathContainerService;
-import ch.cyberduck.core.Protocol;
import ch.cyberduck.core.Scheme;
import ch.cyberduck.core.text.DefaultLexicographicOrderComparator;
-import java.util.Comparator;
+import org.apache.commons.codec.binary.Base64;
-import com.microsoft.azure.storage.core.Base64;
-import com.google.auto.service.AutoService;
+import java.util.Comparator;
-@AutoService(Protocol.class)
public class AzureProtocol extends AbstractProtocol {
@Override
@@ -80,7 +74,10 @@ public Scheme getScheme() {
public boolean validate(final Credentials credentials, final LoginOptions options) {
if(super.validate(credentials, options)) {
if(options.password) {
- return Base64.validateIsBase64String(credentials.getPassword());
+ if(credentials.getPassword().length() % 4 != 0) {
+ return false;
+ }
+ return Base64.isBase64(credentials.getPassword());
}
return true;
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureReadFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureReadFeature.java
index 8116bb80e8c..e0068ea0669 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureReadFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureReadFeature.java
@@ -1,21 +1,18 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.ConnectionCallback;
@@ -23,86 +20,48 @@
import ch.cyberduck.core.Path;
import ch.cyberduck.core.PathContainerService;
import ch.cyberduck.core.exception.BackgroundException;
-import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.features.Read;
-import ch.cyberduck.core.io.StreamCopier;
import ch.cyberduck.core.transfer.TransferStatus;
-import ch.cyberduck.core.worker.DefaultExceptionMappingService;
-import org.apache.commons.io.input.NullInputStream;
-import org.apache.commons.io.input.ProxyInputStream;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import java.io.IOException;
import java.io.InputStream;
-import java.net.URISyntaxException;
-import com.microsoft.azure.storage.AccessCondition;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.blob.BlobInputStream;
-import com.microsoft.azure.storage.blob.BlobRequestOptions;
-import com.microsoft.azure.storage.blob.CloudBlob;
-import com.microsoft.azure.storage.core.SR;
+import com.azure.core.exception.HttpResponseException;
+import com.azure.storage.blob.models.BlobRange;
+import com.azure.storage.blob.models.BlobRequestConditions;
public class AzureReadFeature implements Read {
private static final Logger log = LogManager.getLogger(AzureReadFeature.class);
private final AzureSession session;
-
- private final OperationContext context;
-
private final PathContainerService containerService
= new DirectoryDelimiterPathContainerService();
- public AzureReadFeature(final AzureSession session, final OperationContext context) {
+ public AzureReadFeature(final AzureSession session) {
this.session = session;
- this.context = context;
+ }
+
+ @Override
+ public boolean offset(final Path file) {
+ return true;
}
@Override
public InputStream read(final Path file, final TransferStatus status, final ConnectionCallback callback) throws BackgroundException {
try {
- final CloudBlob blob = session.getClient().getContainerReference(containerService.getContainer(file).getName())
- .getBlobReferenceFromServer(containerService.getKey(file));
- if(0L == blob.getProperties().getLength()) {
- return new NullInputStream(0L);
- }
- final BlobRequestOptions options = new BlobRequestOptions();
- options.setConcurrentRequestCount(1);
- final BlobInputStream in = blob.openInputStream(AccessCondition.generateEmptyCondition(), options, context);
if(status.isAppend()) {
- try {
- return StreamCopier.skip(in, status.getOffset());
- }
- catch(IndexOutOfBoundsException e) {
- // If offset is invalid
- throw new DefaultExceptionMappingService().map("Download {0} failed", e, file);
- }
+ return session.getClient().getBlobContainerClient(containerService.getContainer(file).getName())
+ .getBlobClient(containerService.getKey(file)).openInputStream(new BlobRange(status.getOffset()), new BlobRequestConditions());
+ }
+ else {
+ return session.getClient().getBlobContainerClient(containerService.getContainer(file).getName())
+ .getBlobClient(containerService.getKey(file)).openInputStream();
}
- return new ProxyInputStream(in) {
- @Override
- protected void handleIOException(final IOException e) throws IOException {
- if(StringUtils.equals(SR.STREAM_CLOSED, e.getMessage())) {
- log.warn("Ignore failure {}", e.getMessage());
- return;
- }
- final Throwable cause = ExceptionUtils.getRootCause(e);
- if(cause instanceof StorageException) {
- throw new IOException(e.getMessage(), new AzureExceptionMappingService().map((StorageException) cause));
- }
- throw e;
- }
- };
}
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Download {0} failed", e, file);
}
- catch(URISyntaxException e) {
- throw new NotfoundException(e.getMessage(), e);
- }
}
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureSession.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureSession.java
index 6d2b7a80680..b6a4873aea9 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureSession.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureSession.java
@@ -1,90 +1,77 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
-import ch.cyberduck.core.CancellingListProgressListener;
+import ch.cyberduck.core.Credentials;
import ch.cyberduck.core.Host;
import ch.cyberduck.core.HostKeyCallback;
+import ch.cyberduck.core.HostUrlProvider;
import ch.cyberduck.core.ListService;
import ch.cyberduck.core.LoginCallback;
-import ch.cyberduck.core.Path;
import ch.cyberduck.core.PreferencesUseragentProvider;
-import ch.cyberduck.core.Scheme;
-import ch.cyberduck.core.UrlProvider;
+import ch.cyberduck.core.azure.apache.ApacheHttpClient;
import ch.cyberduck.core.exception.BackgroundException;
-import ch.cyberduck.core.exception.ListCanceledException;
-import ch.cyberduck.core.exception.LoginFailureException;
-import ch.cyberduck.core.exception.NotfoundException;
-import ch.cyberduck.core.features.AclPermission;
-import ch.cyberduck.core.features.AttributesFinder;
-import ch.cyberduck.core.features.Copy;
-import ch.cyberduck.core.features.Delete;
-import ch.cyberduck.core.features.Directory;
-import ch.cyberduck.core.features.Find;
-import ch.cyberduck.core.features.Headers;
-import ch.cyberduck.core.features.Logging;
-import ch.cyberduck.core.features.Metadata;
-import ch.cyberduck.core.features.Move;
-import ch.cyberduck.core.features.Read;
-import ch.cyberduck.core.features.Touch;
-import ch.cyberduck.core.features.Upload;
-import ch.cyberduck.core.features.Write;
-import ch.cyberduck.core.http.DisabledX509HostnameVerifier;
-import ch.cyberduck.core.proxy.Proxy;
+import ch.cyberduck.core.features.*;
+import ch.cyberduck.core.http.HttpSession;
import ch.cyberduck.core.proxy.ProxyFinder;
-import ch.cyberduck.core.proxy.ProxyHostUrlProvider;
-import ch.cyberduck.core.shared.DefaultHomeFinderService;
-import ch.cyberduck.core.ssl.CustomTrustSSLProtocolSocketFactory;
import ch.cyberduck.core.ssl.DefaultX509KeyManager;
import ch.cyberduck.core.ssl.DisabledX509TrustManager;
-import ch.cyberduck.core.ssl.SSLSession;
import ch.cyberduck.core.ssl.X509KeyManager;
import ch.cyberduck.core.ssl.X509TrustManager;
import ch.cyberduck.core.threading.CancelCallback;
import org.apache.http.HttpHeaders;
+import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import org.slf4j.LoggerFactory;
-import javax.net.ssl.HttpsURLConnection;
-import java.net.InetSocketAddress;
-import java.net.URI;
-import java.net.URISyntaxException;
import java.util.Collections;
-import java.util.HashMap;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.SendingRequestEvent;
-import com.microsoft.azure.storage.StorageCredentials;
-import com.microsoft.azure.storage.StorageCredentialsAccountAndKey;
-import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature;
-import com.microsoft.azure.storage.StorageEvent;
-import com.microsoft.azure.storage.blob.CloudBlobClient;
+import com.azure.core.credential.AzureSasCredential;
+import com.azure.core.exception.HttpResponseException;
+import com.azure.core.http.HttpHeaderName;
+import com.azure.core.http.HttpPipelineBuilder;
+import com.azure.core.http.HttpPipelineCallContext;
+import com.azure.core.http.HttpPipelineNextPolicy;
+import com.azure.core.http.HttpPipelineNextSyncPolicy;
+import com.azure.core.http.HttpResponse;
+import com.azure.core.http.policy.AddDatePolicy;
+import com.azure.core.http.policy.AddHeadersPolicy;
+import com.azure.core.http.policy.AzureSasCredentialPolicy;
+import com.azure.core.http.policy.BearerTokenAuthenticationPolicy;
+import com.azure.core.http.policy.HttpPipelinePolicy;
+import com.azure.core.http.policy.RequestIdPolicy;
+import com.azure.core.http.policy.UserAgentPolicy;
+import com.azure.storage.blob.BlobServiceClient;
+import com.azure.storage.blob.BlobServiceClientBuilder;
+import com.azure.storage.blob.models.AccountKind;
+import com.azure.storage.common.StorageSharedKeyCredential;
+import com.azure.storage.common.implementation.Constants;
+import com.azure.storage.common.policy.MetadataValidationPolicy;
+import com.azure.storage.common.policy.RequestRetryOptions;
+import com.azure.storage.common.policy.RequestRetryPolicy;
+import com.azure.storage.common.policy.ResponseValidationPolicyBuilder;
+import com.azure.storage.common.policy.StorageSharedKeyCredentialPolicy;
+import reactor.core.publisher.Mono;
-public class AzureSession extends SSLSession {
+public class AzureSession extends HttpSession {
private static final Logger log = LogManager.getLogger(AzureSession.class);
- private final OperationContext context
- = new OperationContext();
-
- private StorageEvent listener;
+ private final CredentialsHttpPipelinePolicy authenticator
+ = new CredentialsHttpPipelinePolicy();
public AzureSession(final Host h) {
super(h, new DisabledX509TrustManager(), new DefaultX509KeyManager());
@@ -94,141 +81,138 @@ public AzureSession(final Host h, final X509TrustManager trust, final X509KeyMan
super(h, trust, key);
}
- static {
- HttpsURLConnection.setDefaultSSLSocketFactory(new CustomTrustSSLProtocolSocketFactory(new DisabledX509TrustManager(), new DefaultX509KeyManager()));
- HttpsURLConnection.setDefaultHostnameVerifier(new DisabledX509HostnameVerifier());
- HttpsURLConnection.setFollowRedirects(true);
+ @Override
+ protected BlobServiceClient connect(final ProxyFinder proxy, final HostKeyCallback key, final LoginCallback prompt, final CancelCallback cancel) {
+ final HttpClientBuilder pool = builder.build(proxy, this, prompt);
+ return new BlobServiceClientBuilder()
+ .endpoint(new HostUrlProvider().withUsername(false).get(host))
+ .pipeline(new HttpPipelineBuilder()
+ .httpClient(new ApacheHttpClient(pool))
+ .policies(
+ new EmptyAuthenticationPolicy(),
+ new UserAgentPolicy(new PreferencesUseragentProvider().get()),
+ new RequestIdPolicy(),
+ new RequestRetryPolicy(new RequestRetryOptions()),
+ new AddDatePolicy(),
+ new AddHeadersPolicy(new com.azure.core.http.HttpHeaders(
+ Collections.singletonMap(HttpHeaders.USER_AGENT, new PreferencesUseragentProvider().get()))
+ ),
+ new MetadataValidationPolicy(),
+ authenticator,
+ new ResponseValidationPolicyBuilder()
+ .addOptionalEcho(HttpHeaderName.fromString(Constants.HeaderConstants.CLIENT_REQUEST_ID))
+ .addOptionalEcho(HttpHeaderName.fromString(Constants.HeaderConstants.ENCRYPTION_KEY_SHA256))
+ .build()
+ )
+ .build())
+ .buildClient();
}
- @Override
- protected CloudBlobClient connect(final ProxyFinder proxyfinder, final HostKeyCallback callback, final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
- try {
- final StorageCredentials credentials;
- if(host.getCredentials().isTokenAuthentication()) {
- credentials = new StorageCredentialsSharedAccessSignature(host.getCredentials().getToken());
- }
- else {
- credentials = new StorageCredentialsAccountAndKey(host.getCredentials().getUsername(), "null");
- }
- final URI uri = new URI(String.format("%s://%s", Scheme.https, host.getHostname()));
- final CloudBlobClient client = new CloudBlobClient(uri, credentials);
- client.setDirectoryDelimiter(String.valueOf(Path.DELIMITER));
- context.setLoggingEnabled(true);
- context.setLogger(LoggerFactory.getLogger(log.getName()));
- context.setUserHeaders(new HashMap<>(Collections.singletonMap(
- HttpHeaders.USER_AGENT, new PreferencesUseragentProvider().get()))
- );
- context.getSendingRequestEventHandler().addListener(listener = new StorageEvent() {
- @Override
- public void eventOccurred(final SendingRequestEvent event) {
- if(event.getConnectionObject() instanceof HttpsURLConnection) {
- final HttpsURLConnection connection = (HttpsURLConnection) event.getConnectionObject();
- connection.setSSLSocketFactory(new CustomTrustSSLProtocolSocketFactory(trust, key));
- connection.setHostnameVerifier(new DisabledX509HostnameVerifier());
- }
- }
- });
- final Proxy proxy = proxyfinder.find(new ProxyHostUrlProvider().get(host));
- switch(proxy.getType()) {
- case SOCKS: {
- log.info("Configured to use SOCKS proxy {}", proxyfinder);
- final java.net.Proxy socksProxy = new java.net.Proxy(
- java.net.Proxy.Type.SOCKS, new InetSocketAddress(proxy.getHostname(), proxy.getPort()));
- context.setProxy(socksProxy);
- break;
- }
- case HTTP:
- case HTTPS: {
- log.info("Configured to use HTTP proxy {}", proxyfinder);
- final java.net.Proxy httpProxy = new java.net.Proxy(
- java.net.Proxy.Type.HTTP, new InetSocketAddress(proxy.getHostname(), proxy.getPort()));
- context.setProxy(httpProxy);
- break;
- }
- }
- return client;
+ private static final class CredentialsHttpPipelinePolicy implements HttpPipelinePolicy {
+ private Credentials credentials = new Credentials();
+
+ public void setCredentials(final Credentials credentials) {
+ this.credentials = credentials;
}
- catch(URISyntaxException e) {
- throw new LoginFailureException(e.getMessage(), e);
+
+ @Override
+ public Mono process(final HttpPipelineCallContext context, final HttpPipelineNextPolicy next) {
+ if(credentials.isTokenAuthentication()) {
+ return new AzureSasCredentialPolicy(new AzureSasCredential(
+ credentials.getToken())).process(context, next);
+ }
+ return new StorageSharedKeyCredentialPolicy(new StorageSharedKeyCredential(
+ credentials.getUsername(), credentials.getPassword())).process(context, next);
}
}
@Override
public void login(final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
- final StorageCredentials credentials = client.getCredentials();
- if(host.getCredentials().isPasswordAuthentication()) {
- // Update credentials
- final StorageCredentialsAccountAndKey method = (StorageCredentialsAccountAndKey) credentials;
- method.updateKey(host.getCredentials().getPassword());
- }
- // Fetch reference for directory to check login credentials
+ // Keep copy of credentials
+ authenticator.setCredentials(new Credentials(host.getCredentials()));
try {
- new AzureListService(this, context).list(new DefaultHomeFinderService(this).find(), new CancellingListProgressListener());
- }
- catch(ListCanceledException e) {
- // Success
+ final AccountKind kind = client.getAccountInfo().getAccountKind();
+ if(log.isInfoEnabled()) {
+ log.info(String.format("Connected to account of kind %s", kind));
+ }
}
- catch(NotfoundException e) {
- log.warn("Ignore failure {}", e.getMessage());
+ catch(HttpResponseException e) {
+ throw new AzureExceptionMappingService().map(e);
}
}
@Override
protected void logout() {
- context.getSendingRequestEventHandler().removeListener(listener);
+ //
}
@Override
@SuppressWarnings("unchecked")
public T _getFeature(final Class type) {
if(type == ListService.class) {
- return (T) new AzureListService(this, context);
+ return (T) new AzureListService(this);
}
if(type == Read.class) {
- return (T) new AzureReadFeature(this, context);
+ return (T) new AzureReadFeature(this);
}
if(type == Upload.class) {
- return (T) new AzureUploadFeature(this, context);
+ return (T) new AzureUploadFeature(this);
}
if(type == Write.class) {
- return (T) new AzureWriteFeature(this, context);
+ return (T) new AzureWriteFeature(this);
}
if(type == Directory.class) {
- return (T) new AzureDirectoryFeature(this, context);
+ return (T) new AzureDirectoryFeature(this);
}
if(type == Delete.class) {
- return (T) new AzureDeleteFeature(this, context);
+ return (T) new AzureDeleteFeature(this);
}
if(type == Headers.class) {
- return (T) new AzureMetadataFeature(this, context);
+ return (T) new AzureMetadataFeature(this);
}
if(type == Metadata.class) {
- return (T) new AzureMetadataFeature(this, context);
+ return (T) new AzureMetadataFeature(this);
}
if(type == Find.class) {
- return (T) new AzureFindFeature(this, context);
+ return (T) new AzureFindFeature(this);
}
if(type == AttributesFinder.class) {
- return (T) new AzureAttributesFinderFeature(this, context);
+ return (T) new AzureAttributesFinderFeature(this);
}
if(type == Logging.class) {
- return (T) new AzureLoggingFeature(this, context);
+ return (T) new AzureLoggingFeature(this);
}
if(type == Move.class) {
- return (T) new AzureMoveFeature(this, context);
+ return (T) new AzureMoveFeature(this);
}
if(type == Copy.class) {
- return (T) new AzureCopyFeature(this, context);
+ return (T) new AzureCopyFeature(this);
}
if(type == Touch.class) {
- return (T) new AzureTouchFeature(this, context);
+ return (T) new AzureTouchFeature(this);
}
- if(type == UrlProvider.class) {
+ if(type == Share.class) {
return (T) new AzureUrlProvider(this);
}
if(type == AclPermission.class) {
- return (T) new AzureAclPermissionFeature(this, context);
+ return (T) new AzureAclPermissionFeature(this);
}
return super._getFeature(type);
}
+
+ private static final class EmptyAuthenticationPolicy extends BearerTokenAuthenticationPolicy {
+ public EmptyAuthenticationPolicy() {
+ super(request -> Mono.empty());
+ }
+
+ @Override
+ public HttpResponse processSync(final HttpPipelineCallContext context, final HttpPipelineNextSyncPolicy next) {
+ return next.processSync();
+ }
+
+ @Override
+ public Mono process(final HttpPipelineCallContext context, final HttpPipelineNextPolicy next) {
+ return next.process();
+ }
+ }
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureTouchFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureTouchFeature.java
index da0eb43af0b..9b32f160833 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureTouchFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureTouchFeature.java
@@ -1,21 +1,18 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.LocaleFactory;
@@ -29,12 +26,10 @@
import java.text.MessageFormat;
-import com.microsoft.azure.storage.OperationContext;
-
public class AzureTouchFeature extends DefaultTouchFeature {
- public AzureTouchFeature(final AzureSession session, final OperationContext context) {
- super(new AzureWriteFeature(session, context));
+ public AzureTouchFeature(final AzureSession session) {
+ super(new AzureWriteFeature(session));
}
@Override
@@ -46,7 +41,6 @@ public void preflight(final Path workdir, final String filename) throws Backgrou
@Override
public Path touch(final Path file, final TransferStatus status) throws BackgroundException {
- status.setChecksum(write.checksum(file, status).compute(new NullInputStream(0L), status));
- return super.touch(file, status);
+ return super.touch(file, status.setChecksum(write.checksum(file, status).compute(new NullInputStream(0L), status)));
}
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureUploadFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureUploadFeature.java
index 39d8f6af62a..74e0a72f051 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureUploadFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureUploadFeature.java
@@ -22,25 +22,22 @@
import ch.cyberduck.core.shared.DefaultUploadFeature;
import ch.cyberduck.core.transfer.TransferStatus;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.blob.BlobType;
+import com.azure.storage.blob.models.BlobType;
public class AzureUploadFeature extends DefaultUploadFeature {
private final AzureSession session;
- private final OperationContext context;
- public AzureUploadFeature(final AzureSession session, final OperationContext context) {
- super(new AzureWriteFeature(session, context));
+ public AzureUploadFeature(final AzureSession session) {
+ super(new AzureWriteFeature(session));
this.session = session;
- this.context = context;
}
@Override
public Write.Append append(final Path file, final TransferStatus status) throws BackgroundException {
final Write.Append append = new Write.Append(status.isExists()).withStatus(status);
if(append.append) {
- final PathAttributes attr = new AzureAttributesFinderFeature(session, context).find(file);
+ final PathAttributes attr = new AzureAttributesFinderFeature(session).find(file);
if(BlobType.APPEND_BLOB == BlobType.valueOf(attr.getCustom().get(AzureAttributesFinderFeature.KEY_BLOB_TYPE))) {
return append;
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureUrlProvider.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureUrlProvider.java
index 7ba78b3152b..a24edb2e62c 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureUrlProvider.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureUrlProvider.java
@@ -1,27 +1,26 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.DescriptiveUrl;
import ch.cyberduck.core.DescriptiveUrlBag;
import ch.cyberduck.core.DirectoryDelimiterPathContainerService;
+import ch.cyberduck.core.HostPasswordStore;
import ch.cyberduck.core.LocaleFactory;
+import ch.cyberduck.core.PasswordStoreFactory;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.PathContainerService;
import ch.cyberduck.core.Scheme;
@@ -30,46 +29,58 @@
import ch.cyberduck.core.UserDateFormatterFactory;
import ch.cyberduck.core.preferences.HostPreferencesFactory;
-import java.net.URISyntaxException;
-import java.security.InvalidKeyException;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
import java.text.MessageFormat;
+import java.time.Duration;
+import java.time.OffsetDateTime;
import java.util.Calendar;
import java.util.EnumSet;
import java.util.Objects;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.blob.CloudBlob;
-import com.microsoft.azure.storage.blob.CloudBlobContainer;
-import com.microsoft.azure.storage.blob.SharedAccessBlobPermissions;
-import com.microsoft.azure.storage.blob.SharedAccessBlobPolicy;
+import com.azure.storage.blob.implementation.util.BlobSasImplUtil;
+import com.azure.storage.blob.sas.BlobSasPermission;
+import com.azure.storage.blob.sas.BlobServiceSasSignatureValues;
+import com.azure.storage.common.StorageSharedKeyCredential;
public class AzureUrlProvider implements UrlProvider {
+ private static final Logger log = LogManager.getLogger(AzureUrlProvider.class);
private final PathContainerService containerService
= new DirectoryDelimiterPathContainerService();
private final AzureSession session;
+ private final HostPasswordStore store;
public AzureUrlProvider(final AzureSession session) {
+ this(session, PasswordStoreFactory.get());
+ }
+
+ public AzureUrlProvider(final AzureSession session, final HostPasswordStore store) {
this.session = session;
+ this.store = store;
}
@Override
public DescriptiveUrlBag toUrl(final Path file, final EnumSet types) {
final DescriptiveUrlBag list = new DescriptiveUrlBag();
- // In one hour
- list.add(this.toSignedUrl(file, (int) TimeUnit.HOURS.toSeconds(1)));
- // Default signed URL expiring in 24 hours.
- list.add(this.toSignedUrl(file, (int) TimeUnit.SECONDS.toSeconds(
- HostPreferencesFactory.get(session.getHost()).getInteger("s3.url.expire.seconds"))));
- // 1 Week
- list.add(this.toSignedUrl(file, (int) TimeUnit.DAYS.toSeconds(7)));
- // 1 Month
- list.add(this.toSignedUrl(file, (int) TimeUnit.DAYS.toSeconds(30)));
- // 1 Year
- list.add(this.toSignedUrl(file, (int) TimeUnit.DAYS.toSeconds(365)));
+ if(types.contains(DescriptiveUrl.Type.signed)) {
+ // In one hour
+ list.add(this.toSignedUrl(file, (int) TimeUnit.HOURS.toSeconds(1)));
+ // Default signed URL expiring in 24 hours.
+ list.add(this.toSignedUrl(file, (int) TimeUnit.SECONDS.toSeconds(
+ HostPreferencesFactory.get(session.getHost()).getInteger("s3.url.expire.seconds"))));
+ // 1 Week
+ list.add(this.toSignedUrl(file, (int) TimeUnit.DAYS.toSeconds(7)));
+ // 1 Month
+ list.add(this.toSignedUrl(file, (int) TimeUnit.DAYS.toSeconds(30)));
+ // 1 Year
+ list.add(this.toSignedUrl(file, (int) TimeUnit.DAYS.toSeconds(365)));
+ }
return list;
}
@@ -77,17 +88,17 @@ private DescriptiveUrl toSignedUrl(final Path file, int seconds) {
return new SharedAccessSignatureUrl(file, this.getExpiry(seconds));
}
- protected Calendar getExpiry(final int seconds) {
+ protected Long getExpiry(final int seconds) {
final Calendar expiry = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
expiry.add(Calendar.SECOND, seconds);
- return expiry;
+ return expiry.getTimeInMillis();
}
private final class SharedAccessSignatureUrl extends DescriptiveUrl {
private final Path file;
- private final Calendar expiry;
+ private final Long expiry;
- public SharedAccessSignatureUrl(final Path file, final Calendar expiry) {
+ public SharedAccessSignatureUrl(final Path file, final Long expiry) {
super(EMPTY);
this.file = file;
this.expiry = expiry;
@@ -95,38 +106,25 @@ public SharedAccessSignatureUrl(final Path file, final Calendar expiry) {
@Override
public String getUrl() {
- try {
- if(!session.isConnected()) {
- return DescriptiveUrl.EMPTY.getUrl();
+ final String secret = store.findLoginPassword(session.getHost());
+ if(StringUtils.isBlank(secret)) {
+ if(log.isWarnEnabled()) {
+ log.warn("No secret found in password store required to sign temporary URL");
}
- final CloudBlobContainer container = session.getClient().getContainerReference(containerService.getContainer(file).getName());
- final String token;
- if(containerService.isContainer(file)) {
- token = container.generateSharedAccessSignature(this.getPolicy(expiry), null);
- }
- else {
- final CloudBlob blob = container.getBlobReferenceFromServer(containerService.getKey(file));
- token = blob.generateSharedAccessSignature(this.getPolicy(expiry), null);
- }
- return String.format("%s://%s%s?%s",
- Scheme.https.name(), session.getHost().getHostname(), URIEncoder.encode(file.getAbsolute()), token);
- }
- catch(InvalidKeyException | URISyntaxException | StorageException e) {
return DescriptiveUrl.EMPTY.getUrl();
}
- }
-
- private SharedAccessBlobPolicy getPolicy(final Calendar expiry) {
- final SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy();
- policy.setSharedAccessExpiryTime(expiry.getTime());
- policy.setPermissions(EnumSet.of(SharedAccessBlobPermissions.READ));
- return policy;
+ final String token = new BlobSasImplUtil(new BlobServiceSasSignatureValues(
+ OffsetDateTime.now().plus(Duration.ofMillis(expiry)), new BlobSasPermission().setReadPermission(true)), containerService.getContainer(file).getName())
+ .generateSas(new StorageSharedKeyCredential(session.getHost().getCredentials().getUsername(),
+ secret), null);
+ return String.format("%s://%s%s?%s",
+ Scheme.https.name(), session.getHost().getHostname(), URIEncoder.encode(file.getAbsolute()), token);
}
@Override
public String getHelp() {
return MessageFormat.format(LocaleFactory.localizedString("Expires {0}", "S3"),
- UserDateFormatterFactory.get().getMediumFormat(expiry.getTimeInMillis()));
+ UserDateFormatterFactory.get().getMediumFormat(expiry));
}
@Override
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/AzureWriteFeature.java b/azure/src/main/java/ch/cyberduck/core/azure/AzureWriteFeature.java
index 9a50ffbe555..163ca66ea87 100644
--- a/azure/src/main/java/ch/cyberduck/core/azure/AzureWriteFeature.java
+++ b/azure/src/main/java/ch/cyberduck/core/azure/AzureWriteFeature.java
@@ -1,21 +1,18 @@
package ch.cyberduck.core.azure;
/*
- * Copyright (c) 2002-2014 David Kocher. All rights reserved.
- * http://cyberduck.io/
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * Bug fixes, suggestions and comments should be sent to:
- * feedback@cyberduck.io
*/
import ch.cyberduck.core.ConnectionCallback;
@@ -24,7 +21,8 @@
import ch.cyberduck.core.PathAttributes;
import ch.cyberduck.core.PathContainerService;
import ch.cyberduck.core.exception.BackgroundException;
-import ch.cyberduck.core.exception.NotfoundException;
+import ch.cyberduck.core.features.AttributesFinder;
+import ch.cyberduck.core.features.Find;
import ch.cyberduck.core.features.Write;
import ch.cyberduck.core.io.Checksum;
import ch.cyberduck.core.io.ChecksumCompute;
@@ -33,47 +31,60 @@
import ch.cyberduck.core.io.StatusOutputStream;
import ch.cyberduck.core.io.VoidStatusOutputStream;
import ch.cyberduck.core.preferences.HostPreferencesFactory;
+import ch.cyberduck.core.preferences.Preferences;
+import ch.cyberduck.core.preferences.PreferencesFactory;
import ch.cyberduck.core.transfer.TransferStatus;
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.HttpHeaders;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.EnumSet;
import java.util.HashMap;
+import java.util.Map;
-import com.microsoft.azure.storage.AccessCondition;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.StorageException;
-import com.microsoft.azure.storage.blob.BlobOutputStream;
-import com.microsoft.azure.storage.blob.BlobRequestOptions;
-import com.microsoft.azure.storage.blob.BlobType;
-import com.microsoft.azure.storage.blob.CloudAppendBlob;
-import com.microsoft.azure.storage.blob.CloudBlob;
-import com.microsoft.azure.storage.blob.CloudBlockBlob;
-import com.microsoft.azure.storage.core.SR;
+import com.azure.core.exception.HttpResponseException;
+import com.azure.storage.blob.BlobClient;
+import com.azure.storage.blob.models.BlobHttpHeaders;
+import com.azure.storage.blob.models.BlobType;
+import com.azure.storage.blob.options.AppendBlobCreateOptions;
+import com.azure.storage.blob.options.BlockBlobOutputStreamOptions;
+import com.azure.storage.blob.specialized.AppendBlobClient;
+import com.azure.storage.blob.specialized.BlobOutputStream;
+import com.azure.storage.blob.specialized.BlockBlobClient;
+import com.azure.storage.common.implementation.Constants;
public class AzureWriteFeature implements Write {
private static final Logger log = LogManager.getLogger(AzureWriteFeature.class);
private final AzureSession session;
- private final OperationContext context;
+
private final PathContainerService containerService
= new DirectoryDelimiterPathContainerService();
+
+ private final Preferences preferences
+ = PreferencesFactory.get();
private final BlobType blobType;
- public AzureWriteFeature(final AzureSession session, final OperationContext context) {
- this(session, BlobType.valueOf(HostPreferencesFactory.get(session.getHost()).getProperty("azure.upload.blobtype")), context);
+ public AzureWriteFeature(final AzureSession session) {
+ this(session, BlobType.valueOf(HostPreferencesFactory.get(session.getHost()).getProperty("azure.upload.blobtype")));
+ }
+
+ public AzureWriteFeature(final AzureSession session, final BlobType blobType) {
+ this.session = session;
+ this.blobType = blobType;
+ }
+
+ public AzureWriteFeature(final AzureSession session, final Find finder, final AttributesFinder attributes) {
+ this(session, finder, attributes, BlobType.valueOf(HostPreferencesFactory.get(session.getHost()).getProperty("azure.upload.blobtype")));
}
- public AzureWriteFeature(final AzureSession session, final BlobType blobType, final OperationContext context) {
+ public AzureWriteFeature(final AzureSession session, final Find finder, final AttributesFinder attributes, final BlobType blobType) {
this.session = session;
this.blobType = blobType;
- this.context = context;
}
@Override
@@ -84,112 +95,110 @@ public ChecksumCompute checksum(final Path file, final TransferStatus status) {
@Override
public StatusOutputStream write(final Path file, final TransferStatus status, final ConnectionCallback callback) throws BackgroundException {
try {
- final CloudBlob blob;
+ final BlobClient client = session.getClient().getBlobContainerClient(containerService.getContainer(file).getName())
+ .getBlobClient(containerService.getKey(file));
+ final BlobHttpHeaders headers = new BlobHttpHeaders();
+ if(StringUtils.isNotBlank(status.getMime())) {
+ headers.setContentType(status.getMime());
+ }
+ final Map metadata = new HashMap<>(status.getMetadata());
+ for(final Map.Entry m : metadata.entrySet()) {
+ if(HttpHeaders.CACHE_CONTROL.equalsIgnoreCase(m.getKey())) {
+ // Update properties
+ headers.setCacheControl(m.getValue());
+ }
+ if(HttpHeaders.CONTENT_TYPE.equalsIgnoreCase(m.getKey())) {
+ // Update properties
+ headers.setContentType(m.getValue());
+ }
+ }
+ metadata.remove(HttpHeaders.CACHE_CONTROL);
+ metadata.remove(HttpHeaders.CONTENT_TYPE);
+ final Checksum checksum = status.getChecksum();
+ if(Checksum.NONE != checksum) {
+ switch(checksum.algorithm) {
+ case md5:
+ try {
+ headers.setContentMd5(Hex.decodeHex(status.getChecksum().hash.toCharArray()));
+ }
+ catch(DecoderException e) {
+ // Ignore
+ }
+ break;
+ }
+ }
+ final BlobOutputStream out;
if(status.isExists()) {
- if(HostPreferencesFactory.get(session.getHost()).getBoolean("azure.upload.snapshot")) {
- session.getClient().getContainerReference(containerService.getContainer(file).getName())
- .getBlobReferenceFromServer(containerService.getKey(file)).createSnapshot();
+ if(preferences.getBoolean("azure.upload.snapshot")) {
+ session.getClient().getBlobContainerClient(containerService.getContainer(file).getName())
+ .getBlobClient(containerService.getKey(file)).createSnapshot();
}
if(status.isAppend()) {
// Existing append blob type
- blob = session.getClient().getContainerReference(containerService.getContainer(file).getName())
- .getAppendBlobReference(containerService.getKey(file));
+ out = client.getAppendBlobClient().getBlobOutputStream();
}
else {
// Existing block blob type
- final PathAttributes attr = new AzureAttributesFinderFeature(session, context).find(file);
+ final PathAttributes attr = new AzureAttributesFinderFeature(session).find(file);
if(BlobType.APPEND_BLOB == BlobType.valueOf(attr.getCustom().get(AzureAttributesFinderFeature.KEY_BLOB_TYPE))) {
- blob = session.getClient().getContainerReference(containerService.getContainer(file).getName())
- .getAppendBlobReference(containerService.getKey(file));
+ out = client.getAppendBlobClient().getBlobOutputStream(true);
}
else {
- blob = session.getClient().getContainerReference(containerService.getContainer(file).getName())
- .getBlockBlobReference(containerService.getKey(file));
+ final BlockBlobOutputStreamOptions options = new BlockBlobOutputStreamOptions()
+ .setMetadata(metadata)
+ .setHeaders(headers)
+ .setMetadata(metadata);
+ out = client.getBlockBlobClient().getBlobOutputStream(options);
}
}
}
else {
// Create new blob with default type set in defaults
switch(blobType) {
- case APPEND_BLOB:
- blob = session.getClient().getContainerReference(containerService.getContainer(file).getName())
- .getAppendBlobReference(containerService.getKey(file));
+ case APPEND_BLOB: {
+ final AppendBlobClient append = client.getAppendBlobClient();
+ final AppendBlobCreateOptions options = new AppendBlobCreateOptions()
+ .setMetadata(metadata)
+ .setHeaders(headers)
+ .setMetadata(metadata);
+ append.createWithResponse(options, null, null);
+ out = append.getBlobOutputStream();
break;
- default:
- blob = session.getClient().getContainerReference(containerService.getContainer(file).getName())
- .getBlockBlobReference(containerService.getKey(file));
- }
- }
- if(StringUtils.isNotBlank(status.getMime())) {
- blob.getProperties().setContentType(status.getMime());
- }
- // Add previous metadata when overwriting file
- final HashMap headers = new HashMap<>(status.getMetadata());
- blob.setMetadata(headers);
- // Remove additional headers not allowed in metadata and move to properties
- if(headers.containsKey(HttpHeaders.CACHE_CONTROL)) {
- blob.getProperties().setCacheControl(headers.get(HttpHeaders.CACHE_CONTROL));
- headers.remove(HttpHeaders.CACHE_CONTROL);
- }
- if(headers.containsKey(HttpHeaders.CONTENT_TYPE)) {
- blob.getProperties().setContentType(headers.get(HttpHeaders.CONTENT_TYPE));
- headers.remove(HttpHeaders.CONTENT_TYPE);
- }
- final Checksum checksum = status.getChecksum();
- if(Checksum.NONE != checksum) {
- switch(checksum.algorithm) {
- case md5:
- headers.remove(HttpHeaders.CONTENT_MD5);
- blob.getProperties().setContentMD5(status.getChecksum().base64);
+ }
+ default: {
+ final BlockBlobClient block = client.getBlockBlobClient();
+ final BlockBlobOutputStreamOptions options = new BlockBlobOutputStreamOptions()
+ .setMetadata(metadata)
+ .setHeaders(headers)
+ .setMetadata(metadata);
+ out = block.getBlobOutputStream(options);
break;
- }
- }
- final BlobRequestOptions options = new BlobRequestOptions();
- options.setConcurrentRequestCount(1);
- options.setStoreBlobContentMD5(HostPreferencesFactory.get(session.getHost()).getBoolean("azure.upload.md5"));
- final BlobOutputStream out;
- if(status.isAppend()) {
- options.setStoreBlobContentMD5(false);
- if(blob instanceof CloudAppendBlob) {
- out = ((CloudAppendBlob) blob).openWriteExisting(AccessCondition.generateEmptyCondition(), options, context);
- }
- else {
- throw new NotfoundException(String.format("Unexpected blob type for %s", blob.getName()));
- }
- }
- else {
- if(blob instanceof CloudAppendBlob) {
- out = ((CloudAppendBlob) blob).openWriteNew(AccessCondition.generateEmptyCondition(), options, context);
- }
- else {
- out = ((CloudBlockBlob) blob).openOutputStream(AccessCondition.generateEmptyCondition(), options, context);
+ }
}
}
return new VoidStatusOutputStream(out) {
+ @Override
+ public void close() throws IOException {
+ try {
+ super.close();
+ }
+ catch(RuntimeException e) {
+ this.handleIOException(new IOException(e.getMessage(), e));
+ }
+ }
+
@Override
protected void handleIOException(final IOException e) throws IOException {
- if(StringUtils.equals(SR.STREAM_CLOSED, e.getMessage())) {
- log.warn("Ignore failure {}", e.getMessage());
+ if(StringUtils.equals(Constants.STREAM_CLOSED, e.getMessage())) {
+ log.warn(String.format("Ignore failure %s", e));
return;
}
- final Throwable cause = ExceptionUtils.getRootCause(e);
- if(cause instanceof StorageException) {
- throw new IOException(e.getMessage(), new AzureExceptionMappingService().map((StorageException) cause));
- }
throw e;
}
};
}
- catch(StorageException e) {
+ catch(HttpResponseException e) {
throw new AzureExceptionMappingService().map("Upload {0} failed", e, file);
}
- catch(URISyntaxException e) {
- throw new NotfoundException(e.getMessage(), e);
- }
- }
-
- @Override
- public EnumSet features(final Path file) {
- return EnumSet.of(Flags.checksum, Flags.mime);
}
}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/apache/ApacheHttpClient.java b/azure/src/main/java/ch/cyberduck/core/azure/apache/ApacheHttpClient.java
new file mode 100644
index 00000000000..9bdab1737dd
--- /dev/null
+++ b/azure/src/main/java/ch/cyberduck/core/azure/apache/ApacheHttpClient.java
@@ -0,0 +1,80 @@
+package ch.cyberduck.core.azure.apache;
+
+/*
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+import com.azure.core.http.*;
+import com.azure.core.util.FluxUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.protocol.HTTP;
+import reactor.core.publisher.Mono;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+public class ApacheHttpClient implements HttpClient {
+ private final org.apache.http.client.HttpClient httpClient;
+
+ public ApacheHttpClient(final HttpClientBuilder builder) {
+ this.httpClient = builder.build();
+ }
+
+ public Mono send(final HttpRequest azureRequest) {
+ try {
+ ApacheHttpRequest apacheRequest = new ApacheHttpRequest(azureRequest.getHttpMethod(), azureRequest.getUrl(),
+ azureRequest.getHeaders());
+
+ Mono bodyMono = (azureRequest.getBody() != null)
+ ? FluxUtil.collectBytesInByteBufferStream(azureRequest.getBody())
+ : Mono.just(new byte[0]);
+
+ return bodyMono.flatMap(bodyBytes -> {
+ apacheRequest.setEntity(new ByteArrayEntity(bodyBytes));
+ try {
+ return Mono.just(new ApacheHttpResponse(azureRequest, httpClient.execute(apacheRequest)));
+ } catch (IOException ex) {
+ return Mono.error(ex);
+ }
+ });
+ } catch (URISyntaxException e) {
+ return Mono.error(e);
+ }
+ }
+
+ private static final class ApacheHttpRequest extends HttpEntityEnclosingRequestBase {
+ private final String method;
+
+ private ApacheHttpRequest(HttpMethod method, URL url, HttpHeaders headers) throws URISyntaxException {
+ this.method = method.name();
+ setURI(url.toURI());
+ headers.stream().forEach(this::accept);
+ }
+
+ @Override
+ public String getMethod() {
+ return method;
+ }
+
+ private void accept(final HttpHeader header) {
+ if (!StringUtils.equalsIgnoreCase(header.getName(), HTTP.CONTENT_LEN)) {
+ this.addHeader(header.getName(), header.getValue());
+ }
+ }
+ }
+}
diff --git a/azure/src/main/java/ch/cyberduck/core/azure/apache/ApacheHttpResponse.java b/azure/src/main/java/ch/cyberduck/core/azure/apache/ApacheHttpResponse.java
new file mode 100644
index 00000000000..0ef4ffe3cf4
--- /dev/null
+++ b/azure/src/main/java/ch/cyberduck/core/azure/apache/ApacheHttpResponse.java
@@ -0,0 +1,79 @@
+package ch.cyberduck.core.azure.apache;
+
+/*
+ * Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
+ * https://cyberduck.io/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+import com.azure.core.http.HttpHeaders;
+import com.azure.core.http.HttpRequest;
+import com.azure.core.http.HttpResponse;
+import org.apache.http.HttpEntity;
+import org.apache.http.util.EntityUtils;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+final class ApacheHttpResponse extends HttpResponse {
+ private final int statusCode;
+ private final HttpHeaders headers;
+ private final HttpEntity entity;
+
+ protected ApacheHttpResponse(HttpRequest request, org.apache.http.HttpResponse apacheResponse) {
+ super(request);
+ this.statusCode = apacheResponse.getStatusLine().getStatusCode();
+ this.headers = new HttpHeaders();
+ Arrays.stream(apacheResponse.getAllHeaders())
+ .forEach(header -> headers.put(header.getName(), header.getValue()));
+ this.entity = apacheResponse.getEntity();
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public String getHeaderValue(String s) {
+ return headers.getValue(s);
+ }
+
+ public HttpHeaders getHeaders() {
+ return headers;
+ }
+
+ public Flux getBody() {
+ return getBodyAsByteArray().map(ByteBuffer::wrap).flux();
+ }
+
+ public Mono getBodyAsByteArray() {
+ if (null == entity) {
+ return Mono.empty();
+ }
+ try {
+ return Mono.just(EntityUtils.toByteArray(entity));
+ } catch (IOException e) {
+ return Mono.error(e);
+ }
+ }
+
+ public Mono getBodyAsString() {
+ return getBodyAsByteArray().map(String::new);
+ }
+
+ public Mono getBodyAsString(Charset charset) {
+ return getBodyAsByteArray().map(bytes -> new String(bytes, charset));
+ }
+}
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AbstractAzureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AbstractAzureTest.java
index 9911084e379..cd7876e88ee 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AbstractAzureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AbstractAzureTest.java
@@ -1,6 +1,4 @@
-package ch.cyberduck.core.azure;
-
-/*
+package ch.cyberduck.core.azure;/*
* Copyright (c) 2002-2021 iterate GmbH. All rights reserved.
* https://cyberduck.io/
*
@@ -23,18 +21,13 @@
import ch.cyberduck.core.DisabledProgressListener;
import ch.cyberduck.core.Host;
import ch.cyberduck.core.LoginConnectionService;
-import ch.cyberduck.core.LoginOptions;
import ch.cyberduck.core.cryptomator.CryptoVault;
-import ch.cyberduck.core.ssl.DefaultX509KeyManager;
-import ch.cyberduck.core.ssl.DisabledX509TrustManager;
import ch.cyberduck.test.VaultTest;
import org.junit.After;
import org.junit.Before;
import org.junit.runners.Parameterized;
-import static org.junit.Assert.fail;
-
public class AbstractAzureTest extends VaultTest {
protected AzureSession session;
@@ -57,15 +50,8 @@ public void setup() throws Exception {
final Host host = new Host(new AzureProtocol(), "kahy9boj3eib.blob.core.windows.net", new Credentials(
PROPERTIES.get("azure.user"), PROPERTIES.get("azure.password")
));
- session = new AzureSession(host, new DisabledX509TrustManager(), new DefaultX509KeyManager());
- final LoginConnectionService login = new LoginConnectionService(new DisabledLoginCallback() {
- @Override
- public Credentials prompt(final Host bookmark, final String username, final String title, final String reason, final LoginOptions options) {
- fail(reason);
- return null;
- }
- }, new DisabledHostKeyCallback(),
- new DisabledPasswordStore(), new DisabledProgressListener());
- login.check(session, new DisabledCancelCallback());
+ session = new AzureSession(host);
+ new LoginConnectionService(new DisabledLoginCallback(), new DisabledHostKeyCallback(),
+ new DisabledPasswordStore(), new DisabledProgressListener()).connect(session, new DisabledCancelCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureAclPermissionFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureAclPermissionFeatureTest.java
index cd37888d15b..a3090920c6a 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureAclPermissionFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureAclPermissionFeatureTest.java
@@ -1,5 +1,6 @@
package ch.cyberduck.core.azure;
+import ch.cyberduck.core.Acl;
import ch.cyberduck.core.AsciiRandomStringService;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.exception.NotfoundException;
@@ -10,6 +11,8 @@
import java.util.EnumSet;
+import static org.junit.Assert.assertEquals;
+
@Category(IntegrationTest.class)
public class AzureAclPermissionFeatureTest extends AbstractAzureTest {
@@ -17,7 +20,24 @@ public class AzureAclPermissionFeatureTest extends AbstractAzureTest {
@Test(expected = NotfoundException.class)
public void testReadNotFoundContainer() throws Exception {
final Path container = new Path(new AsciiRandomStringService().random(), EnumSet.of(Path.Type.volume, Path.Type.directory));
- final AzureAclPermissionFeature f = new AzureAclPermissionFeature(session, null);
+ final AzureAclPermissionFeature f = new AzureAclPermissionFeature(session);
f.getPermission(container);
}
+
+ @Test
+ public void testWriteContainer() throws Exception {
+ final Path container = new Path("cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory));
+ final AzureAclPermissionFeature f = new AzureAclPermissionFeature(session);
+ {
+ final Acl acl = new Acl();
+ acl.addAll(new Acl.GroupUser(Acl.GroupUser.EVERYONE), new Acl.Role(Acl.Role.READ));
+ f.setPermission(container, acl);
+ assertEquals(acl, f.getPermission(container));
+ }
+ {
+ final Acl acl = new Acl();
+ f.setPermission(container, acl);
+ assertEquals(acl, f.getPermission(container));
+ }
+ }
}
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureAttributesFinderFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureAttributesFinderFeatureTest.java
index f862660d1c2..bd077cdca42 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureAttributesFinderFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureAttributesFinderFeatureTest.java
@@ -27,14 +27,14 @@ public class AzureAttributesFinderFeatureTest extends AbstractAzureTest {
@Test
public void testFindRoot() throws Exception {
- final AzureAttributesFinderFeature f = new AzureAttributesFinderFeature(session, null);
+ final AzureAttributesFinderFeature f = new AzureAttributesFinderFeature(session);
assertEquals(PathAttributes.EMPTY, f.find(new Path("/", EnumSet.of(Path.Type.directory))));
}
@Test(expected = NotfoundException.class)
public void testNotFound() throws Exception {
final Path container = new Path(StringUtils.lowerCase(new AlphanumericRandomStringService().random()), EnumSet.of(Path.Type.directory, Path.Type.volume));
- final AzureAttributesFinderFeature f = new AzureAttributesFinderFeature(session, null);
+ final AzureAttributesFinderFeature f = new AzureAttributesFinderFeature(session);
f.find(new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)));
}
@@ -42,49 +42,49 @@ public void testNotFound() throws Exception {
public void testFind() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureTouchFeature(session, null).touch(test, new TransferStatus());
- final AzureAttributesFinderFeature f = new AzureAttributesFinderFeature(session, null);
+ new AzureTouchFeature(session).touch(test, new TransferStatus());
+ final AzureAttributesFinderFeature f = new AzureAttributesFinderFeature(session);
final PathAttributes attributes = f.find(test);
assertEquals(0L, attributes.getSize());
assertNotNull(attributes.getETag());
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
public void testFindContainer() throws Exception {
final Path container = new Path(new AlphanumericRandomStringService().random().toLowerCase(Locale.ROOT), EnumSet.of(Path.Type.directory, Path.Type.volume));
- new AzureDirectoryFeature(session, null).mkdir(container, new TransferStatus());
- final AzureAttributesFinderFeature f = new AzureAttributesFinderFeature(session, null);
+ new AzureDirectoryFeature(session).mkdir(container, new TransferStatus());
+ final AzureAttributesFinderFeature f = new AzureAttributesFinderFeature(session);
final PathAttributes attributes = f.find(container);
assertNotEquals(PathAttributes.EMPTY, attributes);
assertNotNull(attributes.getETag());
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(container), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(container), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
public void testMissingPlaceholder() throws Exception {
- final Path container = new AzureDirectoryFeature(session, null).mkdir(
+ final Path container = new AzureDirectoryFeature(session).mkdir(
new Path(new AlphanumericRandomStringService().random().toLowerCase(Locale.ROOT), EnumSet.of(Path.Type.directory, Path.Type.volume)), new TransferStatus());
final String prefix = new AlphanumericRandomStringService().random();
final Path intermediate = new Path(container, prefix, EnumSet.of(Path.Type.directory));
- final Path directory = new AzureDirectoryFeature(session, null).mkdir(new Path(intermediate, new AsciiRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(directory));
- final Path test = new AzureTouchFeature(session, null).touch(
+ final Path directory = new AzureDirectoryFeature(session).mkdir(new Path(intermediate, new AsciiRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
+ assertTrue(new AzureFindFeature(session).find(directory));
+ final Path test = new AzureTouchFeature(session).touch(
new Path(directory, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
- final AzureAttributesFinderFeature f = new AzureAttributesFinderFeature(session, null);
+ final AzureAttributesFinderFeature f = new AzureAttributesFinderFeature(session);
final PathAttributes attributes = f.find(container);
assertNotEquals(PathAttributes.EMPTY, attributes);
assertNotNull(attributes.getETag());
- assertNotNull(new AzureObjectListService(session, null).list(directory, new DisabledListProgressListener()).find(new DefaultPathPredicate(test)));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(directory), new DisabledLoginCallback(), new Delete.DisabledCallback());
- assertNotNull(new AzureObjectListService(session, null).list(directory, new DisabledListProgressListener()).find(new DefaultPathPredicate(test)));
+ assertNotNull(new AzureObjectListService(session).list(directory, new DisabledListProgressListener()).find(new DefaultPathPredicate(test)));
+ new AzureDeleteFeature(session).delete(Collections.singletonList(directory), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertNotNull(new AzureObjectListService(session).list(directory, new DisabledListProgressListener()).find(new DefaultPathPredicate(test)));
// Still found as prefix
- assertNotNull(new AzureObjectListService(session, null).list(container, new DisabledListProgressListener()).find(new DefaultPathPredicate(intermediate)));
- assertNotNull(new AzureObjectListService(session, null).list(intermediate, new DisabledListProgressListener()).find(new DefaultPathPredicate(directory)));
+ assertNotNull(new AzureObjectListService(session).list(container, new DisabledListProgressListener()).find(new DefaultPathPredicate(intermediate)));
+ assertNotNull(new AzureObjectListService(session).list(intermediate, new DisabledListProgressListener()).find(new DefaultPathPredicate(directory)));
// Ignore 404 failures
- assertSame(PathAttributes.EMPTY, new AzureAttributesFinderFeature(session, null).find(directory));
- assertSame(PathAttributes.EMPTY, new AzureAttributesFinderFeature(session, null).find(intermediate));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(directory), new DisabledLoginCallback(), new Delete.DisabledCallback());
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(container), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertSame(PathAttributes.EMPTY, new AzureAttributesFinderFeature(session).find(directory));
+ assertSame(PathAttributes.EMPTY, new AzureAttributesFinderFeature(session).find(intermediate));
+ new AzureDeleteFeature(session).delete(Collections.singletonList(directory), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(container), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureCopyFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureCopyFeatureTest.java
index e45b49d5cde..476f9b76afc 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureCopyFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureCopyFeatureTest.java
@@ -4,11 +4,14 @@
import ch.cyberduck.core.DisabledConnectionCallback;
import ch.cyberduck.core.DisabledLoginCallback;
import ch.cyberduck.core.Path;
+import ch.cyberduck.core.PathAttributes;
import ch.cyberduck.core.exception.UnsupportedException;
import ch.cyberduck.core.features.Delete;
import ch.cyberduck.core.features.Find;
import ch.cyberduck.core.io.DisabledStreamListener;
+import ch.cyberduck.core.io.StreamCancelation;
import ch.cyberduck.core.io.StreamCopier;
+import ch.cyberduck.core.io.StreamProgress;
import ch.cyberduck.core.shared.DefaultFindFeature;
import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.test.IntegrationTest;
@@ -31,10 +34,9 @@ public class AzureCopyFeatureTest extends AbstractAzureTest {
@Test
public void testCopy() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
- final Path test = new AzureTouchFeature(session, null).touch(
+ final Path test = new AzureTouchFeature(session).touch(
new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
- Thread.sleep(1000L);
- final AzureCopyFeature feature = new AzureCopyFeature(session, null);
+ final AzureCopyFeature feature = new AzureCopyFeature(session);
assertThrows(UnsupportedException.class, () -> feature.preflight(container, Optional.of(test)));
try {
feature.preflight(container, Optional.of(test));
@@ -45,30 +47,31 @@ public void testCopy() throws Exception {
}
final Path copy = feature.copy(test,
new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus(), new DisabledConnectionCallback(), new DisabledStreamListener());
- assertEquals(test.attributes().getChecksum(), copy.attributes().getChecksum());
- assertNotEquals(new AzureAttributesFinderFeature(session, null).find(test).getModificationDate(), new AzureAttributesFinderFeature(session, null).find(copy).getModificationDate());
- assertTrue(new AzureFindFeature(session, null).find(test));
- assertTrue(new AzureFindFeature(session, null).find(copy));
- new AzureDeleteFeature(session, null).delete(Arrays.asList(test, copy), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertEquals(PathAttributes.EMPTY, copy.attributes());
+ assertEquals(new AzureAttributesFinderFeature(session).find(test).getModificationDate(),
+ new AzureAttributesFinderFeature(session).find(copy).getModificationDate());
+ assertTrue(new AzureFindFeature(session).find(test));
+ assertTrue(new AzureFindFeature(session).find(copy));
+ new AzureDeleteFeature(session).delete(Arrays.asList(test, copy), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
public void testCopyToExistingFile() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path folder = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
- new AzureDirectoryFeature(session, null).mkdir(folder, new TransferStatus());
- final Path test = new AzureTouchFeature(session, null).touch(
+ new AzureDirectoryFeature(session).mkdir(folder, new TransferStatus());
+ final Path test = new AzureTouchFeature(session).touch(
new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
final byte[] content = RandomUtils.nextBytes(1023);
- final OutputStream out = new AzureWriteFeature(session, null).write(test, new TransferStatus().setLength(content.length), new DisabledConnectionCallback());
- new StreamCopier(new TransferStatus(), new TransferStatus()).transfer(new ByteArrayInputStream(content), out);
- final Path copy = new AzureTouchFeature(session, null).touch(
+ final OutputStream out = new AzureWriteFeature(session).write(test, new TransferStatus().setExists(true).setLength(content.length), new DisabledConnectionCallback());
+ new StreamCopier(StreamCancelation.noop, StreamProgress.noop).transfer(new ByteArrayInputStream(content), out);
+ final Path copy = new AzureTouchFeature(session).touch(
new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
- new AzureCopyFeature(session, null).copy(test, copy, new TransferStatus().setExists(true), new DisabledConnectionCallback(), new DisabledStreamListener());
- assertEquals(1023L, new AzureAttributesFinderFeature(session, null).find(copy).getSize());
+ new AzureCopyFeature(session).copy(test, copy, new TransferStatus().setExists(true), new DisabledConnectionCallback(), new DisabledStreamListener());
+ assertEquals(1023L, new AzureAttributesFinderFeature(session).find(copy).getSize());
final Find find = new DefaultFindFeature(session);
assertTrue(find.find(test));
assertTrue(find.find(copy));
- new AzureDeleteFeature(session, null).delete(Arrays.asList(test, copy), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Arrays.asList(test, copy), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureDeleteFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureDeleteFeatureTest.java
index ddaa7a9994b..347a96e2f0a 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureDeleteFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureDeleteFeatureTest.java
@@ -25,33 +25,33 @@ public class AzureDeleteFeatureTest extends AbstractAzureTest {
@Test(expected = NotfoundException.class)
public void testDeleteNotFoundBucket() throws Exception {
final Path container = new Path(new AsciiRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(container), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(container), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test(expected = NotfoundException.class)
public void testDeleteNotFoundKey() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
public void testDeletePlaceholder() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
- final Path test = new AzureDirectoryFeature(session, null).mkdir(new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(test));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
- assertFalse(new AzureFindFeature(session, null).find(test));
+ final Path test = new AzureDirectoryFeature(session).mkdir(new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
+ assertTrue(new AzureFindFeature(session).find(test));
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertFalse(new AzureFindFeature(session).find(test));
}
@Test
public void testDeleteKey() throws Exception {
final Path container = new Path(new AsciiRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.volume));
- new AzureDirectoryFeature(session, null).mkdir(container, new TransferStatus());
+ new AzureDirectoryFeature(session).mkdir(container, new TransferStatus());
final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureTouchFeature(session, null).touch(test, new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(test));
- new AzureDeleteFeature(session, null).delete(Arrays.asList(container, test), new DisabledLoginCallback(), new Delete.DisabledCallback());
- assertFalse(new AzureFindFeature(session, null).find(test));
+ new AzureTouchFeature(session).touch(test, new TransferStatus());
+ assertTrue(new AzureFindFeature(session).find(test));
+ new AzureDeleteFeature(session).delete(Arrays.asList(container, test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertFalse(new AzureFindFeature(session).find(test));
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureDirectoryFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureDirectoryFeatureTest.java
index d10a7ed4fed..d30a2ac4506 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureDirectoryFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureDirectoryFeatureTest.java
@@ -24,40 +24,42 @@ public class AzureDirectoryFeatureTest extends AbstractAzureTest {
@Test
public void testCreateContainer() throws Exception {
- final AzureDirectoryFeature feature = new AzureDirectoryFeature(session, null);
+ final AzureDirectoryFeature feature = new AzureDirectoryFeature(session);
final Path container = feature.mkdir(new Path(new AlphanumericRandomStringService().random().toLowerCase(), EnumSet.of(Path.Type.directory)), new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(container));
+ assertTrue(new AzureFindFeature(session).find(container));
+ assertEquals(PathAttributes.EMPTY, container.attributes());
assertThrows(ConflictException.class, () -> feature.mkdir(container, new TransferStatus()));
- new AzureTouchFeature(session, null).touch(new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(container), new DisabledLoginCallback(), new Delete.DisabledCallback());
- assertFalse(new AzureFindFeature(session, null).find(container));
+ new AzureTouchFeature(session).touch(new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(container), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertFalse(new AzureFindFeature(session).find(container));
}
@Test(expected = InteroperabilityException.class)
public void testCreateContainerInvalidName() throws Exception {
final Path container = new Path("untitled folder", EnumSet.of(Path.Type.directory));
- final AzureDirectoryFeature feature = new AzureDirectoryFeature(session, null);
+ final AzureDirectoryFeature feature = new AzureDirectoryFeature(session);
assertFalse(feature.isSupported(container.getParent(), container.getName()));
assertThrows(InvalidFilenameException.class, () -> feature.preflight(container.getParent(), container.getName()));
feature.mkdir(container, new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(container));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(container), new DisabledLoginCallback(), new Delete.DisabledCallback());
- assertFalse(new AzureFindFeature(session, null).find(container));
+ assertTrue(new AzureFindFeature(session).find(container));
+ new AzureDeleteFeature(session).delete(Collections.singletonList(container), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertFalse(new AzureFindFeature(session).find(container));
}
@Test
public void testCreatePlaceholder() throws Exception {
final Path container = new Path("/cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory));
- final Path placeholder = new AzureDirectoryFeature(session, null).mkdir(new Path(container, new AlphanumericRandomStringService().random(),
+ final Path placeholder = new AzureDirectoryFeature(session).mkdir(new Path(container, new AlphanumericRandomStringService().random(),
EnumSet.of(Path.Type.directory)), new TransferStatus());
assertTrue(placeholder.getType().contains(Path.Type.placeholder));
- assertTrue(new AzureFindFeature(session, null).find(placeholder));
+ assertTrue(new AzureFindFeature(session).find(placeholder));
+ assertEquals(PathAttributes.EMPTY, placeholder.attributes());
final Path file = new Path(placeholder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureTouchFeature(session, null).touch(file, new TransferStatus());
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(placeholder), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureTouchFeature(session).touch(file, new TransferStatus());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(placeholder), new DisabledLoginCallback(), new Delete.DisabledCallback());
// Still find common prefix
- assertTrue(new AzureFindFeature(session, null).find(placeholder));
- assertEquals(PathAttributes.EMPTY, new AzureAttributesFinderFeature(session, null).find(placeholder));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(file), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertTrue(new AzureFindFeature(session).find(placeholder));
+ assertEquals(PathAttributes.EMPTY, new AzureAttributesFinderFeature(session).find(placeholder));
+ new AzureDeleteFeature(session).delete(Collections.singletonList(file), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureFindFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureFindFeatureTest.java
index e253ecf22df..8af92f2af0f 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureFindFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureFindFeatureTest.java
@@ -41,55 +41,56 @@ public class AzureFindFeatureTest extends AbstractAzureTest {
@Test
public void testFindNotFound() throws Exception {
- assertFalse(new AzureFindFeature(session, null).find(new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file))));
+ final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
+ assertFalse(new AzureFindFeature(session).find(new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file))));
}
@Test
public void testFindHome() throws Exception {
- assertTrue(new AzureFindFeature(session, null).find(new DefaultHomeFinderService(session).find()));
+ assertTrue(new AzureFindFeature(session).find(new DefaultHomeFinderService(session).find()));
}
@Test
public void testFindDirectory() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
- final Path folder = new AzureDirectoryFeature(session, null).mkdir(
+ final Path folder = new AzureDirectoryFeature(session).mkdir(
new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(folder));
- assertFalse(new AzureFindFeature(session, null).find(new Path(folder.getAbsolute(), EnumSet.of(Path.Type.file))));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(folder), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertTrue(new AzureFindFeature(session).find(folder));
+ assertFalse(new AzureFindFeature(session).find(new Path(folder.getAbsolute(), EnumSet.of(Path.Type.file))));
+ new AzureDeleteFeature(session).delete(Collections.singletonList(folder), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
public void testFindFile() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path file = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureTouchFeature(session, null).touch(file, new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(file));
- assertFalse(new AzureFindFeature(session, null).find(new Path(file.getAbsolute(), EnumSet.of(Path.Type.directory))));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(file), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureTouchFeature(session).touch(file, new TransferStatus());
+ assertTrue(new AzureFindFeature(session).find(file));
+ assertFalse(new AzureFindFeature(session).find(new Path(file.getAbsolute(), EnumSet.of(Path.Type.directory))));
+ new AzureDeleteFeature(session).delete(Collections.singletonList(file), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
public void testFindCommonPrefix() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
- assertTrue(new AzureFindFeature(session, null).find(container));
+ assertTrue(new AzureFindFeature(session).find(container));
final String prefix = new AlphanumericRandomStringService().random();
final Path intermediate = new Path(container, prefix, EnumSet.of(Path.Type.directory));
- final Path test = new AzureTouchFeature(session, null).touch(new Path(intermediate, new AsciiRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(test));
- assertFalse(new AzureFindFeature(session, null).find(new Path(test.getAbsolute(), EnumSet.of(Path.Type.directory))));
- assertTrue(new AzureFindFeature(session, null).find(intermediate));
+ final Path test = new AzureTouchFeature(session).touch(new Path(intermediate, new AsciiRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
+ assertTrue(new AzureFindFeature(session).find(test));
+ assertFalse(new AzureFindFeature(session).find(new Path(test.getAbsolute(), EnumSet.of(Path.Type.directory))));
+ assertTrue(new AzureFindFeature(session).find(intermediate));
// Ignore 404 for placeholder and search for common prefix
- assertTrue(new AzureFindFeature(session, null).find(new Path(container, prefix, EnumSet.of(Path.Type.directory, Path.Type.placeholder))));
- assertTrue(new AzureObjectListService(session, null).list(intermediate,
+ assertTrue(new AzureFindFeature(session).find(new Path(container, prefix, EnumSet.of(Path.Type.directory, Path.Type.placeholder))));
+ assertTrue(new AzureObjectListService(session).list(intermediate,
new DisabledListProgressListener()).contains(test));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
- assertFalse(new AzureFindFeature(session, null).find(test));
- assertFalse(new AzureFindFeature(session, null).find(intermediate));
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertFalse(new AzureFindFeature(session).find(test));
+ assertFalse(new AzureFindFeature(session).find(intermediate));
final PathCache cache = new PathCache(1);
final Path directory = new Path(container, prefix, EnumSet.of(Path.Type.directory, Path.Type.placeholder));
- assertFalse(new CachingFindFeature(session, cache).find(directory));
- assertTrue(cache.isCached(directory.getParent()));
- assertFalse(new AzureFindFeature(session, null).find(new Path(container, prefix, EnumSet.of(Path.Type.directory, Path.Type.placeholder))));
+ assertFalse(new CachingFindFeature(session, cache, new AzureFindFeature(session)).find(directory));
+ assertFalse(cache.isCached(directory));
+ assertFalse(new AzureFindFeature(session).find(new Path(container, prefix, EnumSet.of(Path.Type.directory, Path.Type.placeholder))));
}
}
\ No newline at end of file
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureLoggingFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureLoggingFeatureTest.java
index 1dca5e2df54..39abb86cf5d 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureLoggingFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureLoggingFeatureTest.java
@@ -18,7 +18,7 @@ public class AzureLoggingFeatureTest extends AbstractAzureTest {
@Test
public void testSetConfiguration() throws Exception {
final Path container = new Path("/cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory));
- final AzureLoggingFeature feature = new AzureLoggingFeature(session, null);
+ final AzureLoggingFeature feature = new AzureLoggingFeature(session);
feature.setConfiguration(container, new LoggingConfiguration(false));
assertFalse(feature.getConfiguration(container).isEnabled());
feature.setConfiguration(container, new LoggingConfiguration(true));
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureMetadataFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureMetadataFeatureTest.java
index 726b8ad40aa..488da9a38d2 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureMetadataFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureMetadataFeatureTest.java
@@ -23,31 +23,27 @@ public class AzureMetadataFeatureTest extends AbstractAzureTest {
public void testSetMetadata() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureTouchFeature(session, null).touch(test, new TransferStatus());
- final TransferStatus status = new TransferStatus();
+ new AzureTouchFeature(session).touch(test, new TransferStatus());
final String v = new AlphanumericRandomStringService().random();
- final AzureMetadataFeature feature = new AzureMetadataFeature(session, null);
- feature.setMetadata(test, status.setMetadata(Collections.singletonMap("Test", v)));
- final Map metadata = feature.getMetadata(test);
+ new AzureMetadataFeature(session).setMetadata(test, Collections.singletonMap("Test", v));
+ final Map metadata = new AzureMetadataFeature(session).getMetadata(test);
assertFalse(metadata.isEmpty());
assertTrue(metadata.containsKey("Test"));
assertEquals(v, metadata.get("Test"));
- feature.setMetadata(test, status.setMetadata(Collections.emptyMap()));
- assertFalse(feature.getMetadata(test).containsKey("Test"));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
public void testSetCacheControl() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureTouchFeature(session, null).touch(test, new TransferStatus());
- final AzureMetadataFeature service = new AzureMetadataFeature(session, null);
+ new AzureTouchFeature(session).touch(test, new TransferStatus());
+ final AzureMetadataFeature service = new AzureMetadataFeature(session);
service.setMetadata(test, Collections.singletonMap("Cache-Control", "public, max-age=0"));
final Map metadata = service.getMetadata(test);
assertFalse(metadata.isEmpty());
assertTrue(metadata.containsKey("Cache-Control"));
assertEquals("public, max-age=0", metadata.get("Cache-Control"));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureMoveFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureMoveFeatureTest.java
index 16f2b54cbb3..6f1ab998934 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureMoveFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureMoveFeatureTest.java
@@ -6,6 +6,8 @@
import ch.cyberduck.core.Path;
import ch.cyberduck.core.PathAttributes;
import ch.cyberduck.core.features.Delete;
+import ch.cyberduck.core.synchronization.Comparison;
+import ch.cyberduck.core.synchronization.ComparisonService;
import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.test.IntegrationTest;
@@ -16,8 +18,7 @@
import java.util.EnumSet;
import java.util.Optional;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
@Category(IntegrationTest.class)
public class AzureMoveFeatureTest extends AbstractAzureTest {
@@ -25,20 +26,22 @@ public class AzureMoveFeatureTest extends AbstractAzureTest {
@Test
public void testMove() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
- final Path test = new AzureTouchFeature(session, null).touch(new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(test));
- final Path target = new AzureMoveFeature(session, null).move(test, new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus(), new Delete.DisabledCallback(), new DisabledConnectionCallback());
- assertFalse(new AzureFindFeature(session, null).find(test));
- assertTrue(new AzureFindFeature(session, null).find(target));
- final PathAttributes targetAttr = new AzureAttributesFinderFeature(session, null).find(target);
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(target), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ final Path test = new AzureTouchFeature(session).touch(new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
+ final PathAttributes sourceAttr = new AzureAttributesFinderFeature(session).find(test);
+ assertTrue(new AzureFindFeature(session).find(test));
+ final Path target = new AzureMoveFeature(session).move(test, new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus(), new Delete.DisabledCallback(), new DisabledConnectionCallback());
+ assertFalse(new AzureFindFeature(session).find(test));
+ assertTrue(new AzureFindFeature(session).find(target));
+ final PathAttributes targetAttr = new AzureAttributesFinderFeature(session).find(target);
+ assertEquals(Comparison.equal, session.getHost().getProtocol().getFeature(ComparisonService.class).compare(Path.Type.file, sourceAttr, targetAttr));
+ new AzureDeleteFeature(session).delete(Collections.singletonList(target), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
public void testSupport() {
final Path c = new Path("/c", EnumSet.of(Path.Type.directory));
- assertFalse(new AzureMoveFeature(session, null).isSupported(c, Optional.of(new Path("/d", EnumSet.of(Path.Type.directory)))));
+ assertFalse(new AzureMoveFeature(session).isSupported(c, Optional.of(new Path("/d", EnumSet.of(Path.Type.directory)))));
final Path cf = new Path("/c/f", EnumSet.of(Path.Type.directory));
- assertTrue(new AzureMoveFeature(session, null).isSupported(cf, Optional.of(new Path("/c/f2", EnumSet.of(Path.Type.directory)))));
+ assertTrue(new AzureMoveFeature(session).isSupported(cf, Optional.of(new Path("/c/f2", EnumSet.of(Path.Type.directory)))));
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureObjectListServiceTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureObjectListServiceTest.java
index da56dc923bb..523c018922e 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureObjectListServiceTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureObjectListServiceTest.java
@@ -6,9 +6,9 @@
import ch.cyberduck.core.DisabledLoginCallback;
import ch.cyberduck.core.IndexedListProgressListener;
import ch.cyberduck.core.Path;
+import ch.cyberduck.core.PathAttributes;
import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.features.Delete;
-import ch.cyberduck.core.io.HashAlgorithm;
import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.test.IntegrationTest;
@@ -30,15 +30,15 @@ public class AzureObjectListServiceTest extends AbstractAzureTest {
@Test(expected = NotfoundException.class)
public void testListNotFoundFolder() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
- new AzureObjectListService(session, null).list(new Path(container, "notfound", EnumSet.of(Path.Type.directory)), new DisabledListProgressListener());
+ new AzureObjectListService(session).list(new Path(container, "notfound", EnumSet.of(Path.Type.directory)), new DisabledListProgressListener());
}
@Test
public void testListEmptyFolder() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
- final Path folder = new AzureDirectoryFeature(session, null).mkdir(new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
+ final Path folder = new AzureDirectoryFeature(session).mkdir(new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
final AtomicBoolean callback = new AtomicBoolean();
- assertTrue(new AzureObjectListService(session, null).list(folder, new DisabledListProgressListener() {
+ assertTrue(new AzureObjectListService(session).list(folder, new DisabledListProgressListener() {
@Override
public void chunk(final Path parent, final AttributedList list) {
assertNotSame(AttributedList.EMPTY, list);
@@ -46,45 +46,46 @@ public void chunk(final Path parent, final AttributedList list) {
}
}).isEmpty());
assertTrue(callback.get());
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(folder), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(folder), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test(expected = NotfoundException.class)
public void testListNotfoundContainer() throws Exception {
final Path container = new Path("notfound-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
- new AzureObjectListService(session, null).list(container, new DisabledListProgressListener());
+ new AzureObjectListService(session).list(container, new DisabledListProgressListener());
}
@Test
public void testList() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
- final Path directory = new AzureDirectoryFeature(session, null).mkdir(new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
+ final Path directory = new AzureDirectoryFeature(session).mkdir(new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
final Path file = new Path(directory, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- assertTrue(new AzureObjectListService(session, null).list(directory, new DisabledListProgressListener()).isEmpty());
- new AzureTouchFeature(session, null).touch(file, new TransferStatus());
- final AttributedList list = new AzureObjectListService(session, null).list(directory, new DisabledListProgressListener());
+ assertTrue(new AzureObjectListService(session).list(directory, new DisabledListProgressListener()).isEmpty());
+ new AzureTouchFeature(session).touch(file, new TransferStatus());
+ final AttributedList list = new AzureObjectListService(session).list(directory, new DisabledListProgressListener());
assertFalse(list.isEmpty());
assertEquals(1, list.size());
assertTrue(list.contains(file));
- assertEquals(HashAlgorithm.md5, list.get(0).attributes().getChecksum().algorithm);
+ final PathAttributes attributes = list.get(0).attributes();
+ assertEquals(attributes, new AzureAttributesFinderFeature(session).find(file));
assertSame(directory, list.get(0).getParent());
- new AzureDeleteFeature(session, null).delete(Arrays.asList(file, directory), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Arrays.asList(file, directory), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
public void testListLexicographicSortOrderAssumption() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory));
- final Path directory = new AzureDirectoryFeature(session, null).mkdir(
+ final Path directory = new AzureDirectoryFeature(session).mkdir(
new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
- assertTrue(new AzureObjectListService(session, null).list(directory, new DisabledListProgressListener()).isEmpty());
+ assertTrue(new AzureObjectListService(session).list(directory, new DisabledListProgressListener()).isEmpty());
final List files = Arrays.asList(
"Z", "aa", "0a", "a", "AAA", "B", "~$a", ".c"
);
for(String f : files) {
- new AzureTouchFeature(session, null).touch(new Path(directory, f, EnumSet.of(Path.Type.file)), new TransferStatus());
+ new AzureTouchFeature(session).touch(new Path(directory, f, EnumSet.of(Path.Type.file)), new TransferStatus());
}
files.sort(session.getHost().getProtocol().getListComparator());
- final AttributedList list = new AzureObjectListService(session, null).list(directory, new IndexedListProgressListener() {
+ final AttributedList list = new AzureObjectListService(session).list(directory, new IndexedListProgressListener() {
@Override
public void message(final String message) {
//
@@ -97,8 +98,8 @@ public void visit(final AttributedList list, final int index, final Path f
});
for(int i = 0; i < list.size(); i++) {
assertEquals(files.get(i), list.get(i).getName());
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(list.get(i)), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(list.get(i)), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(directory), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(directory), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureReadFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureReadFeatureTest.java
index aa8184ff6d6..3411acbafbf 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureReadFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureReadFeatureTest.java
@@ -6,7 +6,9 @@
import ch.cyberduck.core.Path;
import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.features.Delete;
+import ch.cyberduck.core.io.StreamCancelation;
import ch.cyberduck.core.io.StreamCopier;
+import ch.cyberduck.core.io.StreamProgress;
import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.test.IntegrationTest;
@@ -31,34 +33,34 @@ public class AzureReadFeatureTest extends AbstractAzureTest {
public void testReadNotFound() throws Exception {
final TransferStatus status = new TransferStatus();
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
- new AzureReadFeature(session, null).read(new Path(container, "nosuchname", EnumSet.of(Path.Type.file)), status, new DisabledConnectionCallback());
+ new AzureReadFeature(session).read(new Path(container, "nosuchname", EnumSet.of(Path.Type.file)), status, new DisabledConnectionCallback());
}
@Test
public void testReadZeroLength() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureTouchFeature(session, null).touch(test, new TransferStatus());
- final InputStream in = new AzureReadFeature(session, null).read(test, new TransferStatus().setLength(0L), new DisabledConnectionCallback());
+ new AzureTouchFeature(session).touch(test, new TransferStatus());
+ final InputStream in = new AzureReadFeature(session).read(test, new TransferStatus().setLength(0L), new DisabledConnectionCallback());
assertNotNull(in);
in.close();
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
public void testReadRange() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureTouchFeature(session, null).touch(test, new TransferStatus());
+ new AzureTouchFeature(session).touch(test, new TransferStatus());
final byte[] content = RandomUtils.nextBytes(1023);
- final OutputStream out = new AzureWriteFeature(session, null).write(test, new TransferStatus().setLength(content.length), new DisabledConnectionCallback());
+ final OutputStream out = new AzureWriteFeature(session).write(test, new TransferStatus().setExists(true).setLength(content.length), new DisabledConnectionCallback());
assertNotNull(out);
- new StreamCopier(new TransferStatus(), new TransferStatus()).transfer(new ByteArrayInputStream(content), out);
+ new StreamCopier(StreamCancelation.noop, StreamProgress.noop).transfer(new ByteArrayInputStream(content), out);
final TransferStatus status = new TransferStatus();
status.setLength(content.length);
status.setAppend(true);
status.setOffset(100L);
- final InputStream in = new AzureReadFeature(session, null).read(test, status, new DisabledConnectionCallback());
+ final InputStream in = new AzureReadFeature(session).read(test, status, new DisabledConnectionCallback());
assertNotNull(in);
final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length - 100);
new StreamCopier(status, status).transfer(in, buffer);
@@ -68,6 +70,6 @@ public void testReadRange() throws Exception {
in.close();
// Test double close
in.close();
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureSessionTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureSessionTest.java
index 384b28259ee..a7a27293ab0 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureSessionTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureSessionTest.java
@@ -9,16 +9,26 @@
import ch.cyberduck.core.Host;
import ch.cyberduck.core.LoginConnectionService;
import ch.cyberduck.core.LoginOptions;
+import ch.cyberduck.core.Profile;
+import ch.cyberduck.core.ProtocolFactory;
import ch.cyberduck.core.exception.LoginCanceledException;
import ch.cyberduck.core.features.AclPermission;
import ch.cyberduck.core.features.Delete;
import ch.cyberduck.core.features.Directory;
import ch.cyberduck.core.features.Touch;
+import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader;
+import ch.cyberduck.core.ssl.DefaultX509KeyManager;
+import ch.cyberduck.core.ssl.DisabledX509TrustManager;
import ch.cyberduck.test.IntegrationTest;
+import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.junit.experimental.categories.Category;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import static org.junit.Assert.*;
@Category(IntegrationTest.class)
@@ -33,8 +43,59 @@ public void testFeatures() {
}
@Test
- public void testConnect() throws Exception {
+ public void testConnect() {
+ assertTrue(session.isConnected());
+ }
+
+ @Test
+ public void testConnectSharedAccessSignature() throws Exception {
+ final ProtocolFactory factory = new ProtocolFactory(new HashSet<>(Collections.singleton(new AzureProtocol())));
+ final Profile profile = new ProfilePlistReader(factory).read(
+ this.getClass().getResourceAsStream("/Azure (Shared Access Signature Token).cyberduckprofile"));
+ final Host host = new Host(profile, "kahy9boj3eib.blob.core.windows.net", new Credentials(
+ PROPERTIES.get("azure.user"), null, PROPERTIES.get("azure.token")
+ ));
+ AzureSession session = new AzureSession(host, new DisabledX509TrustManager(), new DefaultX509KeyManager());
+ final LoginConnectionService login = new LoginConnectionService(new DisabledLoginCallback() {
+ @Override
+ public Credentials prompt(final Host bookmark, final String username, final String title, final String reason, final LoginOptions options) {
+ fail(reason);
+ return null;
+ }
+ }, new DisabledHostKeyCallback(),
+ new DisabledPasswordStore(), new DisabledProgressListener());
+ login.connect(session, new DisabledCancelCallback());
+ session.close();
+ }
+
+ @Test
+ public void testConnectSharedAccessSignaturePrompt() throws Exception {
+ final ProtocolFactory factory = new ProtocolFactory(new HashSet<>(Collections.singleton(new AzureProtocol())));
+ final Profile profile = new ProfilePlistReader(factory).read(
+ this.getClass().getResourceAsStream("/Azure (Shared Access Signature Token).cyberduckprofile"));
+ final Host host = new Host(profile, "kahy9boj3eib.blob.core.windows.net", new Credentials(
+ null, null, "?sv=2017-07-29&ss=bfqt&srt=sco&sp=rwdlacup&se=2030-05-20T04:29:30Z&st=2018-05-09T20:29:30Z&spr=https&sig=invalidbMKAZ3tXmX%2B56%2Bb5JhHAeWnMOpMp%2BoYlHDIAZVAjHzE%3D"));
+ final AzureSession session = new AzureSession(host);
+ final AtomicBoolean prompt = new AtomicBoolean();
+ final LoginConnectionService connect = new LoginConnectionService(new DisabledLoginCallback() {
+ @Override
+ public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) throws LoginCanceledException {
+ if(prompt.get()) {
+ throw new LoginCanceledException();
+ }
+ try {
+ return new Credentials(StringUtils.EMPTY, "?sv=2017-07-29&ss=bfqt&srt=sco&sp=rwdlacup&se=2030-05-20T04:29:30Z&st=2018-05-09T20:29:30Z&spr=https&sig=bMKAZ3tXmX%2B56%2Bb5JhHAeWnMOpMp%2BoYlHDIAZVAjHzE%3D");
+ }
+ finally {
+ prompt.set(true);
+ }
+ }
+ }, new DisabledHostKeyCallback(),
+ new DisabledPasswordStore(), new DisabledProgressListener());
+ connect.connect(session, new DisabledCancelCallback());
assertTrue(session.isConnected());
+ connect.close(session);
+ assertFalse(session.isConnected());
}
@Test(expected = LoginCanceledException.class)
@@ -47,7 +108,6 @@ public void testConnectInvalidKey() throws Exception {
@Override
public Credentials prompt(final Host bookmark, String username, String title, String reason, LoginOptions options) throws LoginCanceledException {
assertEquals("Login kahy9boj3eib.blob.core.windows.net", title);
- assertEquals("Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. Please contact your web hosting service provider for assistance.", reason);
return super.prompt(bookmark, username, title, reason, options);
}
}, new DisabledHostKeyCallback(),
@@ -64,7 +124,6 @@ public void testConnectKeyNotBase64() throws Exception {
@Override
public Credentials prompt(final Host bookmark, String username, String title, String reason, LoginOptions options) throws LoginCanceledException {
assertEquals("Login kahy9boj3eib.blob.core.windows.net", title);
- assertEquals("Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. Please contact your web hosting service provider for assistance.", reason);
return super.prompt(bookmark, username, title, reason, options);
}
}, new DisabledHostKeyCallback(),
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureTouchFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureTouchFeatureTest.java
index d337a3b0f56..5e9d49a8be8 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureTouchFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureTouchFeatureTest.java
@@ -36,14 +36,14 @@ public class AzureTouchFeatureTest extends AbstractAzureTest {
public void testTouchFileStartWithDot() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path test = new Path(container, String.format(".%s.", new AlphanumericRandomStringService().random()), EnumSet.of(Path.Type.file));
- new AzureTouchFeature(session, null).touch(test, new TransferStatus());
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureTouchFeature(session).touch(test, new TransferStatus());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
public void testPreflightFilename() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
- final AzureTouchFeature feature = new AzureTouchFeature(session, null);
+ final AzureTouchFeature feature = new AzureTouchFeature(session);
feature.preflight(container, new AsciiRandomStringService().random());
feature.preflight(container, new AlphanumericRandomStringService().random());
feature.preflight(container, String.format("%s.suffix", new AlphanumericRandomStringService().random()));
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureUrlProviderTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureUrlProviderTest.java
index 913e5121e8e..e13cd028989 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureUrlProviderTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureUrlProviderTest.java
@@ -1,9 +1,10 @@
package ch.cyberduck.core.azure;
import ch.cyberduck.core.AlphanumericRandomStringService;
-import ch.cyberduck.core.Credentials;
import ch.cyberduck.core.DescriptiveUrl;
+import ch.cyberduck.core.DescriptiveUrlBag;
import ch.cyberduck.core.DisabledLoginCallback;
+import ch.cyberduck.core.DisabledPasswordStore;
import ch.cyberduck.core.Host;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.features.Delete;
@@ -17,6 +18,7 @@
import java.util.EnumSet;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
@Category(IntegrationTest.class)
public class AzureUrlProviderTest extends AbstractAzureTest {
@@ -24,21 +26,18 @@ public class AzureUrlProviderTest extends AbstractAzureTest {
@Test
public void testGet() throws Exception {
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
- final Path test = new Path(container, "f g", EnumSet.of(Path.Type.file));
- new AzureTouchFeature(session, null).touch(test, new TransferStatus());
- assertEquals(5, new AzureUrlProvider(session).toUrl(test).filter(DescriptiveUrl.Type.signed).size());
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
- }
-
- @Test
- public void testDisconnected() throws Exception {
- final Host host = new Host(new AzureProtocol(), "kahy9boj3eib.blob.core.windows.net", new Credentials(
- PROPERTIES.get("azure.user"), PROPERTIES.get("azure.key")
- ));
- final AzureSession session = new AzureSession(host);
- final AzureUrlProvider provider = new AzureUrlProvider(session);
- final Path container = new Path("test.cyberduck.ch", EnumSet.of(Path.Type.directory, Path.Type.volume));
- final Path file = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- assertEquals(DescriptiveUrl.EMPTY.getUrl(), provider.toUrl(file).find(DescriptiveUrl.Type.signed).getUrl());
+ final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
+ new AzureTouchFeature(session).touch(test, new TransferStatus());
+ final DescriptiveUrlBag urls = new AzureUrlProvider(session, new DisabledPasswordStore() {
+ @Override
+ public String findLoginPassword(final Host bookmark) {
+ return PROPERTIES.get("azure.password");
+ }
+ }).toUrl(test).filter(DescriptiveUrl.Type.signed);
+ assertEquals(5, urls.size());
+ for(DescriptiveUrl url : urls) {
+ assertFalse(url.getUrl().isEmpty());
+ }
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AzureWriteFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AzureWriteFeatureTest.java
index 4ae8e1faefe..6155eee9289 100644
--- a/azure/src/test/java/ch/cyberduck/core/azure/AzureWriteFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/azure/AzureWriteFeatureTest.java
@@ -7,7 +7,9 @@
import ch.cyberduck.core.PathAttributes;
import ch.cyberduck.core.features.Delete;
import ch.cyberduck.core.io.MD5ChecksumCompute;
+import ch.cyberduck.core.io.StreamCancelation;
import ch.cyberduck.core.io.StreamCopier;
+import ch.cyberduck.core.io.StreamProgress;
import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.test.IntegrationTest;
@@ -24,8 +26,7 @@
import java.util.EnumSet;
import java.util.Map;
-import com.microsoft.azure.storage.OperationContext;
-import com.microsoft.azure.storage.blob.BlobType;
+import com.azure.storage.blob.models.BlobType;
import static org.junit.Assert.*;
@@ -34,8 +35,6 @@ public class AzureWriteFeatureTest extends AbstractAzureTest {
@Test
public void testWriteOverrideAppendBlob() throws Exception {
- final OperationContext context
- = new OperationContext();
final TransferStatus status = new TransferStatus();
status.setMime("text/plain");
final byte[] content = RandomUtils.nextBytes(513);
@@ -44,35 +43,33 @@ public void testWriteOverrideAppendBlob() throws Exception {
status.setMetadata(Collections.singletonMap("Cache-Control", "public,max-age=86400"));
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- final OutputStream out = new AzureWriteFeature(session, BlobType.APPEND_BLOB, context).write(test, status, new DisabledConnectionCallback());
+ final OutputStream out = new AzureWriteFeature(session, BlobType.APPEND_BLOB).write(test, status, new DisabledConnectionCallback());
assertNotNull(out);
- new StreamCopier(new TransferStatus(), new TransferStatus()).transfer(new ByteArrayInputStream(content), out);
- assertTrue(new AzureFindFeature(session, context).find(test));
- final PathAttributes attributes = new AzureAttributesFinderFeature(session, context).find(test);
+ new StreamCopier(StreamCancelation.noop, StreamProgress.noop).transfer(new ByteArrayInputStream(content), out);
+ assertTrue(new AzureFindFeature(session).find(test));
+ final PathAttributes attributes = new AzureAttributesFinderFeature(session).find(test);
assertEquals(content.length, attributes.getSize());
- final Map metadata = new AzureMetadataFeature(session, context).getMetadata(test);
+ final Map metadata = new AzureMetadataFeature(session).getMetadata(test);
assertEquals("text/plain", metadata.get("Content-Type"));
assertEquals("public,max-age=86400", metadata.get("Cache-Control"));
final byte[] buffer = new byte[content.length];
- final InputStream in = new AzureReadFeature(session, context).read(test, new TransferStatus(), new DisabledConnectionCallback());
+ final InputStream in = new AzureReadFeature(session).read(test, new TransferStatus(), new DisabledConnectionCallback());
IOUtils.readFully(in, buffer);
in.close();
assertArrayEquals(content, buffer);
- final OutputStream overwrite = new AzureWriteFeature(session, context).write(test, new TransferStatus().setExists(true)
+ final OutputStream overwrite = new AzureWriteFeature(session).write(test, new TransferStatus().setExists(true)
.setLength("overwrite".getBytes(StandardCharsets.UTF_8).length).setMetadata(Collections.singletonMap("Content-Type", "text/plain")), new DisabledConnectionCallback());
- new StreamCopier(new TransferStatus(), new TransferStatus())
+ new StreamCopier(StreamCancelation.noop, StreamProgress.noop)
.transfer(new ByteArrayInputStream("overwrite".getBytes(StandardCharsets.UTF_8)), overwrite);
overwrite.close();
// Test double close
overwrite.close();
- assertEquals("overwrite".getBytes(StandardCharsets.UTF_8).length, new AzureAttributesFinderFeature(session, context).find(test).getSize());
- new AzureDeleteFeature(session, context).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertEquals("overwrite".getBytes(StandardCharsets.UTF_8).length, new AzureAttributesFinderFeature(session).find(test).getSize());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
public void testWriteOverrideBlockBlob() throws Exception {
- final OperationContext context
- = new OperationContext();
final TransferStatus status = new TransferStatus();
status.setMime("text/plain");
final byte[] content = RandomUtils.nextBytes(513);
@@ -81,28 +78,28 @@ public void testWriteOverrideBlockBlob() throws Exception {
status.setMetadata(Collections.singletonMap("Cache-Control", "public,max-age=86400"));
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- final OutputStream out = new AzureWriteFeature(session, BlobType.BLOCK_BLOB, context).write(test, status, new DisabledConnectionCallback());
+ final OutputStream out = new AzureWriteFeature(session, BlobType.BLOCK_BLOB).write(test, status, new DisabledConnectionCallback());
assertNotNull(out);
- new StreamCopier(new TransferStatus(), new TransferStatus()).transfer(new ByteArrayInputStream(content), out);
- assertTrue(new AzureFindFeature(session, context).find(test));
- final PathAttributes attributes = new AzureAttributesFinderFeature(session, context).find(test);
+ new StreamCopier(StreamCancelation.noop, StreamProgress.noop).transfer(new ByteArrayInputStream(content), out);
+ assertTrue(new AzureFindFeature(session).find(test));
+ final PathAttributes attributes = new AzureAttributesFinderFeature(session).find(test);
assertEquals(content.length, attributes.getSize());
- final Map metadata = new AzureMetadataFeature(session, context).getMetadata(test);
+ final Map metadata = new AzureMetadataFeature(session).getMetadata(test);
assertEquals("text/plain", metadata.get("Content-Type"));
assertEquals("public,max-age=86400", metadata.get("Cache-Control"));
final byte[] buffer = new byte[content.length];
- final InputStream in = new AzureReadFeature(session, context).read(test, new TransferStatus(), new DisabledConnectionCallback());
+ final InputStream in = new AzureReadFeature(session).read(test, new TransferStatus(), new DisabledConnectionCallback());
IOUtils.readFully(in, buffer);
in.close();
assertArrayEquals(content, buffer);
- final OutputStream overwrite = new AzureWriteFeature(session, context).write(test, new TransferStatus().setExists(true)
+ final OutputStream overwrite = new AzureWriteFeature(session).write(test, new TransferStatus().setExists(true)
.setLength("overwrite".getBytes(StandardCharsets.UTF_8).length).setMetadata(Collections.singletonMap("Content-Type", "text/plain")), new DisabledConnectionCallback());
- new StreamCopier(new TransferStatus(), new TransferStatus())
+ new StreamCopier(StreamCancelation.noop, StreamProgress.noop)
.transfer(new ByteArrayInputStream("overwrite".getBytes(StandardCharsets.UTF_8)), overwrite);
overwrite.close();
// Test double close
overwrite.close();
- assertEquals("overwrite".getBytes(StandardCharsets.UTF_8).length, new AzureAttributesFinderFeature(session, context).find(test).getSize());
- new AzureDeleteFeature(session, context).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertEquals("overwrite".getBytes(StandardCharsets.UTF_8).length, new AzureAttributesFinderFeature(session).find(test).getSize());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureDirectoryFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureDirectoryFeatureTest.java
index 441bb645c9f..5f03c1f902d 100644
--- a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureDirectoryFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureDirectoryFeatureTest.java
@@ -53,10 +53,11 @@ public void testMakeDirectoryEncrypted() throws Exception {
new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)));
final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator));
- final Path test = cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session, null)).mkdir(new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
+ final Path test = cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir(
+ new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
assertTrue(test.getType().contains(Path.Type.placeholder));
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(test));
- cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session, null)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
@@ -67,8 +68,9 @@ public void testMakeDirectoryLongFilenameEncrypted() throws Exception {
new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)));
final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator));
- final Path test = cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session, null)).mkdir(new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
+ final Path test = cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir(
+ new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(test));
- cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session, null)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureListServiceTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureListServiceTest.java
index 559ba25e8e5..ea279109762 100644
--- a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureListServiceTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureListServiceTest.java
@@ -16,25 +16,17 @@
*/
import ch.cyberduck.core.AlphanumericRandomStringService;
-import ch.cyberduck.core.AttributedList;
-import ch.cyberduck.core.Cache;
-import ch.cyberduck.core.CachingFindFeature;
import ch.cyberduck.core.DisabledListProgressListener;
import ch.cyberduck.core.DisabledLoginCallback;
import ch.cyberduck.core.DisabledPasswordCallback;
import ch.cyberduck.core.Path;
-import ch.cyberduck.core.PathCache;
import ch.cyberduck.core.azure.AbstractAzureTest;
import ch.cyberduck.core.azure.AzureDeleteFeature;
-import ch.cyberduck.core.azure.AzureFindFeature;
import ch.cyberduck.core.azure.AzureObjectListService;
import ch.cyberduck.core.azure.AzureWriteFeature;
-import ch.cyberduck.core.cryptomator.features.CryptoFindFeature;
import ch.cyberduck.core.cryptomator.features.CryptoListService;
import ch.cyberduck.core.cryptomator.features.CryptoTouchFeature;
-import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.features.Delete;
-import ch.cyberduck.core.shared.DefaultFindFeature;
import ch.cyberduck.core.shared.DefaultTouchFeature;
import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.core.vault.DefaultVaultRegistry;
@@ -48,9 +40,9 @@
import java.util.Arrays;
import java.util.EnumSet;
-import java.util.Optional;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
@Category(IntegrationTest.class)
@RunWith(value = Parameterized.class)
@@ -64,40 +56,9 @@ public void testListCryptomator() throws Exception {
final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator));
final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- assertTrue(new CryptoListService(session, new AzureObjectListService(session, null), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty());
- new CryptoTouchFeature<>(session, new DefaultTouchFeature<>(new AzureWriteFeature(session, null)), new AzureWriteFeature(session, null), cryptomator).touch(test, new TransferStatus());
- assertEquals(test, new CryptoListService(session, new AzureObjectListService(session, null), cryptomator).list(vault, new DisabledListProgressListener() {
- @Override
- public void cleanup(final Path directory, final AttributedList list, final Optional e) {
- assertEquals(vault, directory);
- for(Path f : list) {
- assertTrue(f.getType().contains(Path.Type.decrypted));
- }
- }
-
- @Override
- public void chunk(final Path directory, final AttributedList list) {
- assertEquals(vault, directory);
- for(Path f : list) {
- assertTrue(f.getType().contains(Path.Type.decrypted));
- }
- }
- }).get(0));
- {
- final Cache cache = new PathCache(1);
- assertTrue(new CachingFindFeature(session, cache, new CryptoFindFeature(session, new AzureFindFeature(session, null), cryptomator)).find(test));
- assertFalse(cache.isCached(vault));
- }
- {
- final Cache cache = new PathCache(1);
- assertTrue(new CachingFindFeature(session, cache, new CryptoFindFeature(session, new DefaultFindFeature(session), cryptomator)).find(test));
- assertTrue(cache.isCached(vault));
- final AttributedList list = cache.get(vault);
- assertFalse(list.isEmpty());
- for(Path f : list) {
- assertTrue(f.getType().contains(Path.Type.decrypted));
- }
- }
- cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session, null)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertTrue(new CryptoListService(session, new AzureObjectListService(session), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty());
+ new CryptoTouchFeature<>(session, new DefaultTouchFeature<>(new AzureWriteFeature(session)), new AzureWriteFeature(session), cryptomator).touch(test, new TransferStatus());
+ assertEquals(test, new CryptoListService(session, new AzureObjectListService(session), cryptomator).list(vault, new DisabledListProgressListener()).get(0));
+ cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureMoveFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureMoveFeatureTest.java
index 7ddc3603075..f6103e1a155 100644
--- a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureMoveFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureMoveFeatureTest.java
@@ -60,25 +60,25 @@ public void testMove() throws Exception {
new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)));
final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator));
- final Path folder = cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session, null)).mkdir(
+ final Path folder = cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir(
new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
- final Path file = new CryptoTouchFeature(session, new AzureTouchFeature(session, null), new AzureWriteFeature(session, null), cryptomator).touch(
+ final Path file = new CryptoTouchFeature<>(session, new AzureTouchFeature(session), new AzureWriteFeature(session), cryptomator).touch(
new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(file));
- final Move move = cryptomator.getFeature(session, Move.class, new AzureMoveFeature(session, null));
+ final Move move = cryptomator.getFeature(session, Move.class, new AzureMoveFeature(session));
// rename file
final Path fileRenamed = new Path(folder, "f1", EnumSet.of(Path.Type.file));
move.move(file, fileRenamed, new TransferStatus(), new Delete.DisabledCallback(), new DisabledConnectionCallback());
- assertFalse(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(file));
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(fileRenamed));
+ assertFalse(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(file));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(fileRenamed));
// rename folder
final Path folderRenamed = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.placeholder));
move.move(folder, folderRenamed, new TransferStatus(), new Delete.DisabledCallback(), new DisabledConnectionCallback());
- assertFalse(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(folder));
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(folderRenamed));
+ assertFalse(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(folder));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(folderRenamed));
final Path fileRenamedInRenamedFolder = new Path(folderRenamed, "f1", EnumSet.of(Path.Type.file));
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(fileRenamedInRenamedFolder));
- cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session, null)).delete(Arrays.asList(
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(fileRenamedInRenamedFolder));
+ cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session)).delete(Arrays.asList(
fileRenamedInRenamedFolder, folderRenamed, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureTouchFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureTouchFeatureTest.java
index 2a00e512e70..972d952dd29 100644
--- a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureTouchFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureTouchFeatureTest.java
@@ -58,12 +58,12 @@ public void testTouchLongFilenameEncrypted() throws Exception {
final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator));
final TransferStatus status = new TransferStatus();
- final Path test = new CryptoTouchFeature<>(session, new AzureTouchFeature(session, null), new AzureWriteFeature(session, null), cryptomator).touch(
+ final Path test = new CryptoTouchFeature<>(session, new AzureTouchFeature(session), new AzureWriteFeature(session), cryptomator).touch(
new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)), status);
assertEquals(TransferStatus.UNKNOWN_LENGTH, test.attributes().getSize());
assertEquals(TransferStatus.UNKNOWN_LENGTH, status.getResponse().getSize());
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(test));
- cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session, null)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(test));
+ cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
@Test
@@ -75,11 +75,11 @@ public void testTouchLongFilenameEncryptedDefaultFeature() throws Exception {
final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator));
final TransferStatus status = new TransferStatus();
- final Path test = new CryptoTouchFeature<>(session, new AzureTouchFeature(session, null), new AzureWriteFeature(session, null), cryptomator).touch(
+ final Path test = new CryptoTouchFeature<>(session, new AzureTouchFeature(session), new AzureWriteFeature(session), cryptomator).touch(
new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)), status);
assertEquals(TransferStatus.UNKNOWN_LENGTH, test.attributes().getSize());
assertEquals(TransferStatus.UNKNOWN_LENGTH, status.getResponse().getSize());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(test));
- cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session, null)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureWriteFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureWriteFeatureTest.java
index 910c30a75dc..a11d3355b97 100644
--- a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureWriteFeatureTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureWriteFeatureTest.java
@@ -54,8 +54,6 @@
import java.util.Arrays;
import java.util.EnumSet;
-import com.microsoft.azure.storage.OperationContext;
-
import static org.junit.Assert.*;
@Category(IntegrationTest.class)
@@ -72,7 +70,7 @@ public void testWrite() throws Exception {
new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)));
final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator));
- final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new AzureWriteFeature(session, null), cryptomator);
+ final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new AzureWriteFeature(session), cryptomator);
final FileHeader header = cryptomator.getFileHeaderCryptor().create();
status.setHeader(cryptomator.getFileHeaderCryptor().encryptHeader(header));
status.setNonces(new RotatingNonceGenerator(cryptomator.getNonceSize(), cryptomator.numberOfChunks(content.length)));
@@ -82,14 +80,13 @@ public void testWrite() throws Exception {
assertNotNull(out);
new StreamCopier(status, status).transfer(new ByteArrayInputStream(content), out);
out.close();
- final OperationContext context = new OperationContext();
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(test));
- final PathAttributes attributes = new CryptoListService(session, new AzureListService(session, context), cryptomator).list(test.getParent(), new DisabledListProgressListener()).get(test).attributes();
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(test));
+ final PathAttributes attributes = new CryptoListService(session, new AzureListService(session), cryptomator).list(test.getParent(), new DisabledListProgressListener()).get(test).attributes();
assertEquals(content.length, attributes.getSize());
final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length);
- final InputStream in = new CryptoReadFeature(session, new AzureReadFeature(session, context), cryptomator).read(test, new TransferStatus().setLength(content.length), new DisabledConnectionCallback());
+ final InputStream in = new CryptoReadFeature(session, new AzureReadFeature(session), cryptomator).read(test, new TransferStatus().setLength(content.length), new DisabledConnectionCallback());
new StreamCopier(status, status).transfer(in, buffer);
assertArrayEquals(content, buffer.toByteArray());
- cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session, context)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java
index 5c63dea021f..b3150c7c79e 100644
--- a/azure/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java
@@ -35,7 +35,9 @@
import ch.cyberduck.core.cryptomator.features.CryptoWriteFeature;
import ch.cyberduck.core.features.Directory;
import ch.cyberduck.core.features.Find;
+import ch.cyberduck.core.io.StreamCancelation;
import ch.cyberduck.core.io.StreamCopier;
+import ch.cyberduck.core.io.StreamProgress;
import ch.cyberduck.core.pool.SessionPool;
import ch.cyberduck.core.shared.DefaultFindFeature;
import ch.cyberduck.core.shared.DefaultTouchFeature;
@@ -63,7 +65,6 @@
import java.util.EnumSet;
import static org.junit.Assert.*;
-import static org.junit.Assume.assumeTrue;
@Category(IntegrationTest.class)
@RunWith(value = Parameterized.class)
@@ -81,15 +82,15 @@ public void testCopyFile() throws Exception {
session.withRegistry(registry);
final byte[] content = RandomUtils.nextBytes(40500);
final TransferStatus status = new TransferStatus();
- new CryptoBulkFeature<>(session, new DisabledBulkFeature(), new AzureDeleteFeature(session, null), cryptomator).pre(Transfer.Type.upload, Collections.singletonMap(new TransferItem(source), status), new DisabledConnectionCallback());
- new StreamCopier(new TransferStatus(), new TransferStatus()).transfer(new ByteArrayInputStream(content), new CryptoWriteFeature<>(session, new AzureWriteFeature(session, null), cryptomator).write(source, status.setLength(content.length), new DisabledConnectionCallback()));
+ new CryptoBulkFeature<>(session, new DisabledBulkFeature(), new AzureDeleteFeature(session), cryptomator).pre(Transfer.Type.upload, Collections.singletonMap(new TransferItem(source), status), new DisabledConnectionCallback());
+ new StreamCopier(StreamCancelation.noop, StreamProgress.noop).transfer(new ByteArrayInputStream(content), new CryptoWriteFeature<>(session, new AzureWriteFeature(session), cryptomator).write(source, status.setLength(content.length), new DisabledConnectionCallback()));
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(source));
final CopyWorker worker = new CopyWorker(Collections.singletonMap(source, target), new SessionPool.SingleSessionPool(session, registry), PathCache.empty(), new DisabledProgressListener(), new DisabledConnectionCallback());
worker.run(session);
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(source));
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(target));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(source));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(target));
final ByteArrayOutputStream out = new ByteArrayOutputStream(content.length);
- assertEquals(content.length, IOUtils.copy(new CryptoReadFeature(session, new AzureReadFeature(session, null), cryptomator).read(target, new TransferStatus().setLength(content.length), new DisabledConnectionCallback()), out));
+ assertEquals(content.length, IOUtils.copy(new CryptoReadFeature(session, new AzureReadFeature(session), cryptomator).read(target, new TransferStatus().setLength(content.length), new DisabledConnectionCallback()), out));
assertArrayEquals(content, out.toByteArray());
new DeleteWorker(new DisabledLoginCallback(), Collections.singletonList(vault), new DisabledProgressListener()).run(session);
}
@@ -105,9 +106,9 @@ public void testCopyToDifferentFolderCryptomator() throws Exception {
cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator);
session.withRegistry(registry);
- new CryptoTouchFeature(session, new DefaultTouchFeature(new AzureWriteFeature(session, null)), new AzureWriteFeature(session, null), cryptomator).touch(source, new TransferStatus());
+ new CryptoTouchFeature<>(session, new DefaultTouchFeature<>(new AzureWriteFeature(session)), new AzureWriteFeature(session), cryptomator).touch(source, new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(source));
- cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session, null)).mkdir(targetFolder, new TransferStatus());
+ cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir(targetFolder, new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(targetFolder));
final CopyWorker worker = new CopyWorker(Collections.singletonMap(source, target), new SessionPool.SingleSessionPool(session, registry), PathCache.empty(), new DisabledProgressListener(), new DisabledConnectionCallback());
worker.run(session);
@@ -119,7 +120,6 @@ public void testCopyToDifferentFolderCryptomator() throws Exception {
@Test
public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception {
- assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED);
final Path home = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final CryptoVault cryptomator = new CryptoVault(new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)));
final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
@@ -128,9 +128,9 @@ public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception
final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file));
final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator);
session.withRegistry(registry);
- new CryptoTouchFeature(session, new AzureTouchFeature(session, null), new AzureWriteFeature(session, null), cryptomator).touch(source, new TransferStatus());
+ new CryptoTouchFeature<>(session, new AzureTouchFeature(session), new AzureWriteFeature(session), cryptomator).touch(source, new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(source));
- cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session, null)).mkdir(targetFolder, new TransferStatus());
+ cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir(targetFolder, new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(targetFolder));
final CopyWorker worker = new CopyWorker(Collections.singletonMap(source, target), new SessionPool.SingleSessionPool(session, registry), PathCache.empty(), new DisabledProgressListener(), new DisabledConnectionCallback());
worker.run(session);
@@ -149,20 +149,20 @@ public void testCopyFolder() throws Exception {
final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator);
session.withRegistry(registry);
- cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session, null)).mkdir(folder, new TransferStatus());
+ cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir(folder, new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(folder));
- new CryptoTouchFeature(session, new AzureTouchFeature(session, null), new AzureWriteFeature(session, null), cryptomator).touch(file, new TransferStatus());
+ new CryptoTouchFeature<>(session, new AzureTouchFeature(session), new AzureWriteFeature(session), cryptomator).touch(file, new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(file));
// copy file
final Path fileRenamed = new Path(folder, "f1", EnumSet.of(Path.Type.file));
new CopyWorker(Collections.singletonMap(file, fileRenamed), new SessionPool.SingleSessionPool(session, registry), PathCache.empty(), new DisabledProgressListener(), new DisabledConnectionCallback()).run(session);
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(file));
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(fileRenamed));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(file));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(fileRenamed));
// copy folder
final Path folderRenamed = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
new CopyWorker(Collections.singletonMap(folder, folderRenamed), new SessionPool.SingleSessionPool(session, registry), PathCache.empty(), new DisabledProgressListener(), new DisabledConnectionCallback()).run(session);
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(folder));
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(folderRenamed));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(folder));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(folderRenamed));
final Path fileRenamedInRenamedFolder = new Path(folderRenamed, "f1", EnumSet.of(Path.Type.file));
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(fileRenamedInRenamedFolder));
registry.clear();
@@ -175,23 +175,23 @@ public void testCopyFileIntoVault() throws Exception {
final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
final Path cleartextFile = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
final byte[] content = RandomUtils.nextBytes(40500);
- new StreamCopier(new TransferStatus(), new TransferStatus()).transfer(new ByteArrayInputStream(content), new AzureWriteFeature(session, null).write(cleartextFile, new TransferStatus().setLength(content.length), new DisabledConnectionCallback()));
- assertTrue(new AzureFindFeature(session, null).find(cleartextFile));
+ new StreamCopier(StreamCancelation.noop, StreamProgress.noop).transfer(new ByteArrayInputStream(content), new AzureWriteFeature(session).write(cleartextFile, new TransferStatus().setLength(content.length), new DisabledConnectionCallback()));
+ assertTrue(new AzureFindFeature(session).find(cleartextFile));
final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
final CryptoVault cryptomator = new CryptoVault(vault);
cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator);
session.withRegistry(registry);
- cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session, null)).mkdir(encryptedFolder, new TransferStatus());
+ cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir(encryptedFolder, new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(encryptedFolder));
// copy file into vault
final CopyWorker worker = new CopyWorker(Collections.singletonMap(cleartextFile, encryptedFile), new SessionPool.SingleSessionPool(session, registry), PathCache.empty(), new DisabledProgressListener(), new DisabledConnectionCallback());
worker.run(session);
- assertTrue(new AzureFindFeature(session, null).find(cleartextFile));
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(encryptedFile));
+ assertTrue(new AzureFindFeature(session).find(cleartextFile));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(encryptedFile));
final ByteArrayOutputStream out = new ByteArrayOutputStream(content.length);
- assertEquals(content.length, IOUtils.copy(new CryptoReadFeature(session, new AzureReadFeature(session, null), cryptomator).read(encryptedFile, new TransferStatus().setLength(content.length), new DisabledConnectionCallback()), out));
+ assertEquals(content.length, IOUtils.copy(new CryptoReadFeature(session, new AzureReadFeature(session), cryptomator).read(encryptedFile, new TransferStatus().setLength(content.length), new DisabledConnectionCallback()), out));
assertArrayEquals(content, out.toByteArray());
registry.clear();
new DeleteWorker(new DisabledLoginCallback(), Collections.singletonList(vault), new DisabledProgressListener()).run(session);
@@ -203,10 +203,10 @@ public void testCopyDirectoryIntoVault() throws Exception {
final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
final Path cleartextFolder = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
final Path cleartextFile = new Path(cleartextFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureDirectoryFeature(session, null).mkdir(cleartextFolder, new TransferStatus());
- new AzureTouchFeature(session, null).touch(cleartextFile, new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(cleartextFolder));
- assertTrue(new AzureFindFeature(session, null).find(cleartextFile));
+ new AzureDirectoryFeature(session).mkdir(cleartextFolder, new TransferStatus());
+ new AzureTouchFeature(session).touch(cleartextFile, new TransferStatus());
+ assertTrue(new AzureFindFeature(session).find(cleartextFolder));
+ assertTrue(new AzureFindFeature(session).find(cleartextFile));
final CryptoVault cryptomator = new CryptoVault(vault);
cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator);
@@ -218,8 +218,8 @@ public void testCopyDirectoryIntoVault() throws Exception {
worker.run(session);
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(encryptedFolder));
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(encryptedFile));
- assertTrue(new AzureFindFeature(session, null).find(cleartextFolder));
- assertTrue(new AzureFindFeature(session, null).find(cleartextFile));
+ assertTrue(new AzureFindFeature(session).find(cleartextFolder));
+ assertTrue(new AzureFindFeature(session).find(cleartextFile));
registry.clear();
new DeleteWorker(new DisabledLoginCallback(), Collections.singletonList(vault), new DisabledProgressListener()).run(session);
}
@@ -229,23 +229,23 @@ public void testCopyFileOutsideVault() throws Exception {
final Path home = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
final Path clearFolder = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
- new AzureDirectoryFeature(session, null).mkdir(clearFolder, new TransferStatus());
+ new AzureDirectoryFeature(session).mkdir(clearFolder, new TransferStatus());
final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
final CryptoVault cryptomator = new CryptoVault(vault);
cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator);
session.withRegistry(registry);
- cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session, null)).mkdir(encryptedFolder, new TransferStatus());
+ cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir(encryptedFolder, new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(encryptedFolder));
- new CryptoTouchFeature(session, new AzureTouchFeature(session, null), new AzureWriteFeature(session, null), cryptomator).touch(encryptedFile, new TransferStatus());
+ new CryptoTouchFeature<>(session, new AzureTouchFeature(session), new AzureWriteFeature(session), cryptomator).touch(encryptedFile, new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(encryptedFile));
// move file outside vault
final Path cleartextFile = new Path(clearFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
final CopyWorker worker = new CopyWorker(Collections.singletonMap(encryptedFile, cleartextFile), new SessionPool.SingleSessionPool(session, registry), PathCache.empty(), new DisabledProgressListener(), new DisabledConnectionCallback());
worker.run(session);
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(encryptedFile));
- assertTrue(new AzureFindFeature(session, null).find(cleartextFile));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(encryptedFile));
+ assertTrue(new AzureFindFeature(session).find(cleartextFile));
registry.clear();
new DeleteWorker(new DisabledLoginCallback(), Arrays.asList(vault, clearFolder), new DisabledProgressListener()).run(session);
}
@@ -260,19 +260,19 @@ public void testCopyDirectoryOutsideVault() throws Exception {
cryptomator.create(session, new VaultCredentials("test"), vaultVersion);
final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator);
session.withRegistry(registry);
- cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session, null)).mkdir(encryptedFolder, new TransferStatus());
+ cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir(encryptedFolder, new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(encryptedFolder));
- new CryptoTouchFeature(session, new AzureTouchFeature(session, null), new AzureWriteFeature(session, null), cryptomator).touch(encryptedFile, new TransferStatus());
+ new CryptoTouchFeature<>(session, new AzureTouchFeature(session), new AzureWriteFeature(session), cryptomator).touch(encryptedFile, new TransferStatus());
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(encryptedFile));
// copy directory outside vault
final Path cleartextFolder = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
final CopyWorker worker = new CopyWorker(Collections.singletonMap(encryptedFolder, cleartextFolder), new SessionPool.SingleSessionPool(session, registry), PathCache.empty(), new DisabledProgressListener(), new DisabledConnectionCallback());
worker.run(session);
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(encryptedFolder));
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(encryptedFile));
- assertTrue(new AzureFindFeature(session, null).find(cleartextFolder));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(encryptedFolder));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(encryptedFile));
+ assertTrue(new AzureFindFeature(session).find(cleartextFolder));
final Path fileRenamed = new Path(cleartextFolder, encryptedFile.getName(), EnumSet.of(Path.Type.file));
- assertTrue(new AzureFindFeature(session, null).find(fileRenamed));
+ assertTrue(new AzureFindFeature(session).find(fileRenamed));
registry.clear();
new DeleteWorker(new DisabledLoginCallback(), Arrays.asList(cleartextFolder, vault), new DisabledProgressListener()).run(session);
}
diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/CryptoAzureSingleTransferWorkerTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/CryptoAzureSingleTransferWorkerTest.java
index 22c656ca57b..4ac361ed8c5 100644
--- a/azure/src/test/java/ch/cyberduck/core/cryptomator/CryptoAzureSingleTransferWorkerTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/CryptoAzureSingleTransferWorkerTest.java
@@ -35,7 +35,9 @@
import ch.cyberduck.core.features.Delete;
import ch.cyberduck.core.features.Find;
import ch.cyberduck.core.io.DisabledStreamListener;
+import ch.cyberduck.core.io.StreamCancelation;
import ch.cyberduck.core.io.StreamCopier;
+import ch.cyberduck.core.io.StreamProgress;
import ch.cyberduck.core.local.DefaultLocalDirectoryFeature;
import ch.cyberduck.core.notification.DisabledNotificationService;
import ch.cyberduck.core.transfer.DisabledTransferErrorCallback;
@@ -98,26 +100,23 @@ public void testUpload() throws Exception {
public TransferAction prompt(final TransferItem file) {
return TransferAction.overwrite;
}
- }, new DisabledTransferErrorCallback(),
- new DisabledProgressListener(), new DisabledStreamListener(), new DisabledLoginCallback(), new DisabledNotificationService()) {
-
- }.run(session));
- assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session, null)).find(dir1));
- assertEquals(content.length, cryptomator.getFeature(session, AttributesFinder.class, new AzureAttributesFinderFeature(session, null)).find(file1).getSize());
+ }, new DisabledTransferErrorCallback(), new DisabledProgressListener(), new DisabledStreamListener(), new DisabledLoginCallback(), new DisabledNotificationService()).run(session));
+ assertTrue(cryptomator.getFeature(session, Find.class, new AzureFindFeature(session)).find(dir1));
+ assertEquals(content.length, cryptomator.getFeature(session, AttributesFinder.class, new AzureAttributesFinderFeature(session)).find(file1).getSize());
{
final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length);
- final InputStream in = new CryptoReadFeature(session, new AzureReadFeature(session, null), cryptomator).read(file1, new TransferStatus().setLength(content.length), new DisabledConnectionCallback());
- new StreamCopier(new TransferStatus(), new TransferStatus()).transfer(in, buffer);
+ final InputStream in = new CryptoReadFeature(session, new AzureReadFeature(session), cryptomator).read(file1, new TransferStatus().setLength(content.length), new DisabledConnectionCallback());
+ new StreamCopier(StreamCancelation.noop, StreamProgress.noop).transfer(in, buffer);
assertArrayEquals(content, buffer.toByteArray());
}
- assertEquals(content.length, cryptomator.getFeature(session, AttributesFinder.class, new AzureAttributesFinderFeature(session, null)).find(file2).getSize());
+ assertEquals(content.length, cryptomator.getFeature(session, AttributesFinder.class, new AzureAttributesFinderFeature(session)).find(file2).getSize());
{
final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length);
- final InputStream in = new CryptoReadFeature(session, new AzureReadFeature(session, null), cryptomator).read(file1, new TransferStatus().setLength(content.length), new DisabledConnectionCallback());
- new StreamCopier(new TransferStatus(), new TransferStatus()).transfer(in, buffer);
+ final InputStream in = new CryptoReadFeature(session, new AzureReadFeature(session), cryptomator).read(file1, new TransferStatus().setLength(content.length), new DisabledConnectionCallback());
+ new StreamCopier(StreamCancelation.noop, StreamProgress.noop).transfer(in, buffer);
assertArrayEquals(content, buffer.toByteArray());
}
- cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session, null)).delete(Arrays.asList(file1, file2, dir1, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session)).delete(Arrays.asList(file1, file2, dir1, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
localFile1.delete();
localFile2.delete();
localDirectory1.delete();
diff --git a/azure/src/test/java/ch/cyberduck/core/worker/AzureSingleTransferWorkerTest.java b/azure/src/test/java/ch/cyberduck/core/worker/AzureSingleTransferWorkerTest.java
index 2860fc5dd8f..78cdd6bf7d4 100644
--- a/azure/src/test/java/ch/cyberduck/core/worker/AzureSingleTransferWorkerTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/worker/AzureSingleTransferWorkerTest.java
@@ -67,14 +67,13 @@ public void testDownload() throws Exception {
{
final byte[] content = RandomUtils.nextBytes(39864);
final TransferStatus writeStatus = new TransferStatus().setLength(content.length).setChecksum(new SHA256ChecksumCompute().compute(new ByteArrayInputStream(content), new TransferStatus()));
- final StatusOutputStream out = new AzureWriteFeature(session, null).write(test, writeStatus, new DisabledConnectionCallback());
+ final StatusOutputStream out = new AzureWriteFeature(session).write(test, writeStatus, new DisabledConnectionCallback());
assertNotNull(out);
new StreamCopier(writeStatus, writeStatus).withLimit((long) content.length).transfer(new ByteArrayInputStream(content), out);
- out.close();
}
final byte[] content = RandomUtils.nextBytes(39864);
- final TransferStatus writeStatus = new TransferStatus().setLength(content.length).setChecksum(new SHA256ChecksumCompute().compute(new ByteArrayInputStream(content), new TransferStatus()));
- final StatusOutputStream out = new AzureWriteFeature(session, null).write(test, writeStatus, new DisabledConnectionCallback());
+ final TransferStatus writeStatus = new TransferStatus().setExists(true).setLength(content.length).setChecksum(new SHA256ChecksumCompute().compute(new ByteArrayInputStream(content), new TransferStatus()));
+ final StatusOutputStream out = new AzureWriteFeature(session).write(test, writeStatus, new DisabledConnectionCallback());
assertNotNull(out);
new StreamCopier(writeStatus, writeStatus).withLimit((long) content.length).transfer(new ByteArrayInputStream(content), out);
out.close();
@@ -85,11 +84,9 @@ public TransferAction prompt(final TransferItem file) {
return TransferAction.overwrite;
}
}, new DisabledTransferErrorCallback(),
- new DisabledProgressListener(), new DisabledStreamListener(), new DisabledLoginCallback(), new DisabledNotificationService()) {
-
- }.run(session));
+ new DisabledProgressListener(), new DisabledStreamListener(), new DisabledLoginCallback(), new DisabledNotificationService()).run(session));
assertArrayEquals(content, IOUtils.toByteArray(localFile.getInputStream()));
- new AzureDeleteFeature(session, null).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
+ new AzureDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
localFile.delete();
}
}
diff --git a/azure/src/test/java/ch/cyberduck/core/worker/CopyWorkerTest.java b/azure/src/test/java/ch/cyberduck/core/worker/CopyWorkerTest.java
index 7f077ec46bd..6fd3d271519 100644
--- a/azure/src/test/java/ch/cyberduck/core/worker/CopyWorkerTest.java
+++ b/azure/src/test/java/ch/cyberduck/core/worker/CopyWorkerTest.java
@@ -46,12 +46,12 @@ public void testCopyFile() throws Exception {
final Path home = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path source = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
final Path target = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureTouchFeature(session, null).touch(source, new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(source));
+ new AzureTouchFeature(session).touch(source, new TransferStatus());
+ assertTrue(new AzureFindFeature(session).find(source));
final CopyWorker worker = new CopyWorker(Collections.singletonMap(source, target), new SessionPool.SingleSessionPool(session), PathCache.empty(), new DisabledProgressListener(), new DisabledConnectionCallback());
worker.run(session);
- assertTrue(new AzureFindFeature(session, null).find(source));
- assertTrue(new AzureFindFeature(session, null).find(target));
+ assertTrue(new AzureFindFeature(session).find(source));
+ assertTrue(new AzureFindFeature(session).find(target));
new DeleteWorker(new DisabledLoginCallback(), Arrays.asList(source, target), new DisabledProgressListener()).run(session);
}
@@ -59,17 +59,17 @@ public void testCopyFile() throws Exception {
public void testCopyFileToDirectory() throws Exception {
final Path home = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path sourceFile = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureTouchFeature(session, null).touch(sourceFile, new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(sourceFile));
+ new AzureTouchFeature(session).touch(sourceFile, new TransferStatus());
+ assertTrue(new AzureFindFeature(session).find(sourceFile));
final Path targetFolder = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
final Path targetFile = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureDirectoryFeature(session, null).mkdir(targetFolder, new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(targetFolder));
+ new AzureDirectoryFeature(session).mkdir(targetFolder, new TransferStatus());
+ assertTrue(new AzureFindFeature(session).find(targetFolder));
// copy file into vault
final CopyWorker worker = new CopyWorker(Collections.singletonMap(sourceFile, targetFile), new SessionPool.SingleSessionPool(session), PathCache.empty(), new DisabledProgressListener(), new DisabledConnectionCallback());
worker.run(session);
- assertTrue(new AzureFindFeature(session, null).find(sourceFile));
- assertTrue(new AzureFindFeature(session, null).find(targetFile));
+ assertTrue(new AzureFindFeature(session).find(sourceFile));
+ assertTrue(new AzureFindFeature(session).find(targetFile));
new DeleteWorker(new DisabledLoginCallback(), Arrays.asList(sourceFile, targetFolder), new DisabledProgressListener()).run(session);
}
@@ -78,19 +78,19 @@ public void testCopyDirectory() throws Exception {
final Path home = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
final Path folder = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
final Path sourceFile = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
- new AzureDirectoryFeature(session, null).mkdir(folder, new TransferStatus());
- new AzureTouchFeature(session, null).touch(sourceFile, new TransferStatus());
- assertTrue(new AzureFindFeature(session, null).find(folder));
- assertTrue(new AzureFindFeature(session, null).find(sourceFile));
+ new AzureDirectoryFeature(session).mkdir(folder, new TransferStatus());
+ new AzureTouchFeature(session).touch(sourceFile, new TransferStatus());
+ assertTrue(new AzureFindFeature(session).find(folder));
+ assertTrue(new AzureFindFeature(session).find(sourceFile));
// move directory into vault
final Path targetFolder = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory));
final Path targetFile = new Path(targetFolder, sourceFile.getName(), EnumSet.of(Path.Type.file));
final CopyWorker worker = new CopyWorker(Collections.singletonMap(folder, targetFolder), new SessionPool.SingleSessionPool(session), PathCache.empty(), new DisabledProgressListener(), new DisabledConnectionCallback());
worker.run(session);
- assertTrue(new AzureFindFeature(session, null).find(targetFolder));
- assertTrue(new AzureFindFeature(session, null).find(targetFile));
- assertTrue(new AzureFindFeature(session, null).find(folder));
- assertTrue(new AzureFindFeature(session, null).find(sourceFile));
+ assertTrue(new AzureFindFeature(session).find(targetFolder));
+ assertTrue(new AzureFindFeature(session).find(targetFile));
+ assertTrue(new AzureFindFeature(session).find(folder));
+ assertTrue(new AzureFindFeature(session).find(sourceFile));
new DeleteWorker(new DisabledLoginCallback(), Arrays.asList(folder, targetFolder), new DisabledProgressListener()).run(session);
}
}