Conversation
Codecov Report
@@ Coverage Diff @@
## master #177 +/- ##
=========================================
Coverage 62.43% 62.43%
Complexity 552 552
=========================================
Files 31 31
Lines 5007 5007
Branches 449 449
=========================================
Hits 3126 3126
Misses 1712 1712
Partials 169 169 Continue to review full report at Codecov.
|
elharo
left a comment
There was a problem hiding this comment.
Can you add documentation in this PR? That would make the code here easier to understand and review.
| /** | ||
| * Use a virtual hosted-style hostname, which adds the bucket into the host portion of the URI | ||
| * rather than the path, e.g. 'https://mybucket.storage.googleapis.com/...'. The bucket name | ||
| * will be obtained from the resource passed in. |
There was a problem hiding this comment.
will be --> is
per Google Tech Writing Guidelines
https://developers.google.com/style/tense
| } | ||
|
|
||
| /** | ||
| * Provides a service account signer to sign the policy. If not provided an attempt will be made |
|
|
||
| /** | ||
| * Generate a path-style URL, which places the bucket name in the path portion of the URL | ||
| * instead of in the hostname, e.g 'https://storage.googleapis.com/mybucket/...'. Note that this |
There was a problem hiding this comment.
delete "Note that"
https://developers.google.com/style/tone
| } | ||
|
|
||
| /** | ||
| * Generate a path-style URL, which places the bucket name in the path portion of the URL |
There was a problem hiding this comment.
Generate --> Generates
https://developers.google.com/style/reference-verbs
| /** | ||
| * Use a bucket-bound hostname, which replaces the storage.googleapis.com host with the name of | ||
| * a CNAME bucket, e.g. a bucket named 'gcs-subdomain.my.domain.tld', or a Google Cloud Load | ||
| * Balancer which routes to a bucket you own, e.g. 'my-load-balancer-domain.tld'. Note that this |
|
|
||
| boolean usePathStyle = shouldUsePathStyleForSignedUrl(optionMap); | ||
|
|
||
| String url = |
There was a problem hiding this comment.
The ternary operator is hard to read when broken across multiple lines. Consider if else.
There was a problem hiding this comment.
Elliotte's comment here makes sense. Probably want to use an if-else in this case.
| @@ -0,0 +1,202 @@ | |||
| /* | |||
| * Copyright 2019 Google LLC | |||
|
|
||
| package com.google.cloud.storage; | ||
|
|
||
| import static com.google.cloud.storage.Storage.V4ConditionType.MATCHES; |
There was a problem hiding this comment.
Use non-static imports here as these are not well-known names.
| private final ServiceAccountCredentials serviceAccountCredentials; | ||
|
|
||
| /** | ||
| * @param testData The serialized test data representing the test case. |
There was a problem hiding this comment.
nit: no cap and no period since it's not a complete sentence
| } | ||
|
|
||
| /** | ||
| * Load all of the tests and return a {@code Collection<Object[]>} representing the set of tests. |
frankyn
left a comment
There was a problem hiding this comment.
I'm still reviewing your PR. One ask is to add examples of how your code is expected to be used into Surface Review Doc
| } | ||
| } | ||
|
|
||
| class V4PostConditions { |
There was a problem hiding this comment.
+1 could you split this up into separate files for maintainability as well?
| SignUrlOption style = SignUrlOption.withPathStyle(); | ||
|
|
||
| if (testData.getUrlStyle().equals(SigningV4Test.UrlStyle.VIRTUAL_HOSTED_STYLE)) { | ||
| if (testData.getUrlStyle().equals(UrlStyle.VIRTUAL_HOSTED_STYLE)) { |
There was a problem hiding this comment.
can you split out this into a separte PR if possible?
There was a problem hiding this comment.
For this specifically, I mean to split out conformance test changes into a separate PR.
frankyn
left a comment
There was a problem hiding this comment.
Thanks again for your patience @JesseLovelace.
| SignUrlOption style = SignUrlOption.withPathStyle(); | ||
|
|
||
| if (testData.getUrlStyle().equals(SigningV4Test.UrlStyle.VIRTUAL_HOSTED_STYLE)) { | ||
| if (testData.getUrlStyle().equals(UrlStyle.VIRTUAL_HOSTED_STYLE)) { |
There was a problem hiding this comment.
For this specifically, I mean to split out conformance test changes into a separate PR.
| } | ||
| } | ||
|
|
||
| class V4PostPolicyOption implements Serializable { |
There was a problem hiding this comment.
Can you split all V4PostPolicy helper classes into a separate file, except what's needed for generateV4PresignedPostPolicy ease of use such as V4PostPolicyOption?
| return generateV4PresignedPostPolicy( | ||
| blobInfo, V4PostFields.newBuilder().build(), duration, options); | ||
| } | ||
|
|
There was a problem hiding this comment.
Put V4 at the end of the name please.
There was a problem hiding this comment.
Please do this for other helpers as well that use V4 for POST Policy. From meeting.
frankyn
left a comment
There was a problem hiding this comment.
@JesseLovelace adding name change request for top level method name.
| */ | ||
| URL signUrl(BlobInfo blobInfo, long duration, TimeUnit unit, SignUrlOption... options); | ||
|
|
||
| V4PostPolicy generateV4PresignedPostPolicy( |
There was a problem hiding this comment.
Using consistent naming across languages, please use: generateSignedPostPolicyV4.
frankyn
left a comment
There was a problem hiding this comment.
Some surface changes requested. Open to discussing them as well.
| * @param duration how long until the form expires, in milliseconds | ||
| * @param options optional post policy options | ||
| */ | ||
| PostPolicyV4 generatePresignedPostPolicyV4( |
There was a problem hiding this comment.
use generateSignedPostPolicyV4
| */ | ||
| PostPolicyV4 generatePresignedPostPolicyV4( | ||
| BlobInfo blobInfo, | ||
| PostFieldsV4 fields, |
There was a problem hiding this comment.
fields and conditions should be optional. I want to say these should be under options.
| this.value = value; | ||
| } | ||
|
|
||
| public static ConditionV4 newV4Condition(ConditionV4Type type, String element, String value) { |
There was a problem hiding this comment.
This doesn't translate correctly for ContentRangeLengths because element and value are start and end respectively.
| } | ||
|
|
||
| public static ConditionV4 newV4Condition(ConditionV4Type type, String element, String value) { | ||
| return new ConditionV4(type, element, value); |
There was a problem hiding this comment.
Given PostConditionV4 requires users to use a related method. Should this class have a private static method helper as well? Also not sure how this is different from private ConditionV4()?
frankyn
left a comment
There was a problem hiding this comment.
Small nits overall LGTM.
Please also add integration tests.
| /** | ||
| * Presigned V4 post policy. | ||
| * | ||
| * @see <a href="https://cloud.google.com/storage/docs/xml-api/post-object" POST Object</a> |
| /** | ||
| * Class representing which fields to specify in a V4 POST request. | ||
| * | ||
| * @see <a href=https://cloud.google.com/storage/docs/xml-api/post-object#form_fields> POST Object Form fields</a> |
There was a problem hiding this comment.
No double quote " around the URL.
| return this; | ||
| } | ||
|
|
||
| public Builder addCustomCondition(ConditionV4Type type, String field, String value) { |
There was a problem hiding this comment.
Suggest removing this until we get a feature request for this method.
There was a problem hiding this comment.
We actually use it in the generate method, but I can change it to package private
There was a problem hiding this comment.
package private sgtm, thanks for clarifying!
| * PostFieldsV4 fields = PostFieldsV4.newBuilder().setAcl("public-read").build(); | ||
| * PostConditionsV4 conditions = PostConditionsV4.newBuilder().addContentTypeCondition(ConditionV4Type.MATCHES, "image/jpeg").build(); | ||
| * | ||
| * PostPolicyV4 policy = storage.generatePresignedPostPolicyV4( |
There was a problem hiding this comment.
uses old, instead of generateSignedPostPolicyV4.
| * | ||
| * PostPolicyV4 policy = storage.generatePresignedPostPolicyV4( | ||
| * BlobInfo.newBuilder("my-bucket", "my-object").build(), | ||
| * fields, conditions, 7, TimeUnit.DAYS); |
There was a problem hiding this comment.
Could you add an example of how to send a POST request with the policy result?
|
|
||
| boolean usePathStyle = shouldUsePathStyleForSignedUrl(optionMap); | ||
|
|
||
| String url = |
There was a problem hiding this comment.
Elliotte's comment here makes sense. Probably want to use an if-else in this case.
| @@ -0,0 +1,202 @@ | |||
| /* | |||
| * Copyright 2019 Google LLC | |||
| PostPolicyV4 generateSignedPostPolicyV4( | ||
| BlobInfo blobInfo, long duration, TimeUnit unit, PostConditionsV4 conditions, PostPolicyV4Option... options); | ||
|
|
||
| PostPolicyV4 generateSignedPostPolicyV4( |
| public Builder setSuccessActionStatus(int successActionStatus) { | ||
| this.successActionStatus = "" + successActionStatus; | ||
| return this; | ||
| } |
There was a problem hiding this comment.
Custom field setter should be available here.
| return this; | ||
| } | ||
|
|
||
| public Builder addCustomMetadataCondition(ConditionV4Type type, String field, String value) { |
There was a problem hiding this comment.
this should be in fields instead.
frankyn
left a comment
There was a problem hiding this comment.
Thanks @JesseLovelace, added a few nit comments. Mainly the integration test should send the request to GCS and make sure it's successful.
| * for(Map.Entry<String, String> entry : policy.getFields().entrySet()) { | ||
| * request.addHeader(entry.getKey(), entry.getValue()); | ||
| * } | ||
| * client.execute(request); |
There was a problem hiding this comment.
This example is missing the file to upload*
| import com.google.cloud.storage.HmacKey; | ||
| import com.google.cloud.storage.HttpMethod; | ||
| import com.google.cloud.storage.PostPolicyV4; | ||
| import com.google.cloud.storage.PostPolicyV4.*; |
There was a problem hiding this comment.
Explicitly import the needed classes and not use *.
| } | ||
|
|
||
| @Test | ||
| public void testSignedPostPolicyV4() { |
There was a problem hiding this comment.
This is more of a unit test so I would say it's good to keep. I'd like to see a request similar to what you added into your documentation above:
PostFieldsV4 fields = PostFieldsV4.newBuilder().setAcl("public-read").build();
PostConditionsV4 conditions = PostConditionsV4.newBuilder().addContentTypeCondition(ConditionV4Type.MATCHES, "image/jpeg").build();
PostPolicyV4 policy = storage.generateSignedPostPolicyV4(
BlobInfo.newBuilder("my-bucket", "my-object").build(),
7, TimeUnit.DAYS, fields, conditions);
HttpClient client = HttpClientBuilder.create().build();
HttpPost request = new HttpPost(policy.getUrl());
for(Map.Entry<String, String> entry : policy.getFields().entrySet()) {
request.addHeader(entry.getKey(), entry.getValue());
}
// Missing data to upload in request
client.execute(request);
| URL signUrl(BlobInfo blobInfo, long duration, TimeUnit unit, SignUrlOption... options); | ||
|
|
||
| /** | ||
| * Generates a URL and a map of fields that can be specified in a form to submit a POST request. |
There was a problem hiding this comment.
in an HTML form
You can link to relevant documentation here: https://cloud.google.com/storage/docs/xml-api/post-object#usage_and_examples
| return this; | ||
| } | ||
|
|
||
| public Builder addBucketCondition(ConditionV4Type type, String bucket) { |
There was a problem hiding this comment.
Please remove this condition.
| <dependency> | ||
| <groupId>com.google.code.gson</groupId> | ||
| <artifactId>gson</artifactId> | ||
| <version>2.8.6</version> |
There was a problem hiding this comment.
what's the scope for gson artifact?
frankyn
left a comment
There was a problem hiding this comment.
LGTM, let's get it merge after you fix the Binary Compat issue.
| * @see <a href="https://cloud.google.com/storage/docs">Google Cloud Storage</a> | ||
| */ | ||
| @InternalExtensionOnly | ||
| public interface Storage extends Service<StorageOptions> { |
There was a problem hiding this comment.
InternalExtensionOnly is necessary, otherwise this change will break API.
There was a problem hiding this comment.
Definitely missed this during review, thank you @dmitry-fa!
| * @see <a | ||
| * href="https://cloud.google.com/storage/docs/json_api/v1/objects/update">https://cloud.google.com/storage/docs/json_api/v1/objects/update</a> | ||
| */ | ||
| Blob update(BlobInfo blobInfo); |
dmitry-fa
left a comment
There was a problem hiding this comment.
Thanks for addressing my notes!
Adds V4 post policy. Will add documentation once implementation is approved
Fixes: #280 #88