Skip to content
This repository has been archived by the owner. It is now read-only.
Browse files
8239052: java/net/httpclient/whitebox/ fail…
…ed with BufferUnderflowException against TLSv1.3

The test assumed that ByteBuffer would be split at long boundaries. This is obviously not always the case. A carry has been added to support reading a long split over several buffers.

Reviewed-by: chegar
  • Loading branch information
dfuch committed Feb 24, 2020
1 parent 965e330 commit f7c819a72d94de04da308732fa837347584b3403
@@ -49,6 +49,7 @@

* @test
* @bug 8238990
* @run main/othervm -Djdk.internal.httpclient.debug=true HandshakeFailureTest TLSv1.2
* @run main/othervm -Djdk.internal.httpclient.debug=true HandshakeFailureTest TLSv1.3
* @summary Verify SSLHandshakeException is received when the handshake fails,
@@ -1,5 +1,5 @@
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* This code is free software; you can redistribute it and/or modify it
@@ -126,19 +126,24 @@ protected static void sleep(long millis) {
protected static class EndSubscriber implements FlowTube.TubeSubscriber {

private static final int REQUEST_WINDOW = 13;
private static final int SIZEOF_LONG = 8;

private final long nbytes;
private final AtomicLong counter = new AtomicLong();
private final CompletableFuture<?> completion;
private final CountDownLatch allBytesReceived;
private volatile Flow.Subscription subscription;
private long unfulfilled;
private final ByteBuffer carry; // used if buffers don't break at long boundaries.

EndSubscriber(long nbytes, CompletableFuture<?> completion,
CountDownLatch allBytesReceived) {
this.nbytes = nbytes;
this.completion = completion;
this.allBytesReceived = allBytesReceived;
this.carry = ByteBuffer.allocate(SIZEOF_LONG);

@@ -159,6 +164,56 @@ public static String info(List<ByteBuffer> i) {
return sb.toString();

// Check whether we need bytes from the next buffer to read
// the next long. If yes, drains the current buffer into the
// carry and returns true. If no and the current buffer
// or the carry have enough bytes to read a long, return
// false.
private boolean requiresMoreBytes(ByteBuffer buf) {
// First see if the carry contains some left over bytes
// from the previous buffer
if (carry.hasRemaining()) {
// If so fills up the carry, if we can
while (carry.hasRemaining() && buf.hasRemaining()) {
if (!carry.hasRemaining()) {
// The carry is full: we can use it.
return false;
} else {
// There was not enough bytes to fill the carry,
// continue with next buffer.
assert !buf.hasRemaining();
return true;
} else if (buf.remaining() < SIZEOF_LONG) {
// The carry is empty and the current buffer doesn't
// have enough bytes: drains it into the carry.
assert carry.hasRemaining();
assert !buf.hasRemaining();
// We still need more bytes from the next buffer.
return true;
// We have enough bytes to read a long. No need
// to read from next buffer.
assert buf.remaining() >= SIZEOF_LONG;
return false;

private long readNextLong(ByteBuffer buf) {
// either the carry is ready to use (it must have 8 bytes to read)
// or it must be used up and at the limit.
assert !carry.hasRemaining() || carry.remaining() == SIZEOF_LONG;
// either we have a long in the carry, or we have enough bytes in the buffer
assert carry.remaining() == SIZEOF_LONG || buf.remaining() >= SIZEOF_LONG;

ByteBuffer source = carry.hasRemaining() ? carry : buf;
return source.getLong();

public void onNext(List<ByteBuffer> buffers) {
if (--unfulfilled == (REQUEST_WINDOW / 2)) {
@@ -176,7 +231,17 @@ public void onNext(List<ByteBuffer> buffers) {

for (ByteBuffer buf : buffers) {
while (buf.hasRemaining()) {
long n = buf.getLong();
// first check if we have enough bytes to
// read a long. If not, place the bytes in
// the carry and continue with next buffer.
if (requiresMoreBytes(buf)) continue;

// either we have a long in the carry, or we have
// enough bytes in the buffer to read a long.
long n = readNextLong(buf);

assert !carry.hasRemaining();

if (currval > (TOTAL_LONGS - 50)) {
System.out.println("End: " + currval);
@@ -225,7 +290,6 @@ protected static SSLEngine createSSLEngine(boolean client) throws IOException {
SSLContext context = (new SimpleSSLContext()).get();
SSLEngine engine = context.createSSLEngine();
SSLParameters params = context.getSupportedSSLParameters();
params.setProtocols(new String[]{"TLSv1.2"}); // TODO: This is essential. Needs to be protocol impl
if (client) {
params.setApplicationProtocols(new String[]{"proto1", "proto2"}); // server will choose proto2
} else {

0 comments on commit f7c819a

Please sign in to comment.