You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ga...@apache.org on 2017/05/08 18:10:25 UTC
[23/50] jclouds git commit: JCLOUDS-1008: Use @Encoded with GCS.
JCLOUDS-1008: Use @Encoded with GCS.
Google cloud storage should use the @Encoded annotation with the
object names to make sure that the object is percent-encoded prior to
being submitted in the path of the request. This was previously broken
because the default path encoding ignores "/" and encodes the entire
string. The @Encoded annotation instructs jclouds annotation processor
to not encode the parameters to which it is attached and not to encode
the entire request path. Parameters that are not annotated with
@Encoded are URL encoded prior to being add to the path.
Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/2385ba90
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/2385ba90
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/2385ba90
Branch: refs/heads/master
Commit: 2385ba901e98d89e6cabd2b32028e1b3cac3992e
Parents: 0612579
Author: Timur Alperovich <ti...@gmail.com>
Authored: Sat Sep 26 15:16:13 2015 -0700
Committer: Ignasi Barrera <na...@apache.org>
Committed: Wed Oct 21 10:40:04 2015 +0200
----------------------------------------------------------------------
.../blobstore/GoogleCloudStorageBlobStore.java | 47 +++++--------
.../features/ObjectAccessControlsApi.java | 32 ++++-----
.../googlecloudstorage/features/ObjectApi.java | 74 +++++++++++---------
...ogleCloudStorageBlobIntegrationLiveTest.java | 1 +
.../features/ObjectApiMockTest.java | 16 +++++
.../src/test/resources/object_encoded_get.json | 21 ++++++
6 files changed, 114 insertions(+), 77 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jclouds/blob/2385ba90/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GoogleCloudStorageBlobStore.java
----------------------------------------------------------------------
diff --git a/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GoogleCloudStorageBlobStore.java b/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GoogleCloudStorageBlobStore.java
index e852704..5dbb7cd 100644
--- a/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GoogleCloudStorageBlobStore.java
+++ b/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GoogleCloudStorageBlobStore.java
@@ -20,8 +20,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.io.BaseEncoding.base64;
import static org.jclouds.googlecloudstorage.domain.DomainResourceReferences.ObjectRole.READER;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
import java.util.List;
import java.util.Set;
@@ -41,11 +39,11 @@ import org.jclouds.blobstore.domain.internal.BlobImpl;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.blobstore.internal.BaseBlobStore;
+import org.jclouds.blobstore.options.CopyOptions;
import org.jclouds.blobstore.options.CreateContainerOptions;
import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.options.PutOptions;
-import org.jclouds.blobstore.options.CopyOptions;
import org.jclouds.blobstore.strategy.internal.FetchBlobMetadata;
import org.jclouds.blobstore.util.BlobUtils;
import org.jclouds.collect.Memoized;
@@ -73,11 +71,10 @@ import org.jclouds.http.HttpResponseException;
import org.jclouds.io.ContentMetadata;
import org.jclouds.io.Payload;
import org.jclouds.io.PayloadSlicer;
+import org.jclouds.util.Strings2;
-import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
-import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.hash.HashCode;
@@ -204,12 +201,7 @@ public final class GoogleCloudStorageBlobStore extends BaseBlobStore {
*/
@Override
public boolean blobExists(String container, String name) {
- try {
- String urlName = name.contains("/") ? URLEncoder.encode(name, Charsets.UTF_8.toString()) : name;
- return api.getObjectApi().objectExists(container, urlName);
- } catch (UnsupportedEncodingException e) {
- throw Throwables.propagate(e);
- }
+ return api.getObjectApi().objectExists(container, Strings2.urlEncode(name));
}
/**
@@ -239,12 +231,12 @@ public final class GoogleCloudStorageBlobStore extends BaseBlobStore {
@Override
public BlobMetadata blobMetadata(String container, String name) {
- return objectToBlobMetadata.apply(api.getObjectApi().getObject(container, name));
+ return objectToBlobMetadata.apply(api.getObjectApi().getObject(container, Strings2.urlEncode(name)));
}
@Override
public Blob getBlob(String container, String name, GetOptions options) {
- GoogleCloudStorageObject gcsObject = api.getObjectApi().getObject(container, name);
+ GoogleCloudStorageObject gcsObject = api.getObjectApi().getObject(container, Strings2.urlEncode(name));
if (gcsObject == null) {
return null;
}
@@ -252,7 +244,7 @@ public final class GoogleCloudStorageBlobStore extends BaseBlobStore {
MutableBlobMetadata metadata = objectToBlobMetadata.apply(gcsObject);
Blob blob = new BlobImpl(metadata);
// TODO: Does getObject not get the payload?!
- Payload payload = api.getObjectApi().download(container, name, httpOptions).getPayload();
+ Payload payload = api.getObjectApi().download(container, Strings2.urlEncode(name), httpOptions).getPayload();
payload.setContentMetadata(metadata.getContentMetadata()); // Doing this first retains it on setPayload.
blob.setPayload(payload);
return blob;
@@ -260,18 +252,13 @@ public final class GoogleCloudStorageBlobStore extends BaseBlobStore {
@Override
public void removeBlob(String container, String name) {
- String urlName;
- try {
- urlName = name.contains("/") ? URLEncoder.encode(name, Charsets.UTF_8.toString()) : name;
- } catch (UnsupportedEncodingException uee) {
- throw Throwables.propagate(uee);
- }
- api.getObjectApi().deleteObject(container, urlName);
+ api.getObjectApi().deleteObject(container, Strings2.urlEncode(name));
}
@Override
public BlobAccess getBlobAccess(String container, String name) {
- ObjectAccessControls controls = api.getObjectAccessControlsApi().getObjectAccessControls(container, name, "allUsers");
+ ObjectAccessControls controls = api.getObjectAccessControlsApi().getObjectAccessControls(container,
+ Strings2.urlEncode(name), "allUsers");
if (controls != null && controls.role() == DomainResourceReferences.ObjectRole.READER) {
return BlobAccess.PUBLIC_READ;
} else {
@@ -287,9 +274,9 @@ public final class GoogleCloudStorageBlobStore extends BaseBlobStore {
.bucket(container)
.role(READER)
.build();
- api.getObjectApi().patchObject(container, name, new ObjectTemplate().addAcl(controls));
+ api.getObjectApi().patchObject(container, Strings2.urlEncode(name), new ObjectTemplate().addAcl(controls));
} else {
- api.getObjectAccessControlsApi().deleteObjectAccessControls(container, name, "allUsers");
+ api.getObjectAccessControlsApi().deleteObjectAccessControls(container, Strings2.urlEncode(name), "allUsers");
}
}
@@ -312,7 +299,8 @@ public final class GoogleCloudStorageBlobStore extends BaseBlobStore {
public String copyBlob(String fromContainer, String fromName, String toContainer, String toName,
CopyOptions options) {
if (!options.getContentMetadata().isPresent() && !options.getUserMetadata().isPresent()) {
- return api.getObjectApi().copyObject(toContainer, toName, fromContainer, fromName).etag();
+ return api.getObjectApi().copyObject(toContainer, Strings2.urlEncode(toName), fromContainer,
+ Strings2.urlEncode(fromName)).etag();
}
ObjectTemplate template = new ObjectTemplate();
@@ -349,7 +337,8 @@ public final class GoogleCloudStorageBlobStore extends BaseBlobStore {
template.customMetadata(options.getUserMetadata().get());
}
- return api.getObjectApi().copyObject(toContainer, toName, fromContainer, fromName, template).etag();
+ return api.getObjectApi().copyObject(toContainer, Strings2.urlEncode(toName), fromContainer,
+ Strings2.urlEncode(fromName), template).etag();
}
@Override
@@ -372,12 +361,14 @@ public final class GoogleCloudStorageBlobStore extends BaseBlobStore {
public String completeMultipartUpload(MultipartUpload mpu, List<MultipartPart> parts) {
ImmutableList.Builder<GoogleCloudStorageObject> builder = ImmutableList.builder();
for (MultipartPart part : parts) {
- builder.add(api.getObjectApi().getObject(mpu.containerName(), getMPUPartName(mpu, part.partNumber())));
+ builder.add(api.getObjectApi().getObject(mpu.containerName(),
+ Strings2.urlEncode(getMPUPartName(mpu, part.partNumber()))));
}
ObjectTemplate destination = blobMetadataToObjectTemplate.apply(mpu.blobMetadata());
ComposeObjectTemplate template = ComposeObjectTemplate.builder().fromGoogleCloudStorageObject(builder.build())
.destination(destination).build();
- return api.getObjectApi().composeObjects(mpu.containerName(), mpu.blobName(), template).etag();
+ return api.getObjectApi().composeObjects(mpu.containerName(), Strings2.urlEncode(mpu.blobName()), template)
+ .etag();
// TODO: delete components?
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/2385ba90/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectAccessControlsApi.java
----------------------------------------------------------------------
diff --git a/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectAccessControlsApi.java b/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectAccessControlsApi.java
index ce31029..32b5e7c 100644
--- a/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectAccessControlsApi.java
+++ b/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectAccessControlsApi.java
@@ -23,6 +23,7 @@ import java.util.List;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
+import javax.ws.rs.Encoded;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
@@ -41,7 +42,6 @@ import org.jclouds.rest.annotations.Fallback;
import org.jclouds.rest.annotations.PATCH;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
-import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.binders.BindToJsonPayload;
/**
@@ -49,7 +49,6 @@ import org.jclouds.rest.binders.BindToJsonPayload;
*
* @see <a href = " https://developers.google.com/storage/docs/json_api/v1/objectAccessControls "/>
*/
-@SkipEncoding({ '/', '=' })
@RequestFilters(OAuthFilter.class)
@Consumes(APPLICATION_JSON)
public interface ObjectAccessControlsApi {
@@ -74,7 +73,7 @@ public interface ObjectAccessControlsApi {
@Fallback(NullOnNotFoundOr404.class)
@Nullable
ObjectAccessControls getObjectAccessControls(@PathParam("bucket") String bucketName,
- @PathParam("object") String objectName, @PathParam("entity") String entity);
+ @PathParam("object") @Encoded String objectName, @PathParam("entity") String entity);
/**
* Returns the acl entry for the specified entity on the specified object.
@@ -97,7 +96,7 @@ public interface ObjectAccessControlsApi {
@Fallback(NullOnNotFoundOr404.class)
@Nullable
ObjectAccessControls getObjectAccessControls(@PathParam("bucket") String bucketName,
- @PathParam("object") String objectName, @PathParam("entity") String entity,
+ @PathParam("object") @Encoded String objectName, @PathParam("entity") String entity,
@QueryParam("generation") Long generation);
/**
@@ -116,7 +115,7 @@ public interface ObjectAccessControlsApi {
@Produces(APPLICATION_JSON)
@Path("/b/{bucket}/o/{object}/acl")
ObjectAccessControls createObjectAccessControls(@PathParam("bucket") String bucketName,
- @PathParam("object") String objectName,
+ @PathParam("object") @Encoded String objectName,
@BinderParam(BindToJsonPayload.class) ObjectAccessControlsTemplate template);
/**
@@ -137,7 +136,7 @@ public interface ObjectAccessControlsApi {
@Produces(APPLICATION_JSON)
@Path("/b/{bucket}/o/{object}/acl")
ObjectAccessControls createObjectAccessControls(@PathParam("bucket") String bucketName,
- @PathParam("object") String objectName,
+ @PathParam("object") @Encoded String objectName,
@BinderParam(BindToJsonPayload.class) ObjectAccessControlsTemplate template,
@QueryParam("generation") Long generation);
@@ -155,8 +154,8 @@ public interface ObjectAccessControlsApi {
@Named("ObjectAccessControls:delete")
@DELETE
@Path("/b/{bucket}/o/{object}/acl/{entity}")
- void deleteObjectAccessControls(@PathParam("bucket") String bucketName, @PathParam("object") String objectName,
- @PathParam("entity") String entity);
+ void deleteObjectAccessControls(@PathParam("bucket") String bucketName,
+ @PathParam("object") @Encoded String objectName, @PathParam("entity") String entity);
/**
* Permanently deletes the acl entry for the specified entity on the specified bucket.
@@ -174,8 +173,9 @@ public interface ObjectAccessControlsApi {
@Named("ObjectAccessControls:delete")
@DELETE
@Path("/b/{bucket}/o/{object}/acl/{entity}")
- void deleteObjectAccessControls(@PathParam("bucket") String bucketName, @PathParam("object") String objectName,
- @PathParam("entity") String entity, @QueryParam("generation") Long generation);
+ void deleteObjectAccessControls(@PathParam("bucket") String bucketName,
+ @PathParam("object") @Encoded String objectName, @PathParam("entity") String entity,
+ @QueryParam("generation") Long generation);
/**
* Retrieves acl entries on a specified object
@@ -193,7 +193,7 @@ public interface ObjectAccessControlsApi {
@Fallback(NullOnNotFoundOr404.class)
@Nullable
List<ObjectAccessControls> listObjectAccessControls(@PathParam("bucket") String bucketName,
- @PathParam("object") String objectName);
+ @PathParam("object") @Encoded String objectName);
/**
* Retrieves acl entries on a specified object
@@ -214,7 +214,7 @@ public interface ObjectAccessControlsApi {
@Fallback(NullOnNotFoundOr404.class)
@Nullable
List<ObjectAccessControls> listObjectAccessControls(@PathParam("bucket") String bucketName,
- @PathParam("object") String objectName, @QueryParam("generation") Long generation);
+ @PathParam("object") @Encoded String objectName, @QueryParam("generation") Long generation);
/**
* Updates an acl entry on the specified object
@@ -237,7 +237,7 @@ public interface ObjectAccessControlsApi {
@Produces(APPLICATION_JSON)
@Path("/b/{bucket}/o/{object}/acl/{entity}")
ObjectAccessControls updateObjectAccessControls(@PathParam("bucket") String bucketName,
- @PathParam("object") String objectName, @PathParam("entity") String entity,
+ @PathParam("object") @Encoded String objectName, @PathParam("entity") String entity,
@BinderParam(BindToJsonPayload.class) ObjectAccessControlsTemplate template);
/**
@@ -262,7 +262,7 @@ public interface ObjectAccessControlsApi {
@Produces(APPLICATION_JSON)
@Path("/b/{bucket}/o/{object}/acl/{entity}")
ObjectAccessControls updateObjectAccessControls(@PathParam("bucket") String bucketName,
- @PathParam("object") String objectName, @PathParam("entity") String entity,
+ @PathParam("object") @Encoded String objectName, @PathParam("entity") String entity,
@BinderParam(BindToJsonPayload.class) ObjectAccessControlsTemplate template,
@QueryParam("generation") Long generation);
@@ -286,7 +286,7 @@ public interface ObjectAccessControlsApi {
@Produces(APPLICATION_JSON)
@Path("/b/{bucket}/o/{object}/acl/{entity}")
ObjectAccessControls patchObjectAccessControls(@PathParam("bucket") String bucketName,
- @PathParam("object") String objectName, @PathParam("entity") String entity,
+ @PathParam("object") @Encoded String objectName, @PathParam("entity") String entity,
@BinderParam(BindToJsonPayload.class) ObjectAccessControlsTemplate template);
/**
@@ -311,7 +311,7 @@ public interface ObjectAccessControlsApi {
@Produces(APPLICATION_JSON)
@Path("/b/{bucket}/o/{object}/acl/{entity}")
ObjectAccessControls patchObjectAccessControls(@PathParam("bucket") String bucketName,
- @PathParam("object") String objectName, @PathParam("entity") String entity,
+ @PathParam("object") @Encoded String objectName, @PathParam("entity") String entity,
@BinderParam(BindToJsonPayload.class) ObjectAccessControlsTemplate template,
@QueryParam("generation") Long generation);
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/2385ba90/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectApi.java
----------------------------------------------------------------------
diff --git a/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectApi.java b/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectApi.java
index ff8dfde..4e4f5b9 100644
--- a/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectApi.java
+++ b/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/features/ObjectApi.java
@@ -21,6 +21,7 @@ import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import javax.inject.Named;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
+import javax.ws.rs.Encoded;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
@@ -60,7 +61,6 @@ import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.QueryParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser;
-import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.binders.BindToJsonPayload;
/**
@@ -68,7 +68,6 @@ import org.jclouds.rest.binders.BindToJsonPayload;
*
* @see <a href="https://developers.google.com/storage/docs/json_api/v1/objects"/>
*/
-@SkipEncoding({ '/', '=' })
@RequestFilters(OAuthFilter.class)
public interface ObjectApi {
@@ -87,7 +86,7 @@ public interface ObjectApi {
@Path("storage/v1/b/{bucket}/o/{object}")
@Fallback(FalseOnNotFoundOr404.class)
@Nullable
- boolean objectExists(@PathParam("bucket") String bucketName, @PathParam("object") String objectName);
+ boolean objectExists(@PathParam("bucket") String bucketName, @PathParam("object") @Encoded String objectName);
/**
* Retrieve an object metadata
@@ -105,7 +104,8 @@ public interface ObjectApi {
@Consumes(APPLICATION_JSON)
@Fallback(NullOnNotFoundOr404.class)
@Nullable
- GoogleCloudStorageObject getObject(@PathParam("bucket") String bucketName, @PathParam("object") String objectName);
+ GoogleCloudStorageObject getObject(@PathParam("bucket") String bucketName,
+ @PathParam("object") @Encoded String objectName);
/**
* Retrieves objects metadata
@@ -126,8 +126,8 @@ public interface ObjectApi {
@Consumes(APPLICATION_JSON)
@Fallback(NullOnNotFoundOr404.class)
@Nullable
- GoogleCloudStorageObject getObject(@PathParam("bucket") String bucketName, @PathParam("object") String objectName,
- HttpRequestOptions options);
+ GoogleCloudStorageObject getObject(@PathParam("bucket") String bucketName,
+ @PathParam("object") @Encoded String objectName, HttpRequestOptions options);
/**
* Retrieve an object or their metadata
@@ -146,7 +146,7 @@ public interface ObjectApi {
@ResponseParser(ParseToPayloadEnclosing.class)
@Fallback(NullOnNotFoundOr404.class)
@Nullable
- PayloadEnclosing download(@PathParam("bucket") String bucketName, @PathParam("object") String objectName);
+ PayloadEnclosing download(@PathParam("bucket") String bucketName, @PathParam("object") @Encoded String objectName);
/**
* Retrieves objects
@@ -167,7 +167,8 @@ public interface ObjectApi {
@Path("storage/v1/b/{bucket}/o/{object}")
@ResponseParser(ParseToPayloadEnclosing.class)
@Fallback(NullOnNotFoundOr404.class)
- @Nullable PayloadEnclosing download(@PathParam("bucket") String bucketName, @PathParam("object") String objectName,
+ @Nullable
+ PayloadEnclosing download(@PathParam("bucket") String bucketName, @PathParam("object") @Encoded String objectName,
HttpRequestOptions options);
/**
@@ -204,7 +205,7 @@ public interface ObjectApi {
@DELETE
@Path("storage/v1/b/{bucket}/o/{object}")
@Fallback(FalseOnNotFoundOr404.class)
- boolean deleteObject(@PathParam("bucket") String bucketName, @PathParam("object") String objectName);
+ boolean deleteObject(@PathParam("bucket") String bucketName, @PathParam("object") @Encoded String objectName);
/**
* Deletes an object and its metadata. Deletions are permanent if versioning is not enabled for the bucket, or if the
@@ -221,7 +222,7 @@ public interface ObjectApi {
@DELETE
@Path("storage/v1/b/{bucket}/o/{object}")
@Fallback(FalseOnNotFoundOr404.class)
- boolean deleteObject(@PathParam("bucket") String bucketName, @PathParam("object") String objectName,
+ boolean deleteObject(@PathParam("bucket") String bucketName, @PathParam("object") @Encoded String objectName,
DeleteObjectOptions options);
/**
@@ -271,8 +272,9 @@ public interface ObjectApi {
@Produces(APPLICATION_JSON)
@Path("storage/v1/b/{bucket}/o/{object}")
@Fallback(NullOnNotFoundOr404.class)
- GoogleCloudStorageObject updateObject(@PathParam("bucket") String bucketName, @PathParam("object") String objectName,
- @BinderParam(BindToJsonPayload.class) ObjectTemplate objectTemplate);
+ GoogleCloudStorageObject updateObject(@PathParam("bucket") String bucketName,
+ @PathParam("object") @Encoded String objectName,
+ @BinderParam(BindToJsonPayload.class) ObjectTemplate objectTemplate);
/**
* Updates an object
@@ -294,8 +296,9 @@ public interface ObjectApi {
@Produces(APPLICATION_JSON)
@Path("storage/v1/b/{bucket}/o/{object}")
@Fallback(NullOnNotFoundOr404.class)
- GoogleCloudStorageObject updateObject(@PathParam("bucket") String bucketName, @PathParam("object") String objectName,
- @BinderParam(BindToJsonPayload.class) ObjectTemplate objectTemplate, UpdateObjectOptions options);
+ GoogleCloudStorageObject updateObject(@PathParam("bucket") String bucketName,
+ @PathParam("object") @Encoded String objectName,
+ @BinderParam(BindToJsonPayload.class) ObjectTemplate objectTemplate, UpdateObjectOptions options);
/**
* Updates an object according to patch semantics
@@ -315,8 +318,9 @@ public interface ObjectApi {
@Produces(APPLICATION_JSON)
@Path("storage/v1/b/{bucket}/o/{object}")
@Fallback(NullOnNotFoundOr404.class)
- GoogleCloudStorageObject patchObject(@PathParam("bucket") String bucketName, @PathParam("object") String objectName,
- @BinderParam(BindToJsonPayload.class) ObjectTemplate objectTemplate);
+ GoogleCloudStorageObject patchObject(@PathParam("bucket") String bucketName,
+ @PathParam("object") @Encoded String objectName,
+ @BinderParam(BindToJsonPayload.class) ObjectTemplate objectTemplate);
/**
* Updates an object according to patch semantics
@@ -338,8 +342,9 @@ public interface ObjectApi {
@Produces(APPLICATION_JSON)
@Path("storage/v1/b/{bucket}/o/{object}")
@Fallback(NullOnNotFoundOr404.class)
- GoogleCloudStorageObject patchObject(@PathParam("bucket") String bucketName, @PathParam("object") String objectName,
- @BinderParam(BindToJsonPayload.class) ObjectTemplate objectTemplate, UpdateObjectOptions options);
+ GoogleCloudStorageObject patchObject(@PathParam("bucket") String bucketName,
+ @PathParam("object") @Encoded String objectName,
+ @BinderParam(BindToJsonPayload.class) ObjectTemplate objectTemplate, UpdateObjectOptions options);
/**
* Concatenates a list of existing objects into a new object in the same bucket.
@@ -358,7 +363,7 @@ public interface ObjectApi {
@Consumes(APPLICATION_JSON)
@Path("storage/v1/b/{destinationBucket}/o/{destinationObject}/compose")
GoogleCloudStorageObject composeObjects(@PathParam("destinationBucket") String destinationBucket,
- @PathParam("destinationObject") String destinationObject,
+ @PathParam("destinationObject") @Encoded String destinationObject,
@BinderParam(BindToJsonPayload.class) ComposeObjectTemplate composeObjectTemplate);
/**
@@ -380,7 +385,7 @@ public interface ObjectApi {
@Consumes(APPLICATION_JSON)
@Path("storage/v1/b/{destinationBucket}/o/{destinationObject}/compose")
GoogleCloudStorageObject composeObjects(@PathParam("destinationBucket") String destinationBucket,
- @PathParam("destinationObject") String destinationObject,
+ @PathParam("destinationObject") @Encoded String destinationObject,
@BinderParam(BindToJsonPayload.class) ComposeObjectTemplate composeObjectTemplate,
ComposeObjectOptions options);
@@ -403,8 +408,9 @@ public interface ObjectApi {
@Consumes(APPLICATION_JSON)
@Path("/storage/v1/b/{sourceBucket}/o/{sourceObject}/copyTo/b/{destinationBucket}/o/{destinationObject}")
GoogleCloudStorageObject copyObject(@PathParam("destinationBucket") String destinationBucket,
- @PathParam("destinationObject") String destinationObject, @PathParam("sourceBucket") String sourceBucket,
- @PathParam("sourceObject") String sourceObject);
+ @PathParam("destinationObject") @Encoded String destinationObject,
+ @PathParam("sourceBucket") String sourceBucket,
+ @PathParam("sourceObject") @Encoded String sourceObject);
/**
* Copies an object to a specified location with updated metadata.
@@ -427,8 +433,10 @@ public interface ObjectApi {
@Consumes(APPLICATION_JSON)
@Path("/storage/v1/b/{sourceBucket}/o/{sourceObject}/copyTo/b/{destinationBucket}/o/{destinationObject}")
GoogleCloudStorageObject copyObject(@PathParam("destinationBucket") String destinationBucket,
- @PathParam("destinationObject") String destinationObject, @PathParam("sourceBucket") String sourceBucket,
- @PathParam("sourceObject") String sourceObject, @BinderParam(BindToJsonPayload.class) ObjectTemplate template);
+ @PathParam("destinationObject") @Encoded String destinationObject,
+ @PathParam("sourceBucket") String sourceBucket,
+ @PathParam("sourceObject") @Encoded String sourceObject,
+ @BinderParam(BindToJsonPayload.class) ObjectTemplate template);
/**
* Copies an object to a specified location. Optionally overrides metadata.
@@ -451,8 +459,9 @@ public interface ObjectApi {
@Consumes(APPLICATION_JSON)
@Path("/storage/v1/b/{sourceBucket}/o/{sourceObject}/copyTo/b/{destinationBucket}/o/{destinationObject}")
GoogleCloudStorageObject copyObject(@PathParam("destinationBucket") String destinationBucket,
- @PathParam("destinationObject") String destinationObject, @PathParam("sourceBucket") String sourceBucket,
- @PathParam("sourceObject") String sourceObject, CopyObjectOptions options);
+ @PathParam("destinationObject") @Encoded String destinationObject,
+ @PathParam("sourceBucket") String sourceBucket,
+ @PathParam("sourceObject") @Encoded String sourceObject, CopyObjectOptions options);
/**
* Stores a new object with metadata.
@@ -495,9 +504,8 @@ public interface ObjectApi {
@Consumes(APPLICATION_JSON)
@Path("/storage/v1/b/{sourceBucket}/o/{sourceObject}/rewriteTo/b/{destinationBucket}/o/{destinationObject}")
RewriteResponse rewriteObjects(@PathParam("destinationBucket") String destinationBucket,
- @PathParam("destinationObject") String destinationObject,
- @PathParam("sourceBucket") String sourceBucket,
- @PathParam("sourceObject") String sourceObject);
+ @PathParam("destinationObject") @Encoded String destinationObject,
+ @PathParam("sourceBucket") String sourceBucket, @PathParam("sourceObject") @Encoded String sourceObject);
/**
* Rewrites a source object to a destination object.
@@ -520,8 +528,8 @@ public interface ObjectApi {
@Consumes(APPLICATION_JSON)
@Path("/storage/v1/b/{sourceBucket}/o/{sourceObject}/rewriteTo/b/{destinationBucket}/o/{destinationObject}")
RewriteResponse rewriteObjects(@PathParam("destinationBucket") String destinationBucket,
- @PathParam("destinationObject") String destinationObject,
- @PathParam("sourceBucket") String sourceBucket,
- @PathParam("sourceObject") String sourceObject,
- RewriteObjectOptions options);
+ @PathParam("destinationObject") @Encoded String destinationObject,
+ @PathParam("sourceBucket") String sourceBucket,
+ @PathParam("sourceObject") @Encoded String sourceObject,
+ RewriteObjectOptions options);
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/2385ba90/providers/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/blobstore/integration/GoogleCloudStorageBlobIntegrationLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/blobstore/integration/GoogleCloudStorageBlobIntegrationLiveTest.java b/providers/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/blobstore/integration/GoogleCloudStorageBlobIntegrationLiveTest.java
index 162c45a..db1bcd8 100644
--- a/providers/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/blobstore/integration/GoogleCloudStorageBlobIntegrationLiveTest.java
+++ b/providers/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/blobstore/integration/GoogleCloudStorageBlobIntegrationLiveTest.java
@@ -143,6 +143,7 @@ public class GoogleCloudStorageBlobIntegrationLiveTest extends BaseBlobIntegrati
return new Object[][] { { "file.xml", "text/xml", file, realObject },
{ "string.xml", "text/xml", realObject, realObject },
+ { "stringwith/slash.xml", "text/xml", realObject, realObject },
{ "bytes.xml", "application/octet-stream", realObject.getBytes(), realObject } };
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/2385ba90/providers/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/features/ObjectApiMockTest.java
----------------------------------------------------------------------
diff --git a/providers/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/features/ObjectApiMockTest.java b/providers/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/features/ObjectApiMockTest.java
index 9906a90..35e9827 100644
--- a/providers/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/features/ObjectApiMockTest.java
+++ b/providers/google-cloud-storage/src/test/java/org/jclouds/googlecloudstorage/features/ObjectApiMockTest.java
@@ -40,6 +40,7 @@ import org.jclouds.googlecloudstorage.parse.ParseGoogleCloudStorageObjectListTes
import org.jclouds.googlecloudstorage.parse.ParseObjectRewriteResponse;
import org.jclouds.http.internal.PayloadEnclosingImpl;
import org.jclouds.io.PayloadEnclosing;
+import org.jclouds.util.Strings2;
import org.testng.annotations.Test;
import com.google.common.net.MediaType;
@@ -57,6 +58,13 @@ public class ObjectApiMockTest extends BaseGoogleCloudStorageApiMockTest {
assertSent(server, "GET", "/storage/v1/b/test/o/file_name", null);
}
+ public void existsEncoded() throws Exception {
+ server.enqueue(jsonResponse("/object_encoded_get.json"));
+
+ assertTrue(objectApi().objectExists("test", Strings2.urlEncode("dir/file name")));
+ assertSent(server, "GET", "/storage/v1/b/test/o/dir%2Ffile%20name", null);
+ }
+
public void exists_4xx() throws Exception {
server.enqueue(response404());
@@ -120,6 +128,14 @@ public class ObjectApiMockTest extends BaseGoogleCloudStorageApiMockTest {
assertSent(server, "DELETE", "/storage/v1/b/test/o/object_name", null);
}
+ public void delete_encoded() throws Exception {
+ server.enqueue(new MockResponse());
+
+ // TODO: Should this be returning True on not found?
+ assertTrue(objectApi().deleteObject("test", Strings2.urlEncode("dir/object name")));
+ assertSent(server, "DELETE", "/storage/v1/b/test/o/dir%2Fobject%20name", null);
+ }
+
public void list() throws Exception {
server.enqueue(jsonResponse("/object_list.json"));
http://git-wip-us.apache.org/repos/asf/jclouds/blob/2385ba90/providers/google-cloud-storage/src/test/resources/object_encoded_get.json
----------------------------------------------------------------------
diff --git a/providers/google-cloud-storage/src/test/resources/object_encoded_get.json b/providers/google-cloud-storage/src/test/resources/object_encoded_get.json
new file mode 100644
index 0000000..7fdb843
--- /dev/null
+++ b/providers/google-cloud-storage/src/test/resources/object_encoded_get.json
@@ -0,0 +1,21 @@
+{
+ "kind": "storage#object",
+ "id": "test/dir%2Ffile%20name/1000",
+ "selfLink": "https://www.googleapis.com/storage/v1/b/test/o/dir%2Ffile%20name",
+ "name": "dir%2Ffile%20name",
+ "bucket": "test",
+ "generation": "1000",
+ "metageneration": "8",
+ "contentType": "application/x-tar",
+ "updated": "2014-09-27T00:01:44.819",
+ "storageClass": "STANDARD",
+ "size": "1000",
+ "md5Hash": "md5Hash",
+ "mediaLink": "https://www.googleapis.com/download/storage/v1/b/test/o/dir%2Ffile%20name?generation=1000&alt=media",
+ "owner": {
+ "entity": "entity",
+ "entityId": "entityId"
+ },
+ "crc32c": "crc32c",
+ "etag": "etag"
+}