8299015: Ensure that HttpResponse.BodySubscribers.ofFile writes all bytes

Backport-of: a7d6de71bb83c8715654f61dd166aad6e8dab847
This commit is contained in:
Chris Hegarty 2022-12-22 12:49:25 +00:00
parent 5e001d6ff3
commit 9863f59e1d
3 changed files with 42 additions and 3 deletions
src/java.net.http/share/classes/jdk/internal/net/http
test/jdk/java/net/httpclient/PathSubscriber

@ -282,7 +282,10 @@ public class ResponseSubscribers {
@Override
public void onNext(List<ByteBuffer> items) {
try {
out.write(items.toArray(Utils.EMPTY_BB_ARRAY));
ByteBuffer[] buffers = items.toArray(Utils.EMPTY_BB_ARRAY);
do {
out.write(buffers);
} while (Utils.hasRemaining(buffers));
} catch (IOException ex) {
close();
subscription.cancel();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -665,6 +665,14 @@ public final class Utils {
return false;
}
public static boolean hasRemaining(ByteBuffer[] bufs) {
for (ByteBuffer buf : bufs) {
if (buf.hasRemaining())
return true;
}
return false;
}
public static long remaining(List<ByteBuffer> bufs) {
long remain = 0;
for (ByteBuffer buf : bufs) {

@ -23,7 +23,7 @@
/*
* @test
* @bug 8237470
* @bug 8237470 8299015
* @summary Confirm HttpResponse.BodySubscribers#ofFile(Path)
* works with default and non-default file systems
* when SecurityManager is enabled
@ -66,11 +66,15 @@ import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse.BodyHandler;
import java.net.http.HttpResponse.BodySubscriber;
import java.net.http.HttpResponse.BodySubscribers;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;
import java.util.concurrent.Flow;
import java.util.stream.IntStream;
import static java.lang.System.out;
import static java.net.http.HttpClient.Builder.NO_PROXY;
@ -199,6 +203,30 @@ public class BodySubscriberOfFileTest implements HttpServerAdapters {
}
}
// A large enough number of buffers to gather from, in an attempt to provoke a partial
// write. Loosely based on the value of _SC_IOV_MAX, to trigger partial gathering write.
private static final int NUM_GATHERING_BUFFERS = 1024 + 1;
@Test
public void testSubscribersWritesAllBytes() throws Exception {
var buffers = IntStream.range(0, NUM_GATHERING_BUFFERS)
.mapToObj(i -> new byte[10])
.map(ByteBuffer::wrap).toList();
int expectedSize = buffers.stream().mapToInt(Buffer::remaining).sum();
var subscriber = BodySubscribers.ofFile(defaultFsPath);
subscriber.onSubscribe(new Flow.Subscription() {
@Override
public void request(long n) { }
@Override
public void cancel() { }
});
subscriber.onNext(buffers);
subscriber.onComplete();
buffers.forEach(b -> assertEquals(b.remaining(), 0) );
assertEquals(expectedSize, Files.size(defaultFsPath));
}
@BeforeTest
public void setup() throws Exception {
sslContext = new SimpleSSLContext().get();