Skip to content
This repository was archived by the owner on Jul 19, 2024. It is now read-only.

Commit e91a622

Browse files
committed
Added preserveRawValue option to SharedAccessHeaders
1 parent 2b87018 commit e91a622

File tree

4 files changed

+150
-19
lines changed

4 files changed

+150
-19
lines changed

ChangeLog.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
2019.08.15 Version 8.5.0
1+
2019.12.02 Version 8.5.0
22
* Support for HTTP proxy with Basic auth.
33
* Support for HTTP proxy with Digest auth.
4+
* Added an option to SharedAccessHeaders that will allow the customer to preserve the raw value set on the object. Headers could previously be changed by an internal url decode that might modified the desired value.
45

56
2019.08.05 Version 8.4.0
67
* Support for 2019-02-02 REST version. Please see our REST API documentation and blogs for information about the related added features.

microsoft-azure-storage-test/src/com/microsoft/azure/storage/blob/SasTests.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,47 @@ public void eventOccurred(SendingRequestEvent eventArg) {
459459
sasBlob.download(new ByteArrayOutputStream(), null, null, context);
460460
}
461461

462+
@Test
463+
@Category(SlowTests.class)
464+
public void testBlobSaSWithSharedAccessBlobHeadersPreserveRaw() throws InvalidKeyException,
465+
IllegalArgumentException, StorageException, URISyntaxException, InterruptedException {
466+
SharedAccessBlobPolicy sp = createSharedAccessPolicy(EnumSet.of(SharedAccessBlobPermissions.READ,
467+
SharedAccessBlobPermissions.WRITE, SharedAccessBlobPermissions.LIST), 300);
468+
BlobContainerPermissions perms = new BlobContainerPermissions();
469+
470+
perms.getSharedAccessPolicies().put("readperm", sp);
471+
this.container.uploadPermissions(perms);
472+
Thread.sleep(30000);
473+
474+
SharedAccessBlobHeaders headers = new SharedAccessBlobHeaders(true);
475+
headers.setCacheControl("no%20cache");
476+
headers.setContentDisposition("inline; filename=\"My Image.jpg\"; filename*=UTF-8''My%20Image.jpg");
477+
headers.setContentEncoding("gzip%20");
478+
headers.setContentLanguage("da%20");
479+
headers.setContentType("text/html; charset=utf%208");
480+
481+
CloudBlockBlob sasBlob = new CloudBlockBlob(new URI(this.blob.getUri().toString() + "?"
482+
+ this.blob.generateSharedAccessSignature(null, headers, "readperm")));
483+
OperationContext context = new OperationContext();
484+
485+
context.getSendingRequestEventHandler().addListener(new StorageEvent<SendingRequestEvent>() {
486+
487+
@Override
488+
public void eventOccurred(SendingRequestEvent eventArg) {
489+
HttpURLConnection connection = (HttpURLConnection) eventArg.getConnectionObject();
490+
assertEquals("no%20cache", connection.getHeaderField(Constants.HeaderConstants.CACHE_CONTROL));
491+
assertEquals("inline; filename=\"My Image.jpg\"; filename*=UTF-8''My%20Image.jpg",
492+
connection.getHeaderField(Constants.HeaderConstants.CONTENT_DISPOSITION));
493+
assertEquals("gzip%20", connection.getHeaderField(Constants.HeaderConstants.CONTENT_ENCODING));
494+
assertEquals("da%20", connection.getHeaderField(Constants.HeaderConstants.CONTENT_LANGUAGE));
495+
assertEquals("text/html; charset=utf%208",
496+
connection.getHeaderField(Constants.HeaderConstants.CONTENT_TYPE));
497+
}
498+
});
499+
500+
sasBlob.download(new ByteArrayOutputStream(), null, null, context);
501+
}
502+
462503
@Test
463504
public void testAppendBlobCopyWithSasAndSnapshot()
464505
throws URISyntaxException, StorageException, InterruptedException, IOException, InvalidKeyException {

microsoft-azure-storage/src/com/microsoft/azure/storage/SharedAccessHeaders.java

Lines changed: 88 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/**
22
* Copyright Microsoft Corporation
3-
*
3+
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
* http://www.apache.org/licenses/LICENSE-2.0
8-
*
8+
*
99
* Unless required by applicable law or agreed to in writing, software
1010
* distributed under the License is distributed on an "AS IS" BASIS,
1111
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,6 +20,8 @@
2020
* RESERVED FOR INTERNAL USE. Represents the optional headers that can be returned using SAS.
2121
*/
2222
public abstract class SharedAccessHeaders {
23+
private final boolean preserveRawValue;
24+
2325
/**
2426
* The cache-control header returned.
2527
*/
@@ -49,11 +51,31 @@ public abstract class SharedAccessHeaders {
4951
* Initializes a new instance of the {@link SharedAccessHeaders} class.
5052
*/
5153
public SharedAccessHeaders() {
54+
this(false);
55+
}
56+
57+
/**
58+
* Initializes a new instance of the {@link SharedAccessHeaders} class. The empty constructor should be preferred
59+
* and this option should only be used by customers who are sure they do not want the safety usually afforded by
60+
* this SDK when constructing a sas.
61+
* <p>
62+
* The header values are typically decoded before building the sas token. This can cause problems if the desired
63+
* value for one of the headers contains something that looks like encoding. Setting this flag to true will ensure
64+
* that the value of these headers are preserved as set on this object when constructing the sas.
65+
* <p>
66+
* Note that these values are preserved by encoding them here so that the decoding which happens at sas construction
67+
* time returns them to the original values. So if get is called on this object when preserveRawValues was set to
68+
* true, the value returned will be percent encoded.
69+
*
70+
* @param preserveRawValue Whether the sdk should preserve the raw value of these headers.
71+
*/
72+
public SharedAccessHeaders(boolean preserveRawValue) {
73+
this.preserveRawValue = preserveRawValue;
5274
}
5375

5476
/**
5577
* Initializes a new instance of the {@link SharedAccessHeaders} class based on an existing instance.
56-
*
78+
*
5779
* @param other
5880
* A {@link SharedAccessHeaders} object which specifies the set of properties to clone.
5981
*/
@@ -65,11 +87,13 @@ public SharedAccessHeaders(SharedAccessHeaders other) {
6587
this.contentEncoding = other.contentEncoding;
6688
this.contentLanguage = other.contentLanguage;
6789
this.cacheControl = other.cacheControl;
90+
91+
this.preserveRawValue = other.preserveRawValue;
6892
}
6993

7094
/**
7195
* Gets the cache control header.
72-
*
96+
*
7397
* @return A <code>String</code> which represents the cache control header.
7498
*/
7599
public String getCacheControl() {
@@ -78,17 +102,26 @@ public String getCacheControl() {
78102

79103
/**
80104
* Sets the cache control header.
81-
*
105+
*
82106
* @param cacheControl
83107
* A <code>String</code> which specifies the cache control header.
84108
*/
85109
public void setCacheControl(String cacheControl) {
86-
this.cacheControl = cacheControl;
110+
if (this.preserveRawValue) {
111+
try {
112+
this.cacheControl = Utility.safeEncode(cacheControl);
113+
} catch (StorageException e) {
114+
e.printStackTrace();
115+
}
116+
}
117+
else {
118+
this.cacheControl = cacheControl;
119+
}
87120
}
88121

89122
/**
90123
* Gets the content disposition header.
91-
*
124+
*
92125
* @return A <code>String</code> which represents the content disposition header.
93126
*/
94127
public String getContentDisposition() {
@@ -97,17 +130,26 @@ public String getContentDisposition() {
97130

98131
/**
99132
* Sets the content disposition header.
100-
*
133+
*
101134
* @param contentDisposition
102135
* A <code>String</code> which specifies the content disposition header.
103136
*/
104137
public void setContentDisposition(String contentDisposition) {
105-
this.contentDisposition = contentDisposition;
138+
if (this.preserveRawValue) {
139+
try {
140+
this.contentDisposition = Utility.safeEncode(contentDisposition);
141+
} catch (StorageException e) {
142+
e.printStackTrace();
143+
}
144+
}
145+
else {
146+
this.contentDisposition = contentDisposition;
147+
}
106148
}
107149

108150
/**
109151
* Gets the content encoding header.
110-
*
152+
*
111153
* @return A <code>String</code> which represents the content encoding header.
112154
*/
113155
public String getContentEncoding() {
@@ -116,17 +158,26 @@ public String getContentEncoding() {
116158

117159
/**
118160
* Sets the content encoding header.
119-
*
161+
*
120162
* @param contentEncoding
121163
* A <code>String</code> which specifies the content encoding header.
122164
*/
123165
public void setContentEncoding(String contentEncoding) {
124-
this.contentEncoding = contentEncoding;
166+
if (this.preserveRawValue) {
167+
try {
168+
this.contentEncoding = Utility.safeEncode(contentEncoding);
169+
} catch (StorageException e) {
170+
e.printStackTrace();
171+
}
172+
}
173+
else {
174+
this.contentEncoding = contentEncoding;
175+
}
125176
}
126177

127178
/**
128179
* Gets the content language header.
129-
*
180+
*
130181
* @return A <code>String</code> which represents the content language header.
131182
*/
132183
public String getContentLanguage() {
@@ -135,17 +186,26 @@ public String getContentLanguage() {
135186

136187
/**
137188
* Sets the content language header.
138-
*
189+
*
139190
* @param contentLanguage
140191
* A <code>String</code> which specifies the content language header.
141192
*/
142193
public void setContentLanguage(String contentLanguage) {
143-
this.contentLanguage = contentLanguage;
194+
if (this.preserveRawValue) {
195+
try {
196+
this.contentLanguage = Utility.safeEncode(contentLanguage);
197+
} catch (StorageException e) {
198+
e.printStackTrace();
199+
}
200+
}
201+
else {
202+
this.contentLanguage = contentLanguage;
203+
}
144204
}
145205

146206
/**
147207
* Gets the content type header.
148-
*
208+
*
149209
* @return A <code>String</code> which represents the content type header.
150210
*/
151211
public String getContentType() {
@@ -154,11 +214,21 @@ public String getContentType() {
154214

155215
/**
156216
* Sets the content type header.
157-
*
217+
*
158218
* @param contentType
159219
* A <code>String</code> which specifies the content type header.
160220
*/
161221
public void setContentType(String contentType) {
162-
this.contentType = contentType;
222+
if (this.preserveRawValue) {
223+
try {
224+
this.contentType = Utility.safeEncode(contentType);
225+
} catch (StorageException e) {
226+
e.printStackTrace();
227+
}
228+
}
229+
else {
230+
this.contentType = contentType;
231+
}
163232
}
164233
}
234+

microsoft-azure-storage/src/com/microsoft/azure/storage/blob/SharedAccessBlobHeaders.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,27 @@ public final class SharedAccessBlobHeaders extends SharedAccessHeaders {
2424
* Initializes a new instance of the {@link SharedAccessBlobHeaders} class.
2525
*/
2626
public SharedAccessBlobHeaders() {
27+
super();
2728
}
2829

30+
/**
31+
* Initializes a new instance of the {@link SharedAccessHeaders} class. The empty constructor should be preferred
32+
* and this option should only be used by customers who are sure they do not want the safety usually afforded by
33+
* this SDK when constructing a sas.
34+
* <p>
35+
* The header values are typically decoded before building the sas token. This can cause problems if the desired
36+
* value for one of the headers contains something that looks like encoding. Setting this flag to true will ensure
37+
* that the value of these headers are preserved as set on this object when constructing the sas.
38+
* <p>
39+
* Note that these values are preserved by encoding them here so that the decoding which happens at sas construction
40+
* time returns them to the original values. So if get is called on this object when preserveRawValues was set to
41+
* true, the value returned will be percent encoded.
42+
*
43+
* @param preserveRawValue Whether the sdk should preserve the raw value of these headers.
44+
*/
45+
public SharedAccessBlobHeaders(boolean preserveRawValue) {
46+
super(preserveRawValue);
47+
}
2948
/**
3049
* Initializes a new instance of the {@link SharedAccessBlobHeaders} class based on an existing instance.
3150
*

0 commit comments

Comments
 (0)