Skip to content

Commit 6ecc2f8

Browse files
author
Local Merge
committed
addressing review comments
1 parent bf58dfe commit 6ecc2f8

4 files changed

Lines changed: 28 additions & 37 deletions

File tree

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobDownloadHeaders.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ public List<ObjectReplicationPolicy> getObjectReplicationSourcePolicies() {
146146
/**
147147
* Get the contentLength property: The number of bytes present in the response body.
148148
*
149+
* <p>When content validation is enabled, the storage client transparently decodes the structured message
150+
* framing before returning the response. In that case this value reflects the size of the decoded payload
151+
* that callers will actually read — not the larger wire size of the encoded message.</p>
152+
*
149153
* @return the contentLength value.
150154
*/
151155
public Long getContentLength() {

sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/policy/DecodedResponse.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515
import java.nio.charset.Charset;
1616

1717
/**
18-
* {@link HttpResponse} wrapper that exposes a decoded body stream while preserving the request, status code, and
19-
* headers of the original response.
18+
* {@link HttpResponse} wrapper that exposes a decoded body stream while preserving the request and status code of
19+
* the original response.
2020
*
2121
* <p>The policy hands this class a Flux that already represents validated, framing-stripped bytes (produced by the
2222
* decoder pipeline). This class's only job is to make that Flux look like the body of the original
23-
* {@link HttpResponse}. Status code, headers, and request remain identical to the underlying response so callers
24-
* cannot distinguish a validated download from a normal one – the validation is transparent.</p>
23+
* {@link HttpResponse}. {@code Content-Length} is overridden to the decoded payload size so it matches what callers
24+
* will actually read; all other headers are forwarded verbatim. The validation is transparent to callers.</p>
2525
*/
2626
class DecodedResponse extends HttpResponse {
2727
private final HttpResponse originalResponse;
@@ -77,7 +77,7 @@ public Mono<byte[]> getBodyAsByteArray() {
7777
@Override
7878
public Mono<String> getBodyAsString() {
7979
return getBodyAsByteArray()
80-
.map(b -> CoreUtils.bomAwareToString(b, originalResponse.getHeaderValue(HttpHeaderName.CONTENT_TYPE)));
80+
.map(b -> CoreUtils.bomAwareToString(b, adjustedHeaders.getValue(HttpHeaderName.CONTENT_TYPE)));
8181
}
8282

8383
@Override

sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/policy/StorageContentValidationDecoderPolicy.java

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,9 @@ public Mono<HttpResponse> process(HttpPipelineCallContext context, HttpPipelineN
7070
return httpResponse;
7171
}
7272

73-
// Confirm the service actually honored our structured-body request before we hand the body to the decoder.
74-
validateStructuredMessageHeaders(httpResponse);
75-
76-
Long decodedContentLength = getStructuredContentLength(httpResponse.getHeaders());
77-
if (decodedContentLength == null) {
78-
throw LOGGER.logExceptionAsError(new IllegalStateException(
79-
"x-ms-structured-content-length header is present but could not be parsed as a long."));
80-
}
73+
// Confirm the service honored our structured-body request and parse the decoded length in one step,
74+
// failing fast with a consistent error if either header is absent or unparseable.
75+
long decodedContentLength = validateAndGetDecodedContentLength(httpResponse);
8176

8277
// Fresh decoder per response so retries each get a clean state machine.
8378
StructuredMessageDecoder decoder = new StructuredMessageDecoder(contentLength);
@@ -98,11 +93,14 @@ private boolean shouldApplyDecoding(HttpPipelineCallContext context) {
9893
}
9994

10095
/**
101-
* Verifies the response acknowledges the structured-body request: presence of the
102-
* {@code x-ms-structured-body} header and the {@code x-ms-structured-content-length}
103-
* header. If either is missing, the service is sending us a normal body and we must not run the decoder over it.
96+
* Verifies the response acknowledges the structured-body request ({@code x-ms-structured-body} present) and
97+
* parses {@code x-ms-structured-content-length} in one step. Throws with a consistent error message if either
98+
* header is absent or the length value is not parseable as a {@code long}, matching the fail-fast behaviour
99+
* used for other validation failures.
100+
*
101+
* @return the decoded payload size declared by the service.
104102
*/
105-
private void validateStructuredMessageHeaders(HttpResponse httpResponse) {
103+
private long validateAndGetDecodedContentLength(HttpResponse httpResponse) {
106104
String structuredBody
107105
= httpResponse.getHeaders().getValue(Constants.HeaderConstants.STRUCTURED_BODY_TYPE_HEADER_NAME);
108106
String structuredContentLength
@@ -111,6 +109,12 @@ private void validateStructuredMessageHeaders(HttpResponse httpResponse) {
111109
throw LOGGER.logExceptionAsError(
112110
new IllegalStateException("Structured message was requested but the response did not acknowledge it."));
113111
}
112+
try {
113+
return Long.parseLong(structuredContentLength);
114+
} catch (NumberFormatException e) {
115+
throw LOGGER.logExceptionAsError(new IllegalStateException("x-ms-structured-content-length header value '"
116+
+ structuredContentLength + "' could not be parsed as a long.", e));
117+
}
114118
}
115119

116120
/**
@@ -129,22 +133,6 @@ private static Long getContentLength(HttpHeaders headers) {
129133
return null;
130134
}
131135

132-
/**
133-
* Reads {@code x-ms-structured-content-length} as a {@code Long}, returning {@code null} if missing or
134-
* unparseable.
135-
*/
136-
private static Long getStructuredContentLength(HttpHeaders headers) {
137-
String value = headers.getValue(Constants.HeaderConstants.STRUCTURED_CONTENT_LENGTH_HEADER_NAME);
138-
if (value != null) {
139-
try {
140-
return Long.parseLong(value);
141-
} catch (NumberFormatException e) {
142-
// Malformed header; fall through to null.
143-
}
144-
}
145-
return null;
146-
}
147-
148136
/**
149137
* @return true for a 2xx response to a GET request, the only response shape that carries a body we
150138
* can decode. 206 (Partial Content) on retried range downloads is included.

sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/policy/DecodedResponseTests.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,10 @@ public void inheritedGetBodyAsBinaryDataReturnsDecodedBytes() {
217217
public void contentLengthIsOverriddenToDecodedSize() {
218218
long wireSize = 500L;
219219
long decodedSize = 300L;
220-
HttpHeaders h = new HttpHeaders()
221-
.set(HttpHeaderName.CONTENT_LENGTH, String.valueOf(wireSize))
220+
HttpHeaders h = new HttpHeaders().set(HttpHeaderName.CONTENT_LENGTH, String.valueOf(wireSize))
222221
.set(CUSTOM_HEADER, "preserve-me");
223-
DecodedResponse wrapper = new DecodedResponse(mockResponse(200, h, new byte[0]), fluxOf(new byte[0]),
224-
decodedSize);
222+
DecodedResponse wrapper
223+
= new DecodedResponse(mockResponse(200, h, new byte[0]), fluxOf(new byte[0]), decodedSize);
225224

226225
assertEquals(String.valueOf(decodedSize), wrapper.getHeaders().getValue(HttpHeaderName.CONTENT_LENGTH));
227226
assertEquals("preserve-me", wrapper.getHeaders().getValue(CUSTOM_HEADER));

0 commit comments

Comments
 (0)