Skip to content

Commit 7200393

Browse files
authored
Merge pull request #15797 from iterate-ch/bugfix/GH-15742
Display all user editable metadata and not only x-amz-meta
2 parents 35edde4 + 99ab399 commit 7200393

File tree

3 files changed

+88
-13
lines changed

3 files changed

+88
-13
lines changed

s3/src/main/java/ch/cyberduck/core/s3/S3AttributesAdapter.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@
2525
import org.jets3t.service.model.StorageObject;
2626

2727
import java.util.Date;
28+
import java.util.HashMap;
2829
import java.util.Map;
2930

3031
import com.google.common.collect.Maps;
3132

33+
import static org.jets3t.service.model.StorageObject.METADATA_HEADER_SERVER_SIDE_ENCRYPTION_KMS_KEY_ID;
34+
3235
public class S3AttributesAdapter implements AttributesAdapter<StorageObject> {
3336

3437
@Override
@@ -55,9 +58,9 @@ else if(object.containsMetadata("storage-class")) {
5558
if(object instanceof S3Object) {
5659
attributes.setVersionId(((S3Object) object).getVersionId());
5760
}
58-
if(object.containsMetadata("server-side-encryption-aws-kms-key-id")) {
61+
if(object.containsMetadata(METADATA_HEADER_SERVER_SIDE_ENCRYPTION_KMS_KEY_ID)) {
5962
attributes.setEncryption(new Encryption.Algorithm(object.getServerSideEncryptionAlgorithm(),
60-
object.getMetadata("server-side-encryption-aws-kms-key-id").toString()) {
63+
object.getMetadata(METADATA_HEADER_SERVER_SIDE_ENCRYPTION_KMS_KEY_ID).toString()) {
6164
@Override
6265
public String getDescription() {
6366
return String.format("SSE-KMS (%s)", key);
@@ -75,7 +78,7 @@ public String getDescription() {
7578
});
7679
}
7780
}
78-
final Map<String, String> metadata = Maps.transformValues(object.getUserMetadataMap(), Object::toString);
81+
final Map<String, String> metadata = metadata(object);
7982
if(!metadata.isEmpty()) {
8083
attributes.setMetadata(metadata);
8184
}
@@ -91,4 +94,17 @@ public String getDescription() {
9194
}
9295
return attributes;
9396
}
97+
98+
/**
99+
* @return Pruned metadata with user editable headers only
100+
*/
101+
public static Map<String, String> metadata(final StorageObject object) {
102+
final Map<String, String> metadata = new HashMap<>(Maps.transformValues(object.getModifiableMetadata(), Object::toString));
103+
metadata.keySet().removeIf(header -> StringUtils.equalsIgnoreCase(header, "storage-class"));
104+
metadata.keySet().removeIf(header -> StringUtils.equalsIgnoreCase(header, "server-side-encryption"));
105+
metadata.keySet().removeIf(header -> StringUtils.equalsIgnoreCase(header, "expiration"));
106+
metadata.keySet().removeIf(header -> StringUtils.equalsIgnoreCase(header, "checksum-sha256"));
107+
metadata.keySet().removeIf(header -> StringUtils.equalsIgnoreCase(header, "version-id"));
108+
return metadata;
109+
}
94110
}

s3/src/test/java/ch/cyberduck/core/s3/S3MetadataFeatureTest.java

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* Bug fixes, suggestions and comments should be sent to [email protected]
1818
*/
1919

20+
import ch.cyberduck.core.Acl;
2021
import ch.cyberduck.core.AlphanumericRandomStringService;
2122
import ch.cyberduck.core.DisabledLoginCallback;
2223
import ch.cyberduck.core.Path;
@@ -50,41 +51,94 @@ public void testGetMetadataBucket() throws Exception {
5051
public void testGetMetadataFile() throws Exception {
5152
final Path container = new Path("versioning-test-eu-central-1-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory));
5253
final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
53-
new S3TouchFeature(session, new S3AccessControlListFeature(session)).touch(test, new TransferStatus().withMetadata(Collections.singletonMap("app", "cyberduck")));
54+
new S3TouchFeature(session, new S3AccessControlListFeature(session)).touch(test, new TransferStatus()
55+
.withMetadata(Collections.singletonMap("app", "cyberduck"))
56+
.withMime("text/plain"));
5457
final Map<String, String> metadata = new S3MetadataFeature(session, new S3AccessControlListFeature(session)).getMetadata(test);
5558
new S3DefaultDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
5659
assertFalse(metadata.isEmpty());
5760
assertTrue(metadata.containsKey("app"));
5861
assertEquals("cyberduck", metadata.get("app"));
62+
assertTrue(metadata.containsKey("Content-Type"));
63+
assertEquals("text/plain", metadata.get("Content-Type"));
5964
assertFalse(metadata.containsKey(Constants.KEY_FOR_USER_METADATA));
6065
assertFalse(metadata.containsKey(Constants.KEY_FOR_SERVICE_METADATA));
6166
assertFalse(metadata.containsKey(Constants.KEY_FOR_COMPLETE_METADATA));
6267
}
6368

69+
@Test
70+
public void testSetMetadataHttpHeaders() throws Exception {
71+
final Path container = new Path("versioning-test-eu-central-1-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory));
72+
final Path test = new S3TouchFeature(session, new S3AccessControlListFeature(session)).touch(
73+
new Path(container, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)), new TransferStatus());
74+
final S3MetadataFeature feature = new S3MetadataFeature(session, new S3AccessControlListFeature(session));
75+
final Map<String, String> metadata = feature.getMetadata(test);
76+
77+
metadata.put("Content-Disposition", "attachment");
78+
feature.setMetadata(test, metadata);
79+
assertTrue(feature.getMetadata(test).containsKey("Content-Disposition"));
80+
metadata.put("Cache-Control", "public,max-age=1");
81+
feature.setMetadata(test, metadata);
82+
assertTrue(feature.getMetadata(test).containsKey("Cache-Control"));
83+
metadata.put("Content-Type", "text/html");
84+
feature.setMetadata(test, metadata);
85+
assertTrue(feature.getMetadata(test).containsKey("Content-Type"));
86+
87+
new S3DefaultDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
88+
}
89+
6490
@Test
6591
public void testSetMetadataFileLeaveOtherFeatures() throws Exception {
66-
final Path container = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory));
92+
final Path container = new Path("versioning-test-eu-central-1-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory));
6793
final Path test = new Path(container, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file));
68-
new S3TouchFeature(session, new S3AccessControlListFeature(session)).touch(test, new TransferStatus());
94+
final S3AccessControlListFeature acls = new S3AccessControlListFeature(session);
95+
new S3TouchFeature(session, acls).touch(test, new TransferStatus());
96+
final S3MetadataFeature feature = new S3MetadataFeature(session, acls);
97+
final Map<String, String> reference = feature.getMetadata(test);
98+
6999
final String v = UUID.randomUUID().toString();
70-
final S3StorageClassFeature storage = new S3StorageClassFeature(session, new S3AccessControlListFeature(session));
100+
101+
final Acl acl = acls.getPermission(test);
102+
acl.addAll(new Acl.GroupUser(Acl.GroupUser.EVERYONE), new Acl.Role(Acl.Role.READ));
103+
acl.addAll(new Acl.GroupUser(Acl.GroupUser.AUTHENTICATED), new Acl.Role(Acl.Role.READ));
104+
acls.setPermission(test, acl);
105+
assertEquals(reference, feature.getMetadata(test));
106+
107+
final S3StorageClassFeature storage = new S3StorageClassFeature(session, acls);
71108
storage.setClass(test, S3Object.STORAGE_CLASS_REDUCED_REDUNDANCY);
72109
assertEquals(S3Object.STORAGE_CLASS_REDUCED_REDUNDANCY, storage.getClass(test));
110+
assertEquals(reference, feature.getMetadata(test));
73111

74-
final S3EncryptionFeature encryption = new S3EncryptionFeature(session, new S3AccessControlListFeature(session));
112+
final S3EncryptionFeature encryption = new S3EncryptionFeature(session, acls);
75113
encryption.setEncryption(test, S3EncryptionFeature.SSE_AES256);
76114
assertEquals("AES256", encryption.getEncryption(test).algorithm);
115+
assertEquals(reference, feature.getMetadata(test));
77116

78-
final S3MetadataFeature feature = new S3MetadataFeature(session, new S3AccessControlListFeature(session));
79117
feature.setMetadata(test, Collections.singletonMap("Test", v));
80118
final Map<String, String> metadata = feature.getMetadata(test);
81119
assertFalse(metadata.isEmpty());
82120
assertTrue(metadata.containsKey("test"));
83121
assertEquals(v, metadata.get("test"));
122+
assertEquals(reference.size() + 1, metadata.size());
84123

85124
assertEquals(S3Object.STORAGE_CLASS_REDUCED_REDUNDANCY, storage.getClass(test));
86125
assertEquals("AES256", encryption.getEncryption(test).algorithm);
126+
assertEquals(acl, acls.getPermission(test));
127+
128+
new S3DefaultDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
129+
}
87130

131+
@Test
132+
public void testSetDuplicateHeaderDifferentCapitalization() throws Exception {
133+
final Path container = new Path("versioning-test-eu-central-1-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory));
134+
final Path test = new Path(container, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file));
135+
new S3TouchFeature(session, new S3AccessControlListFeature(session)).touch(test, new TransferStatus());
136+
final S3MetadataFeature feature = new S3MetadataFeature(session, new S3AccessControlListFeature(session));
137+
assertTrue(feature.getMetadata(test).containsKey("Content-Type"));
138+
feature.setMetadata(test, Collections.singletonMap("Content-type", "text/plain"));
139+
final Map<String, String> metadata = feature.getMetadata(test);
140+
assertTrue(metadata.containsKey("Content-Type"));
141+
assertEquals("text/plain", metadata.get("Content-Type"));
88142
new S3DefaultDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
89143
}
90144
}

s3/src/test/java/ch/cyberduck/core/s3/S3TimestampFeatureTest.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import java.util.HashMap;
3535
import java.util.Map;
3636

37-
import static org.junit.Assert.assertEquals;
37+
import static org.junit.Assert.*;
3838

3939
@Category(IntegrationTest.class)
4040
public class S3TimestampFeatureTest extends AbstractS3Test {
@@ -45,7 +45,7 @@ public void testFindTimestamp() throws Exception {
4545
final TransferStatus status = new TransferStatus();
4646
final S3AccessControlListFeature acl = new S3AccessControlListFeature(session);
4747
final Path test = new S3TouchFeature(session, acl).touch(new Path(bucket,
48-
new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)),
48+
new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)),
4949
status
5050
.withCreated(1695159781972L)
5151
.withModified(1530305150672L));
@@ -54,11 +54,16 @@ public void testFindTimestamp() throws Exception {
5454
final PathAttributes attributes = new S3AttributesFinderFeature(session, acl).find(test);
5555
assertEquals(1530305150000L, attributes.getModificationDate());
5656
assertEquals(1695159781000L, attributes.getCreationDate());
57+
final Map<String, String> metadata = attributes.getMetadata();
58+
assertEquals(3, metadata.size());
59+
assertTrue(metadata.containsKey("mtime"));
60+
assertTrue(metadata.containsKey("btime"));
61+
assertTrue(metadata.containsKey("Content-Type"));
5762
final S3TimestampFeature feature = new S3TimestampFeature(session);
5863
feature.setTimestamp(test, new TransferStatus().withModified(1630305150672L).withCreated(1530305160672L));
5964
final PathAttributes attributesAfterSettingNewTimestamps = new S3AttributesFinderFeature(session, acl).find(test);
60-
assertEquals(2, attributesAfterSettingNewTimestamps.getMetadata().size());
61-
assertEquals(new S3MetadataFeature(session, acl).getMetadata(test), attributesAfterSettingNewTimestamps.getMetadata());
65+
assertNotEquals(metadata, attributesAfterSettingNewTimestamps.getMetadata());
66+
assertEquals(metadata.size(), attributesAfterSettingNewTimestamps.getMetadata().size());
6267
assertEquals(new S3AttributesFinderFeature(session, acl).find(test).getVersionId(), attributesAfterSettingNewTimestamps.getVersionId());
6368
assertEquals(1630305150000L, attributesAfterSettingNewTimestamps.getModificationDate());
6469
assertEquals(1530305160000L, attributesAfterSettingNewTimestamps.getCreationDate());

0 commit comments

Comments
 (0)