1010import com .azure .core .http .HttpResponse ;
1111import com .azure .core .test .http .MockHttpResponse ;
1212import com .azure .core .util .BinaryData ;
13+ import com .azure .storage .common .implementation .Constants ;
1314import org .junit .jupiter .api .Test ;
1415import reactor .core .publisher .Flux ;
1516import reactor .test .StepVerifier ;
@@ -64,17 +65,19 @@ public void preservesRequestStatusCodeAndHeaders() {
6465 HttpHeaders h = new HttpHeaders ().set (HttpHeaderName .CONTENT_LENGTH , "100" ).set (CUSTOM_HEADER , "value" );
6566 MockHttpResponse original = mockResponse (206 , h , bytes ("encoded" ));
6667
67- DecodedResponse wrapper = new DecodedResponse (original , fluxOf (bytes ("decoded" )));
68+ DecodedResponse wrapper = new DecodedResponse (original , fluxOf (bytes ("decoded" )), 100L , 80L );
6869
6970 assertSame (original .getRequest (), wrapper .getRequest ());
7071 assertEquals (206 , wrapper .getStatusCode ());
71- assertSame (h , wrapper .getHeaders ());
72+ // Content-Length is overridden to decoded size; other headers are preserved.
73+ assertEquals ("80" , wrapper .getHeaders ().getValue (HttpHeaderName .CONTENT_LENGTH ));
74+ assertEquals ("value" , wrapper .getHeaders ().getValue (CUSTOM_HEADER ));
7275 }
7376
7477 @ Test
7578 public void getHeaderValueByStringReturnsHeaderValue () {
7679 HttpHeaders h = headers (CUSTOM_HEADER , "value" );
77- DecodedResponse wrapper = new DecodedResponse (mockResponse (200 , h , new byte [0 ]), fluxOf (new byte [0 ]));
80+ DecodedResponse wrapper = new DecodedResponse (mockResponse (200 , h , new byte [0 ]), fluxOf (new byte [0 ]), 0L , 0L );
7881
7982 assertEquals ("value" , wrapper .getHeaderValue (CUSTOM_HEADER .getCaseInsensitiveName ()));
8083 assertNull (wrapper .getHeaderValue ("nonexistent" ));
@@ -84,7 +87,7 @@ public void getHeaderValueByStringReturnsHeaderValue() {
8487 public void getBodyReturnsDecodedFlux () {
8588 byte [] decoded = bytes ("decoded body" );
8689 DecodedResponse wrapper
87- = new DecodedResponse (mockResponse (200 , new HttpHeaders (), bytes ("encoded" )), fluxOf (decoded ));
90+ = new DecodedResponse (mockResponse (200 , new HttpHeaders (), bytes ("encoded" )), fluxOf (decoded ), 0L , 0L );
8891
8992 StepVerifier .create (wrapper .getBody ().reduce (new ByteArrayOutputStream (), (sink , buf ) -> {
9093 byte [] copy = new byte [buf .remaining ()];
@@ -98,7 +101,7 @@ public void getBodyReturnsDecodedFlux() {
98101 public void getBodyAsByteArrayReturnsDecodedBytes () {
99102 byte [] decoded = bytes ("decoded body" );
100103 DecodedResponse wrapper
101- = new DecodedResponse (mockResponse (200 , new HttpHeaders (), bytes ("encoded" )), fluxOf (decoded ));
104+ = new DecodedResponse (mockResponse (200 , new HttpHeaders (), bytes ("encoded" )), fluxOf (decoded ), 0L , 0L );
102105
103106 StepVerifier .create (wrapper .getBodyAsByteArray ())
104107 .expectNextMatches (b -> Arrays .equals (decoded , b ))
@@ -111,7 +114,7 @@ public void getBodyAsStringDefaultsToUtf8WhenNoCharsetSpecified() {
111114 // BOM nor a Content-Type charset parameter is present. This test pins the "no headers, no BOM" path.
112115 String text = "héllo wörld – ✓" ;
113116 DecodedResponse wrapper = new DecodedResponse (mockResponse (200 , new HttpHeaders (), new byte [0 ]),
114- fluxOf (text .getBytes (StandardCharsets .UTF_8 )));
117+ fluxOf (text .getBytes (StandardCharsets .UTF_8 )), 0L , 0L );
115118
116119 StepVerifier .create (wrapper .getBodyAsString ()).expectNext (text ).verifyComplete ();
117120 }
@@ -124,7 +127,7 @@ public void getBodyAsStringHonorsCharsetFromContentTypeHeader() {
124127 String text = "ümlaut" ;
125128 byte [] iso = text .getBytes (StandardCharsets .ISO_8859_1 );
126129 HttpHeaders h = new HttpHeaders ().set (HttpHeaderName .CONTENT_TYPE , "text/plain; charset=ISO-8859-1" );
127- DecodedResponse wrapper = new DecodedResponse (mockResponse (200 , h , new byte [0 ]), fluxOf (iso ));
130+ DecodedResponse wrapper = new DecodedResponse (mockResponse (200 , h , new byte [0 ]), fluxOf (iso ), 0L , 0L );
128131
129132 StepVerifier .create (wrapper .getBodyAsString ()).expectNext (text ).verifyComplete ();
130133 }
@@ -140,7 +143,7 @@ public void getBodyAsStringDetectsUtf8BomAndStripsIt() {
140143 System .arraycopy (bom , 0 , withBom , 0 , bom .length );
141144 System .arraycopy (payload , 0 , withBom , bom .length , payload .length );
142145 DecodedResponse wrapper
143- = new DecodedResponse (mockResponse (200 , new HttpHeaders (), new byte [0 ]), fluxOf (withBom ));
146+ = new DecodedResponse (mockResponse (200 , new HttpHeaders (), new byte [0 ]), fluxOf (withBom ), 0L , 0L );
144147
145148 StepVerifier .create (wrapper .getBodyAsString ()).expectNext (text ).verifyComplete ();
146149 }
@@ -150,7 +153,7 @@ public void getBodyAsStringDecodesUsingProvidedCharset() {
150153 String text = "ümlaut" ;
151154 byte [] latin1 = text .getBytes (StandardCharsets .ISO_8859_1 );
152155 DecodedResponse wrapper
153- = new DecodedResponse (mockResponse (200 , new HttpHeaders (), new byte [0 ]), fluxOf (latin1 ));
156+ = new DecodedResponse (mockResponse (200 , new HttpHeaders (), new byte [0 ]), fluxOf (latin1 ), 0L , 0L );
154157
155158 StepVerifier .create (wrapper .getBodyAsString (StandardCharsets .ISO_8859_1 )).expectNext (text ).verifyComplete ();
156159 }
@@ -160,7 +163,7 @@ public void inheritedGetBodyAsInputStreamUsesDecodedBytes() throws IOException {
160163 // Base getBodyAsInputStream() routes through getBodyAsByteArray(), so the override is exercised end-to-end.
161164 byte [] decoded = bytes ("decoded stream" );
162165 DecodedResponse wrapper
163- = new DecodedResponse (mockResponse (200 , new HttpHeaders (), bytes ("encoded" )), fluxOf (decoded ));
166+ = new DecodedResponse (mockResponse (200 , new HttpHeaders (), bytes ("encoded" )), fluxOf (decoded ), 0L , 0L );
164167
165168 try (InputStream stream = wrapper .getBodyAsInputStream ().block ()) {
166169 assertNotNull (stream );
@@ -172,7 +175,7 @@ public void inheritedGetBodyAsInputStreamUsesDecodedBytes() throws IOException {
172175 public void inheritedWriteBodyToWritesDecodedBytes () throws IOException {
173176 byte [] decoded = bytes ("write me" );
174177 DecodedResponse wrapper
175- = new DecodedResponse (mockResponse (200 , new HttpHeaders (), bytes ("encoded" )), fluxOf (decoded ));
178+ = new DecodedResponse (mockResponse (200 , new HttpHeaders (), bytes ("encoded" )), fluxOf (decoded ), 0L , 0L );
176179
177180 ByteArrayOutputStream sink = new ByteArrayOutputStream ();
178181 try (WritableByteChannel channel = Channels .newChannel (sink )) {
@@ -186,7 +189,7 @@ public void inheritedWriteBodyToWritesDecodedBytes() throws IOException {
186189 public void inheritedBufferReturnsResponseBackedByDecodedBytes () {
187190 byte [] decoded = bytes ("buffered" );
188191 DecodedResponse wrapper
189- = new DecodedResponse (mockResponse (200 , new HttpHeaders (), bytes ("encoded" )), fluxOf (decoded ));
192+ = new DecodedResponse (mockResponse (200 , new HttpHeaders (), bytes ("encoded" )), fluxOf (decoded ), 0L , 0L );
190193
191194 HttpResponse buffered = wrapper .buffer ();
192195 assertNotNull (buffered );
@@ -201,15 +204,34 @@ public void inheritedGetBodyAsBinaryDataReturnsDecodedBytes() {
201204 // must contain the decoded payload, not the original wire body. A divergent Content-Length header is set
202205 // to make the wire vs decoded distinction explicit and guard against regressions in header forwarding.
203206 byte [] decoded = bytes ("decoded payload" );
204- HttpHeaders h = new HttpHeaders ().set (HttpHeaderName .CONTENT_LENGTH , String .valueOf (decoded .length + 32 ));
205- DecodedResponse wrapper
206- = new DecodedResponse (mockResponse (200 , h , bytes ("encoded wire body" )), fluxOf (decoded ));
207+ long originalSize = decoded .length + 32 ;
208+ HttpHeaders h = new HttpHeaders ().set (HttpHeaderName .CONTENT_LENGTH , String .valueOf (originalSize ));
209+ DecodedResponse wrapper = new DecodedResponse (mockResponse (200 , h , bytes ("encoded wire body" )), fluxOf (decoded ),
210+ originalSize , decoded .length );
207211
208212 BinaryData data = wrapper .getBodyAsBinaryData ();
209213 assertNotNull (data );
210214 assertArrayEquals (decoded , data .toBytes ());
211215 }
212216
217+ @ Test
218+ public void contentLengthIsOverriddenToDecodedSizeAndOriginalIsPreserved () {
219+ long originalSize = 500L ;
220+ long decodedSize = 300L ;
221+ HttpHeaders h = new HttpHeaders ().set (HttpHeaderName .CONTENT_LENGTH , String .valueOf (originalSize ))
222+ .set (CUSTOM_HEADER , "preserve-me" );
223+ DecodedResponse wrapper
224+ = new DecodedResponse (mockResponse (200 , h , new byte [0 ]), fluxOf (new byte [0 ]), originalSize , decodedSize );
225+
226+ assertEquals (String .valueOf (decodedSize ), wrapper .getHeaders ().getValue (HttpHeaderName .CONTENT_LENGTH ));
227+ assertEquals (String .valueOf (originalSize ),
228+ wrapper .getHeaders ().getValue (Constants .HeaderConstants .ORIGINAL_CONTENT_LENGTH_HEADER_NAME ));
229+ assertEquals ("preserve-me" , wrapper .getHeaders ().getValue (CUSTOM_HEADER ));
230+ // Deprecated getHeaderValue must reflect the same overrides.
231+ assertEquals (String .valueOf (decodedSize ),
232+ wrapper .getHeaderValue (HttpHeaderName .CONTENT_LENGTH .getCaseInsensitiveName ()));
233+ }
234+
213235 private static byte [] readAll (InputStream stream ) throws IOException {
214236 ByteArrayOutputStream out = new ByteArrayOutputStream ();
215237 byte [] buf = new byte [1024 ];
0 commit comments