Skip to content

Commit cbae516

Browse files
authored
Eagerly Read in LengthValidatingInputStream to Fix Flaky JDK HttpClient Test (Azure#31020)
1 parent feb7ccf commit cbae516

File tree

3 files changed

+23
-14
lines changed

3 files changed

+23
-14
lines changed

sdk/core/azure-core-http-jdk-httpclient/src/main/java/com/azure/core/http/jdk/httpclient/BodyPublisherUtils.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import com.azure.core.util.BinaryData;
1414
import com.azure.core.util.CoreUtils;
1515
import com.azure.core.util.ProgressReporter;
16-
import com.azure.core.util.logging.ClientLogger;
1716
import reactor.adapter.JdkFlowAdapter;
1817

1918
import java.net.http.HttpRequest;
@@ -27,8 +26,6 @@
2726
import static java.net.http.HttpRequest.BodyPublishers.ofString;
2827

2928
final class BodyPublisherUtils {
30-
private static final ClientLogger LOGGER = new ClientLogger(BodyPublisherUtils.class);
31-
3229
private BodyPublisherUtils() {
3330
}
3431

@@ -37,7 +34,7 @@ private BodyPublisherUtils() {
3734
* If progress reporter is not null, configures it to track request body upload.
3835
*
3936
* @param request {@link com.azure.core.http.HttpRequest} instance
40-
* @progressReporter optional progress reporter.
37+
* @param progressReporter optional progress reporter.
4138
* @return the request BodyPublisher
4239
*/
4340
public static HttpRequest.BodyPublisher toBodyPublisher(com.azure.core.http.HttpRequest request, ProgressReporter progressReporter) {
@@ -46,7 +43,7 @@ public static HttpRequest.BodyPublisher toBodyPublisher(com.azure.core.http.Http
4643
return noBody();
4744
}
4845

49-
HttpRequest.BodyPublisher publisher = null;
46+
HttpRequest.BodyPublisher publisher;
5047
BinaryDataContent bodyContent = BinaryDataHelper.getContent(body);
5148
if (bodyContent instanceof ByteArrayContent) {
5249
publisher = ofByteArray(bodyContent.toBytes());

sdk/core/azure-core-test/src/main/java/com/azure/core/test/implementation/RestProxyTests.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -684,15 +684,12 @@ public void asyncPutRequestWithBinaryDataBodyAndMoreThanContentLength() {
684684
*/
685685
@Test
686686
public void asyncPutRequestWithStreamBinaryDataBodyAndMoreThanContentLength() {
687-
Mono<BinaryData> bodyMono = Mono.just(BinaryData.fromStream(
688-
new ByteArrayInputStream("test".getBytes(StandardCharsets.UTF_8))));
689-
StepVerifier.create(
690-
bodyMono.flatMap(body ->
691-
createService(Service9.class).putAsyncBodyAndContentLength(body, 3L)))
687+
BinaryData body = BinaryData.fromStream(new ByteArrayInputStream("test".getBytes(StandardCharsets.UTF_8)));
688+
StepVerifier.create(createService(Service9.class).putAsyncBodyAndContentLength(body, 3L))
692689
.verifyErrorSatisfies(exception -> {
693690
assertTrue(exception instanceof UnexpectedLengthException
694691
|| (exception.getSuppressed().length > 0
695-
&& exception.getSuppressed()[0] instanceof UnexpectedLengthException));
692+
&& exception.getSuppressed()[0] instanceof UnexpectedLengthException));
696693
assertTrue(exception.getMessage().contains("more than"));
697694
});
698695
}

sdk/core/azure-core/src/main/java/com/azure/core/implementation/http/rest/LengthValidatingInputStream.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,25 @@ final class LengthValidatingInputStream extends InputStream {
4646

4747
@Override
4848
public synchronized int read(byte[] b, int off, int len) throws IOException {
49-
int readSize = inner.read(b, off, len);
50-
validateLength(readSize);
49+
int totalRead = 0;
50+
int readSize;
51+
do {
52+
// Attempt to read until the byte array is filled or the inner stream ends.
53+
// This results in finishing validation faster and prevents scenarios such as with JDK HttpClient where
54+
// a large buffer will be requested and it validates read length before we can finish validation.
55+
readSize = inner.read(b, off + totalRead, len - totalRead);
56+
validateLength(readSize);
57+
58+
if (readSize != -1) {
59+
totalRead += readSize;
60+
} else if (totalRead == 0) {
61+
// If the inner stream was already read to completion the first read will return -1, need to set
62+
// total read to -1 to prevent any infinite read loops by returning 0.
63+
totalRead = -1;
64+
}
65+
} while (readSize != -1 && totalRead != len);
5166

52-
return readSize;
67+
return totalRead;
5368
}
5469

5570
@Override

0 commit comments

Comments
 (0)