diff --git a/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/functions/ResourceToObjectInfo.java b/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/functions/ResourceToObjectInfo.java index 56dad87a09..45d8eb4794 100644 --- a/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/functions/ResourceToObjectInfo.java +++ b/apis/swift/src/main/java/org/jclouds/openstack/swift/blobstore/functions/ResourceToObjectInfo.java @@ -16,8 +16,6 @@ */ package org.jclouds.openstack.swift.blobstore.functions; -import static com.google.common.io.BaseEncoding.base16; - import java.util.Map.Entry; import javax.inject.Singleton; @@ -29,6 +27,7 @@ import org.jclouds.openstack.swift.domain.MutableObjectInfoWithMetadata; import org.jclouds.openstack.swift.domain.internal.MutableObjectInfoWithMetadataImpl; import com.google.common.base.Function; +import org.jclouds.openstack.swift.utils.ETagUtils; /** * @author Adrian Cole @@ -48,7 +47,7 @@ public class ResourceToObjectInfo implements FunctionConverts the ETag of an OpenStack object to a byte array.

+ * + *

Not applicable to all ETags, only those of OpenStack objects. According + * to the HTTP spec + * an eTag can be any string, but the + * OpenStack Object Storage Administration Guide + * says that the ETag of an OpenStack object will be an MD5 sum (and MD5 sums + * are conventionally represented as hex strings). This method only accepts + * hex strings as input, not arbitrary strings.

+ */ + public static byte[] convertHexETagToByteArray(String hexETag) { + hexETag = unquote(hexETag); + return base16().lowerCase().decode(hexETag); + } + + @VisibleForTesting + static String unquote(String eTag) { + return QUOTED_STRING.matcher(eTag).replaceAll("$1"); + } +} diff --git a/apis/swift/src/test/java/org/jclouds/openstack/swift/functions/ParseObjectInfoFromHeadersTest.java b/apis/swift/src/test/java/org/jclouds/openstack/swift/functions/ParseObjectInfoFromHeadersTest.java index 7e62800d94..8c30fdbd1c 100644 --- a/apis/swift/src/test/java/org/jclouds/openstack/swift/functions/ParseObjectInfoFromHeadersTest.java +++ b/apis/swift/src/test/java/org/jclouds/openstack/swift/functions/ParseObjectInfoFromHeadersTest.java @@ -16,6 +16,7 @@ */ package org.jclouds.openstack.swift.functions; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import org.jclouds.http.HttpResponse; @@ -26,7 +27,7 @@ import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; /** - * Tests behavior of {@code ParseContainerListFromJsonResponse} + * Tests behavior of {@code ParseObjectInfoFromHeaders} * * @author Adrian Cole */ @@ -34,17 +35,30 @@ import com.google.common.collect.ImmutableList; public class ParseObjectInfoFromHeadersTest extends BasePayloadTest { public void testEtagCaseIssue() { + assertETagCanBeParsed("feb1", + new byte[] { (byte) 0xfe, (byte) 0xb1 } + ); + } + + public void testParseEtagWithQuotes() { + assertETagCanBeParsed("\"feb1\"", + new byte[] { (byte) 0xfe, (byte) 0xb1 } + ); + } + + private void assertETagCanBeParsed(String etag, byte[] expectedHash) { ParseObjectInfoFromHeaders parser = i.getInstance(ParseObjectInfoFromHeaders.class); - + parser.setContext(requestForArgs(ImmutableList. of("container", "key"))); HttpResponse response = HttpResponse.builder().statusCode(200).message("ok").payload("") .addHeader("Last-Modified", "Fri, 12 Jun 2007 13:40:18 GMT") .addHeader("Content-Length", "0") - .addHeader("Etag", "feb1").build(); + .addHeader("Etag", etag).build(); response.getPayload().getContentMetadata().setContentType("text/plain"); MutableObjectInfoWithMetadata md = parser.apply(response); assertNotNull(md.getHash()); + assertEquals(md.getHash(), expectedHash); } } diff --git a/apis/swift/src/test/java/org/jclouds/openstack/swift/utils/ETagUtilsTest.java b/apis/swift/src/test/java/org/jclouds/openstack/swift/utils/ETagUtilsTest.java new file mode 100644 index 0000000000..e46d792c5d --- /dev/null +++ b/apis/swift/src/test/java/org/jclouds/openstack/swift/utils/ETagUtilsTest.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.openstack.swift.utils; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; + +/** + * @author Francis Devereux + */ +@Test(groups = "unit") +public class ETagUtilsTest { + @Test + public void testNoExceptionUnquotingSingleDQuote() { + String singleDQuoteCharacter = "\""; + assertEquals(ETagUtils.unquote(singleDQuoteCharacter), + singleDQuoteCharacter); + } +}