This commit is contained in:
Jonathan Gibbons 2017-04-28 15:43:43 -07:00
commit 03be4097ae
34 changed files with 586 additions and 149 deletions

View File

@ -25,9 +25,25 @@
include LauncherCommon.gmk
# The JVMCI exports are needed since JVMCI is normally dynamically exported
# (see jdk.vm.ci.services.internal.ReflectionAccessJDK::openJVMCITo).
$(eval $(call SetupBuildLauncher, jaotc, \
MAIN_CLASS := jdk.tools.jaotc.Main, \
JAVA_ARGS := -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.aarch64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.amd64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.code=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.code.site=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.code.stack=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.common=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.amd64=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.sparc=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.meta=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.runtime=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.sparc=$(call CommaList, jdk.internal.vm.compiler jdk.aot) \
-XX:+UseAOT \
-Djvmci.UseProfilingInformation=false \
-Dgraal.UseExceptionProbability=false \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2017, 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
@ -2846,6 +2846,7 @@ public final class Scanner implements Iterator<String>, Closeable {
class FindSpliterator extends Spliterators.AbstractSpliterator<MatchResult> {
final Pattern pattern;
int expectedCount = -1;
private boolean advance = false; // true if we need to auto-advance
FindSpliterator(Pattern pattern) {
super(Long.MAX_VALUE,
@ -2861,12 +2862,15 @@ public final class Scanner implements Iterator<String>, Closeable {
throw new ConcurrentModificationException();
}
} else {
// init
matchValid = false;
matcher.usePattern(pattern);
expectedCount = modCount;
}
while (true) {
// assert expectedCount == modCount
if (findPatternInBuffer(pattern, 0)) { // doesn't increment modCount
if (nextInBuffer()) { // doesn't increment modCount
cons.accept(matcher.toMatchResult());
if (expectedCount != modCount) {
throw new ConcurrentModificationException();
@ -2879,6 +2883,29 @@ public final class Scanner implements Iterator<String>, Closeable {
return false; // reached end of input
}
}
// reimplementation of findPatternInBuffer with auto-advance on zero-length matches
private boolean nextInBuffer() {
if (advance) {
if (position + 1 > buf.limit()) {
if (!sourceClosed)
needInput = true;
return false;
}
position++;
advance = false;
}
matcher.region(position, buf.limit());
if (matcher.find() && (!matcher.hitEnd() || sourceClosed)) {
// Did not hit end, or hit real end
position = matcher.end();
advance = matcher.start() == position;
return true;
}
if (!sourceClosed)
needInput = true;
return false;
}
}
/** Small LRU cache of Patterns. */

View File

@ -26,7 +26,10 @@
package jdk.internal.misc;
import static java.lang.Thread.State.*;
import java.util.Map;
import java.util.HashMap;
import java.util.Properties;
import java.util.Collections;
public class VM {
@ -132,25 +135,33 @@ public class VM {
* Returns the system property of the specified key saved at
* system initialization time. This method should only be used
* for the system properties that are not changed during runtime.
* It accesses a private copy of the system properties so
* that user's locking of the system properties object will not
* cause the library to deadlock.
*
* Note that the saved system properties do not include
* the ones set by sun.misc.Version.init().
*
* the ones set by java.lang.VersionProps.init().
*/
public static String getSavedProperty(String key) {
if (savedProps.isEmpty())
throw new IllegalStateException("Should be non-empty if initialized");
if (savedProps == null)
throw new IllegalStateException("Not yet initialized");
return savedProps.getProperty(key);
return savedProps.get(key);
}
// TODO: the Property Management needs to be refactored and
// the appropriate prop keys need to be accessible to the
// calling classes to avoid duplication of keys.
private static final Properties savedProps = new Properties();
/**
* Gets an unmodifiable view of the system properties saved at system
* initialization time. This method should only be used
* for the system properties that are not changed during runtime.
*
* Note that the saved system properties do not include
* the ones set by java.lang.VersionProps.init().
*/
public static Map<String, String> getSavedProperties() {
if (savedProps == null)
throw new IllegalStateException("Not yet initialized");
return savedProps;
}
private static Map<String, String> savedProps;
// Save a private copy of the system properties and remove
// the system properties that are not intended for public access.
@ -160,7 +171,12 @@ public class VM {
if (initLevel() != 0)
throw new IllegalStateException("Wrong init level");
savedProps.putAll(props);
@SuppressWarnings({"rawtypes", "unchecked"})
Map<String, String> sp =
Map.ofEntries(props.entrySet().toArray(new Map.Entry[0]));
// only main thread is running at this time, so savedProps and
// its content will be correctly published to threads started later
savedProps = sp;
// Set the maximum amount of direct memory. This value is controlled
// by the vm option -XX:MaxDirectMemorySize=<size>.

View File

@ -23,14 +23,5 @@
* questions.
*/
// jdk.internal.vm.compiler uses Unsafe and VM classes from jdk.internal.misc
exports jdk.internal.misc to jdk.internal.vm.compiler;
opens jdk.internal.misc to jdk.internal.vm.compiler;
// jdk.internal.vm.compiler uses com.sun.crypto.provider to generate crypto intrinsics
opens com.sun.crypto.provider to jdk.internal.vm.compiler;
exports jdk.internal.module to jdk.internal.vm.compiler;
// AOT uses jdk.internal.misc.Unsafe
exports jdk.internal.misc to jdk.aot;

View File

@ -54,4 +54,4 @@ abstract class AbstractPushPublisher<T> implements Flow.Publisher<T> {
}
}
}
}

View File

@ -70,6 +70,11 @@ interface AsyncConnection {
*/
void startReading();
/**
* Cancel asynchronous reading. Used to downgrade a HTTP/2 connection to HTTP/1
*/
void stopAsyncReading();
/**
* In async mode, this method puts buffers at the end of the send queue.
* When in async mode, calling this method should later be followed by
@ -79,6 +84,11 @@ interface AsyncConnection {
*/
void writeAsync(ByteBufferReference[] buffers) throws IOException;
/**
* Re-enable asynchronous reads through the callback
*/
void enableCallback();
/**
* In async mode, this method may put buffers at the beginning of send queue,
* breaking frames sequence and allowing to write these buffers before other
@ -99,5 +109,4 @@ interface AsyncConnection {
* and continue execution.
*/
void flushAsync() throws IOException;
}

View File

@ -32,6 +32,7 @@ import java.nio.channels.SocketChannel;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
import javax.net.ssl.SSLEngine;
import jdk.incubator.http.internal.common.ByteBufferReference;
import jdk.incubator.http.internal.common.ExceptionallyCloseable;
@ -44,33 +45,48 @@ class AsyncSSLConnection extends HttpConnection
implements AsyncConnection, ExceptionallyCloseable {
final AsyncSSLDelegate sslDelegate;
final PlainHttpConnection delegate;
final PlainHttpConnection plainConnection;
AsyncSSLConnection(InetSocketAddress addr, HttpClientImpl client, String[] ap) {
super(addr, client);
delegate = new PlainHttpConnection(addr, client);
sslDelegate = new AsyncSSLDelegate(delegate, client, ap);
plainConnection = new PlainHttpConnection(addr, client);
sslDelegate = new AsyncSSLDelegate(plainConnection, client, ap);
}
@Override
synchronized void configureMode(Mode mode) throws IOException {
super.configureMode(mode);
delegate.configureMode(mode);
plainConnection.configureMode(mode);
}
private CompletableFuture<Void> configureModeAsync(Void ignore) {
CompletableFuture<Void> cf = new CompletableFuture<>();
try {
configureMode(Mode.ASYNC);
cf.complete(null);
} catch (Throwable t) {
cf.completeExceptionally(t);
}
return cf;
}
@Override
public void connect() throws IOException, InterruptedException {
delegate.connect();
plainConnection.connect();
configureMode(Mode.ASYNC);
startReading();
sslDelegate.connect();
}
@Override
public CompletableFuture<Void> connectAsync() {
return delegate.connectAsync();
// not used currently
throw new InternalError();
}
@Override
boolean connected() {
return delegate.connected();
return plainConnection.connected() && sslDelegate.connected();
}
@Override
@ -85,7 +101,12 @@ class AsyncSSLConnection extends HttpConnection
@Override
SocketChannel channel() {
return delegate.channel();
return plainConnection.channel();
}
@Override
public void enableCallback() {
sslDelegate.enableCallback();
}
@Override
@ -131,22 +152,26 @@ class AsyncSSLConnection extends HttpConnection
@Override
public void closeExceptionally(Throwable cause) {
Utils.close(cause, sslDelegate, delegate.channel());
Utils.close(cause, sslDelegate, plainConnection.channel());
}
@Override
public void close() {
Utils.close(sslDelegate, delegate.channel());
Utils.close(sslDelegate, plainConnection.channel());
}
@Override
void shutdownInput() throws IOException {
delegate.channel().shutdownInput();
plainConnection.channel().shutdownInput();
}
@Override
void shutdownOutput() throws IOException {
delegate.channel().shutdownOutput();
plainConnection.channel().shutdownOutput();
}
SSLEngine getEngine() {
return sslDelegate.getEngine();
}
@Override
@ -154,7 +179,7 @@ class AsyncSSLConnection extends HttpConnection
Consumer<Throwable> errorReceiver,
Supplier<ByteBufferReference> readBufferSupplier) {
sslDelegate.setAsyncCallbacks(asyncReceiver, errorReceiver, readBufferSupplier);
delegate.setAsyncCallbacks(sslDelegate::asyncReceive, errorReceiver, sslDelegate::getNetBuffer);
plainConnection.setAsyncCallbacks(sslDelegate::asyncReceive, errorReceiver, sslDelegate::getNetBuffer);
}
// Blocking read functions not used here
@ -176,7 +201,12 @@ class AsyncSSLConnection extends HttpConnection
@Override
public void startReading() {
delegate.startReading();
plainConnection.startReading();
sslDelegate.startReading();
}
@Override
public void stopAsyncReading() {
plainConnection.stopAsyncReading();
}
}

View File

@ -28,8 +28,10 @@ package jdk.incubator.http;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.Supplier;
@ -72,13 +74,13 @@ import jdk.incubator.http.internal.common.ExceptionallyCloseable;
* channelInputQ
* /\
* ||
* "lowerRead" method puts buffers into channelInputQ. It is invoked from
* "asyncReceive" method puts buffers into channelInputQ. It is invoked from
* OP_READ events from the selector.
*
* Whenever handshaking is required, the doHandshaking() method is called
* which creates a thread to complete the handshake. It takes over the
* channelInputQ from upperRead, and puts outgoing packets on channelOutputQ.
* Selector events are delivered to lowerRead and lowerWrite as normal.
* Selector events are delivered to asyncReceive and lowerWrite as normal.
*
* Errors
*
@ -92,9 +94,6 @@ class AsyncSSLDelegate implements ExceptionallyCloseable, AsyncConnection {
// while SSL handshaking happening.
final AsyncWriteQueue appOutputQ = new AsyncWriteQueue(this::upperWrite);
// queue of wrapped ByteBuffers waiting to be sent on socket channel
//final Queue<ByteBuffer> channelOutputQ;
// Bytes read into this queue before being unwrapped. Backup on this
// Q should only happen when the engine is stalled due to delegated tasks
final Queue<ByteBufferReference> channelInputQ;
@ -107,35 +106,34 @@ class AsyncSSLDelegate implements ExceptionallyCloseable, AsyncConnection {
final SSLEngine engine;
final SSLParameters sslParameters;
//final SocketChannel chan;
final HttpConnection lowerOutput;
final HttpClientImpl client;
// should be volatile to provide proper synchronization(visibility) action
volatile Consumer<ByteBufferReference> asyncReceiver;
volatile Consumer<Throwable> errorHandler;
volatile boolean connected = false;
// Locks.
final Object reader = new Object();
// synchronizing handshake state
final Semaphore handshaker = new Semaphore(1);
// flag set when frame or writer is blocked waiting for handshake to finish
//boolean writerBlocked;
//boolean readerBlocked;
final String[] alpn;
// alpn[] may be null. upcall is callback which receives incoming decoded bytes off socket
AsyncSSLDelegate(HttpConnection lowerOutput, HttpClientImpl client, String[] alpn)
{
SSLContext context = client.sslContext();
//channelOutputQ = new Queue<>();
//channelOutputQ.registerPutCallback(this::lowerWrite);
engine = context.createSSLEngine();
engine.setUseClientMode(true);
SSLParameters sslp = client.sslParameters()
.orElseGet(context::getSupportedSSLParameters);
sslParameters = Utils.copySSLParameters(sslp);
if (alpn != null) {
Log.logSSL("AsyncSSLDelegate: Setting application protocols: " + Arrays.toString(alpn));
sslParameters.setApplicationProtocols(alpn);
} else {
Log.logSSL("AsyncSSLDelegate: no applications set!");
}
logParams(sslParameters);
engine.setSSLParameters(sslParameters);
@ -143,6 +141,7 @@ class AsyncSSLDelegate implements ExceptionallyCloseable, AsyncConnection {
this.client = client;
this.channelInputQ = new Queue<>();
this.channelInputQ.registerPutCallback(this::upperRead);
this.alpn = alpn;
}
@Override
@ -162,6 +161,10 @@ class AsyncSSLDelegate implements ExceptionallyCloseable, AsyncConnection {
}
}
SSLEngine getEngine() {
return engine;
}
@Override
public void closeExceptionally(Throwable t) {
Utils.close(t, appOutputQ, channelInputQ, lowerOutput);
@ -223,6 +226,18 @@ class AsyncSSLDelegate implements ExceptionallyCloseable, AsyncConnection {
}
}
// Connecting at this level means the initial handshake has completed.
// This means that the initial SSL parameters are available including
// ALPN result.
void connect() throws IOException, InterruptedException {
doHandshakeNow("Init");
connected = true;
}
boolean connected() {
return connected;
}
private void startHandshake(String tag) {
Runnable run = () -> {
try {
@ -241,22 +256,28 @@ class AsyncSSLDelegate implements ExceptionallyCloseable, AsyncConnection {
{
handshaker.acquire();
try {
channelInputQ.registerPutCallback(null);
channelInputQ.disableCallback();
lowerOutput.flushAsync();
Log.logTrace("{0}: Starting handshake...", tag);
doHandshakeImpl();
Log.logTrace("{0}: Handshake completed", tag);
channelInputQ.registerPutCallback(this::upperRead);
// don't unblock the channel here, as we aren't sure yet, whether ALPN
// negotiation succeeded. Caller will call enableCallback() externally
} finally {
handshaker.release();
}
}
public void enableCallback() {
channelInputQ.enableCallback();
}
/**
* Executes entire handshake in calling thread.
* Returns after handshake is completed or error occurs
*/
private void doHandshakeImpl() throws IOException {
engine.beginHandshake();
while (true) {
SSLEngineResult.HandshakeStatus status = engine.getHandshakeStatus();
switch(status) {
@ -272,7 +293,9 @@ class AsyncSSLDelegate implements ExceptionallyCloseable, AsyncConnection {
case NEED_UNWRAP: case NEED_UNWRAP_AGAIN:
handshakeReceiveAndUnWrap();
break;
case FINISHED: case NOT_HANDSHAKING:
case FINISHED:
return;
case NOT_HANDSHAKING:
return;
default:
throw new InternalError("Unexpected Handshake Status: "
@ -311,6 +334,12 @@ class AsyncSSLDelegate implements ExceptionallyCloseable, AsyncConnection {
// maybe this class does not need to implement AsyncConnection
}
@Override
public void stopAsyncReading() {
// maybe this class does not need to implement AsyncConnection
}
static class EngineResult {
final SSLEngineResult result;
final ByteBufferReference destBuffer;

View File

@ -111,7 +111,8 @@ final class ConnectionPool {
}
static CacheKey cacheKey(InetSocketAddress destination,
InetSocketAddress proxy) {
InetSocketAddress proxy)
{
return new CacheKey(destination, proxy);
}

View File

@ -549,7 +549,7 @@ final class Exchange<T> {
}
HttpClient.Version version() {
return client.version();
return multi.version();
}
private static SocketPermission getSocketPermissionFor(URI url) {

View File

@ -81,7 +81,17 @@ abstract class ExchangeImpl<T> {
} else {
Http2ClientImpl c2 = exchange.client().client2(); // TODO: improve
HttpRequestImpl request = exchange.request();
Http2Connection c = c2.getConnectionFor(request);
Http2Connection c;
try {
c = c2.getConnectionFor(request);
} catch (Http2Connection.ALPNException e) {
// failed to negotiate "h2"
AsyncSSLConnection as = e.getConnection();
as.stopAsyncReading();
SSLConnection sslc = new SSLConnection(as);
ExchangeImpl<U> ex = new Http1Exchange<>(exchange, sslc);
return ex;
}
if (c == null) {
// no existing connection. Send request with HTTP 1 and then
// upgrade if successful

View File

@ -104,7 +104,15 @@ class Http2ClientImpl {
return connection;
}
// we are opening the connection here blocking until it is done.
connection = new Http2Connection(req, this);
try {
connection = new Http2Connection(req, this);
} catch (Throwable t) {
synchronized (opening) {
opening.remove(key);
opening.notifyAll();
}
throw t;
}
synchronized (opening) {
connections.put(key, connection);
opening.remove(key);

View File

@ -43,6 +43,7 @@ import java.util.Formatter;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
import javax.net.ssl.SSLEngine;
import jdk.incubator.http.internal.common.*;
import jdk.incubator.http.internal.frame.*;
import jdk.incubator.http.internal.hpack.Encoder;
@ -82,8 +83,6 @@ import static jdk.incubator.http.internal.frame.SettingsFrame.*;
* stream are provided by calling Stream.incoming().
*/
class Http2Connection {
/*
* ByteBuffer pooling strategy for HTTP/2 protocol:
*
@ -258,15 +257,46 @@ class Http2Connection {
keyFor(request.uri(), request.proxy(h2client.client())));
Log.logTrace("Connection send window size {0} ", windowController.connectionWindowSize());
connection.connect();
// start reading
AsyncConnection asyncConn = (AsyncConnection)connection;
asyncConn.setAsyncCallbacks(this::asyncReceive, this::shutdown, this::getReadBuffer);
connection.configureMode(Mode.ASYNC); // set mode only AFTER setAsyncCallbacks to provide visibility.
asyncConn.startReading();
connection.connect();
checkSSLConfig();
// safe to resume async reading now.
asyncConn.enableCallback();
sendConnectionPreface();
}
/**
* Throws an IOException if h2 was not negotiated
*/
private void checkSSLConfig() throws IOException {
AsyncSSLConnection aconn = (AsyncSSLConnection)connection;
SSLEngine engine = aconn.getEngine();
String alpn = engine.getApplicationProtocol();
if (alpn == null || !alpn.equals("h2")) {
String msg;
if (alpn == null) {
Log.logSSL("ALPN not supported");
msg = "ALPN not supported";
} else switch (alpn) {
case "":
Log.logSSL("No ALPN returned");
msg = "No ALPN negotiated";
break;
case "http/1.1":
Log.logSSL("HTTP/1.1 ALPN returned");
msg = "HTTP/1.1 ALPN returned";
break;
default:
Log.logSSL("unknown ALPN returned");
msg = "Unexpected ALPN: " + alpn;
throw new IOException(msg);
}
throw new ALPNException(msg, aconn);
}
}
static String keyFor(HttpConnection connection) {
boolean isProxy = connection.isProxied();
boolean isSecure = connection.isSecure();
@ -858,4 +888,21 @@ class Http2Connection {
return 0;
}
}
/**
* Thrown when https handshake negotiates http/1.1 alpn instead of h2
*/
static final class ALPNException extends IOException {
private static final long serialVersionUID = 23138275393635783L;
final AsyncSSLConnection connection;
ALPNException(String msg, AsyncSSLConnection connection) {
super(msg);
this.connection = connection;
}
AsyncSSLConnection getConnection() {
return connection;
}
}
}

View File

@ -154,9 +154,9 @@ public abstract class HttpClient {
/**
* Requests a specific HTTP protocol version where possible. If not set,
* the version defaults to {@link HttpClient.Version#HTTP_1_1}. If
* the version defaults to {@link HttpClient.Version#HTTP_2}. If
* {@link HttpClient.Version#HTTP_2} is set, then each request will
* attempt to upgrade to HTTP/2. If the upgrade succeeds, then the
* attempt to upgrade to HTTP/2. If the upgrade succeeds, then the
* response to this request will use HTTP/2 and all subsequent requests
* and responses to the same
* <a href="https://tools.ietf.org/html/rfc6454#section-4">origin server</a>
@ -267,7 +267,7 @@ public abstract class HttpClient {
/**
* Returns the HTTP protocol version requested for this client. The default
* value is {@link HttpClient.Version#HTTP_1_1}
* value is {@link HttpClient.Version#HTTP_2}
*
* @return the HTTP protocol version requested
*/

View File

@ -40,7 +40,7 @@ class HttpClientBuilderImpl extends HttpClient.Builder {
HttpClient.Redirect followRedirects;
ProxySelector proxy;
Authenticator authenticator;
HttpClient.Version version = HttpClient.Version.HTTP_1_1;
HttpClient.Version version;
Executor executor;
// Security parameters
SSLContext sslContext;

View File

@ -125,7 +125,11 @@ class HttpClientImpl extends HttpClient {
Redirect.NEVER : builder.followRedirects;
this.proxySelector = builder.proxy;
authenticator = builder.authenticator;
version = builder.version;
if (builder.version == null) {
version = HttpClient.Version.HTTP_2;
} else {
version = builder.version;
}
if (builder.sslParams == null) {
sslParams = getDefaultParams(sslContext);
} else {

View File

@ -152,15 +152,16 @@ abstract class HttpConnection implements Closeable {
HttpClientImpl client,
HttpRequestImpl request, boolean isHttp2)
{
HttpConnection c;
HttpConnection c = null;
InetSocketAddress proxy = request.proxy(client);
boolean secure = request.secure();
ConnectionPool pool = client.connectionPool();
String[] alpn = null;
if (secure && client.version() == HttpClient.Version.HTTP_2) {
alpn = new String[1];
if (secure && isHttp2) {
alpn = new String[2];
alpn[0] = "h2";
alpn[1] = "http/1.1";
}
if (!secure) {
@ -171,7 +172,9 @@ abstract class HttpConnection implements Closeable {
return getPlainConnection(addr, proxy, request, client);
}
} else {
c = pool.getConnection(true, addr, proxy);
if (!isHttp2) { // if http2 we don't cache connections
c = pool.getConnection(true, addr, proxy);
}
if (c != null) {
return c;
} else {

View File

@ -303,10 +303,11 @@ public abstract class HttpRequest {
public abstract Builder expectContinue(boolean enable);
/**
* Overrides the {@link HttpClient#version() } setting for this
* request. This sets the version requested. The corresponding
* {@link HttpResponse} should be checked for the version that was
* used.
* Sets the preferred {@link HttpClient.Version} for this
* request. The corresponding {@link HttpResponse} should be checked
* for the version that was used. If the version is not set
* in a request, then the version requested will be that of the
* sending {@link HttpClient}.
*
* @param version the HTTP protocol version requested
* @return this request builder
@ -497,13 +498,16 @@ public abstract class HttpRequest {
public abstract URI uri();
/**
* Returns the HTTP protocol version that will be requested for this
* {@code HttpRequest}. The corresponding {@link HttpResponse} should be
* Returns an {@code Optional} containing the HTTP protocol version that
* will be requested for this {@code HttpRequest}. If the version was not
* set in the request's builder, then the {@code Optional} is empty.
* In that case, the version requested will be that of the sending
* {@link HttpClient}. The corresponding {@link HttpResponse} should be
* queried to determine the version that was actually used.
*
* @return HTTP protocol version
*/
public abstract HttpClient.Version version();
public abstract Optional<HttpClient.Version> version();
/**
* The (user-accessible) request headers that this request was (or will be)

View File

@ -28,6 +28,7 @@ package jdk.incubator.http;
import java.net.URI;
import jdk.incubator.http.HttpRequest.BodyProcessor;
import java.time.Duration;
import java.util.Optional;
import static java.util.Objects.requireNonNull;
import jdk.incubator.http.internal.common.HttpHeadersImpl;
import static jdk.incubator.http.internal.common.Utils.isValidName;
@ -41,7 +42,7 @@ class HttpRequestBuilderImpl extends HttpRequest.Builder {
//private HttpClient.Redirect followRedirects;
private boolean expectContinue;
private HttpRequest.BodyProcessor body;
private HttpClient.Version version;
private volatile Optional<HttpClient.Version> version;
//private final HttpClientImpl client;
//private ProxySelector proxy;
private Duration duration;
@ -52,10 +53,12 @@ class HttpRequestBuilderImpl extends HttpRequest.Builder {
this.uri = uri;
this.userHeaders = new HttpHeadersImpl();
this.method = "GET"; // default, as per spec
this.version = Optional.empty();
}
public HttpRequestBuilderImpl() {
this.userHeaders = new HttpHeadersImpl();
this.version = Optional.empty();
}
@Override
@ -149,7 +152,7 @@ class HttpRequestBuilderImpl extends HttpRequest.Builder {
@Override
public HttpRequestBuilderImpl version(HttpClient.Version version) {
requireNonNull(version);
this.version = version;
this.version = Optional.of(version);
return this;
}
@ -169,7 +172,7 @@ class HttpRequestBuilderImpl extends HttpRequest.Builder {
public HttpRequest.BodyProcessor body() { return body; }
HttpClient.Version version() { return version; }
Optional<HttpClient.Version> version() { return version; }
@Override
public HttpRequest.Builder GET() { return method("GET", null); }

View File

@ -52,7 +52,7 @@ class HttpRequestImpl extends HttpRequest implements WebSocketRequest {
private boolean isWebSocket;
private AccessControlContext acc;
private final Duration duration;
private final HttpClient.Version version;
private final Optional<HttpClient.Version> version;
/**
* Creates an HttpRequestImpl from the given builder.
@ -128,8 +128,8 @@ class HttpRequestImpl extends HttpRequest implements WebSocketRequest {
this.authority = authority;
this.secure = false;
this.expectContinue = false;
this.duration = null; // block TODO: fix
this.version = client.version(); // TODO: ??
this.duration = null;
this.version = Optional.of(client.version());
}
/**
@ -191,12 +191,6 @@ class HttpRequestImpl extends HttpRequest implements WebSocketRequest {
@Override
public boolean expectContinue() { return expectContinue; }
public boolean requestHttp2() {
return version.equals(HttpClient.Version.HTTP_2);
}
// AccessControlContext getAccessControlContext() { return acc; }
InetSocketAddress proxy(HttpClientImpl client) {
ProxySelector ps = client.proxy().orElse(null);
if (ps == null) {
@ -254,7 +248,7 @@ class HttpRequestImpl extends HttpRequest implements WebSocketRequest {
HttpHeadersImpl getSystemHeaders() { return systemHeaders; }
@Override
public HttpClient.Version version() { return version; }
public Optional<HttpClient.Version> version() { return version; }
void addSystemHeader(String name, String value) {
systemHeaders.addHeader(name, value);

View File

@ -192,7 +192,7 @@ class MultiExchange<U,T> {
}
HttpClient.Version version() {
return client.version();
return request.version().orElse(client.version());
}
private synchronized void setExchange(Exchange<T> exchange) {

View File

@ -76,6 +76,11 @@ class PlainHttpConnection extends HttpConnection implements AsyncConnection {
}
}
@Override
public void stopAsyncReading() {
client.cancelRegistration(chan);
}
class ConnectEvent extends AsyncEvent {
CompletableFuture<Void> cf;
@ -213,6 +218,12 @@ class PlainHttpConnection extends HttpConnection implements AsyncConnection {
}
}
@Override
public void enableCallback() {
// not used
assert false;
}
void asyncOutput(ByteBufferReference[] refs, AsyncWriteQueue delayCallback) {
try {
ByteBuffer[] bufs = ByteBufferReference.toBuffers(refs);
@ -246,7 +257,6 @@ class PlainHttpConnection extends HttpConnection implements AsyncConnection {
closed = true;
try {
Log.logError("Closing: " + toString());
//System.out.println("Closing: " + this);
chan.close();
} catch (IOException e) {}
}
@ -272,7 +282,6 @@ class PlainHttpConnection extends HttpConnection implements AsyncConnection {
while (true) {
ByteBufferReference buf = readBufferSupplier.get();
int n = chan.read(buf.get());
//System.err.printf("Read %d bytes from chan\n", n);
if (n == -1) {
throw new IOException();
}

View File

@ -69,6 +69,18 @@ class SSLConnection extends HttpConnection {
delegate = new PlainHttpConnection(addr, client);
}
/**
* Create an SSLConnection from an existing connected AsyncSSLConnection.
* Used when downgrading from HTTP/2 to HTTP/1.1
*/
SSLConnection(AsyncSSLConnection c) {
super(c.address, c.client);
this.delegate = c.plainConnection;
AsyncSSLDelegate adel = c.sslDelegate;
this.sslDelegate = new SSLDelegate(adel.engine, delegate.channel(), client);
this.alpn = adel.alpn;
}
@Override
SSLParameters sslParameters() {
return sslDelegate.getSSLParameters();

View File

@ -51,6 +51,15 @@ class SSLDelegate {
final SocketChannel chan;
final HttpClientImpl client;
SSLDelegate(SSLEngine eng, SocketChannel chan, HttpClientImpl client)
{
this.engine = eng;
this.chan = chan;
this.client = client;
this.wrapper = new EngineWrapper(chan, engine);
this.sslParameters = engine.getSSLParameters();
}
// alpn[] may be null
SSLDelegate(SocketChannel chan, HttpClientImpl client, String[] alpn)
throws IOException
@ -63,9 +72,9 @@ class SSLDelegate {
sslParameters = Utils.copySSLParameters(sslp);
if (alpn != null) {
sslParameters.setApplicationProtocols(alpn);
Log.logSSL(() -> "Setting application protocols: " + Arrays.toString(alpn));
Log.logSSL("SSLDelegate: Setting application protocols: {0}" + Arrays.toString(alpn));
} else {
Log.logSSL("No application protocols proposed");
Log.logSSL("SSLDelegate: No application protocols proposed");
}
engine.setSSLParameters(sslParameters);
wrapper = new EngineWrapper(chan, engine);
@ -181,7 +190,7 @@ class SSLDelegate {
boolean closed = false;
int u_remaining; // the number of bytes left in unwrap_src after an unwrap()
EngineWrapper (SocketChannel chan, SSLEngine engine) throws IOException {
EngineWrapper (SocketChannel chan, SSLEngine engine) {
this.chan = chan;
this.engine = engine;
wrapLock = new Object();

View File

@ -28,6 +28,7 @@ package jdk.incubator.http.internal.common;
import java.io.IOException;
import java.util.LinkedList;
import java.util.stream.Stream;
import java.util.Objects;
// Each stream has one of these for input. Each Http2Connection has one
// for output. Can be used blocking or asynchronously.
@ -38,33 +39,9 @@ public class Queue<T> implements ExceptionallyCloseable {
private volatile boolean closed = false;
private volatile Throwable exception = null;
private Runnable callback;
private boolean forceCallback;
private boolean callbackDisabled = false;
private int waiters; // true if someone waiting
public synchronized void putAll(T[] objs) throws IOException {
if (closed) {
throw new IOException("stream closed");
}
boolean wasEmpty = q.isEmpty();
for (T obj : objs) {
q.add(obj);
}
if (waiters > 0) {
notifyAll();
}
if (wasEmpty || forceCallback) {
forceCallback = false;
if (callback != null) {
// Note: calling callback while holding the lock is
// dangerous and may lead to deadlocks.
callback.run();
}
}
}
public synchronized int size() {
return q.size();
}
@ -81,17 +58,30 @@ public class Queue<T> implements ExceptionallyCloseable {
}
q.add(obj);
if (waiters > 0) {
notifyAll();
}
if (q.size() == 1 || forceCallback) {
forceCallback = false;
if (callback != null) {
// Note: calling callback while holding the lock is
// dangerous and may lead to deadlocks.
callback.run();
}
if (callbackDisabled) {
return;
}
if (q.size() > 0 && callback != null) {
// Note: calling callback while holding the lock is
// dangerous and may lead to deadlocks.
callback.run();
}
}
public synchronized void disableCallback() {
callbackDisabled = true;
}
public synchronized void enableCallback() {
callbackDisabled = false;
while (q.size() > 0) {
callback.run();
}
}
@ -100,8 +90,9 @@ public class Queue<T> implements ExceptionallyCloseable {
* the Queue was empty.
*/
public synchronized void registerPutCallback(Runnable callback) {
Objects.requireNonNull(callback);
this.callback = callback;
if (callback != null && q.size() > 0) {
if (q.size() > 0) {
// Note: calling callback while holding the lock is
// dangerous and may lead to deadlocks.
callback.run();
@ -167,12 +158,10 @@ public class Queue<T> implements ExceptionallyCloseable {
}
public synchronized void pushback(T v) {
forceCallback = true;
q.addFirst(v);
}
public synchronized void pushbackAll(T[] v) {
forceCallback = true;
for (int i=v.length-1; i>=0; i--) {
q.addFirst(v[i]);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2017, 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
@ -201,7 +201,7 @@ import static sun.security.util.ResourcesMgr.getAuthResourceString;
*
* <p>
* Arbitrary
* <a href="{@docRoot}/../../../../../technotes/guides/jndi/jndi-ldap-gl.html#PROP">JNDI properties</a>
* {@extLink jndi_ldap_gl_prop "JNDI properties"}
* may also be specified in the {@link Configuration}.
* They are added to the environment and passed to the LDAP provider.
* Note that the following four JNDI properties are set by this module directly

View File

@ -104,6 +104,7 @@ public class RequestBodyTest {
SSLContext ctx = LightWeightHttpServer.ctx;
client = HttpClient.newBuilder()
.sslContext(ctx)
.version(HttpClient.Version.HTTP_1_1)
.followRedirects(HttpClient.Redirect.ALWAYS)
.executor(exec)
.build();

View File

@ -165,6 +165,7 @@ public class SmokeTest {
client = HttpClient.newBuilder()
.sslContext(ctx)
.executor(e)
.version(HttpClient.Version.HTTP_1_1)
.sslParameters(sslparams)
.followRedirects(HttpClient.Redirect.ALWAYS)
.build();

View File

@ -0,0 +1,140 @@
/*
* Copyright (c) 2017, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8175814
* @modules jdk.incubator.httpclient java.logging jdk.httpserver
* @run main/othervm -Djdk.httpclient.HttpClient.log=errors,requests,headers,trace VersionTest
*/
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.net.InetSocketAddress;
import jdk.incubator.http.HttpClient;
import jdk.incubator.http.HttpRequest;
import jdk.incubator.http.HttpResponse;
import static jdk.incubator.http.HttpRequest.BodyProcessor.fromString;
import static jdk.incubator.http.HttpResponse.*;
import static jdk.incubator.http.HttpResponse.BodyHandler.asString;
import static jdk.incubator.http.HttpResponse.BodyHandler.discard;
import static jdk.incubator.http.HttpClient.Version.HTTP_1_1;
import static jdk.incubator.http.HttpClient.Version.HTTP_2;
/**
*/
public class VersionTest {
static HttpServer s1 ;
static ExecutorService executor;
static int port;
static HttpClient client;
static URI uri;
static volatile boolean error = false;
public static void main(String[] args) throws Exception {
initServer();
client = HttpClient.newBuilder()
.executor(executor)
.build();
// first check that the version is HTTP/2
if (client.version() != HttpClient.Version.HTTP_2) {
throw new RuntimeException("Default version not HTTP_2");
}
try {
test(HTTP_1_1);
test(HTTP_2);
} finally {
s1.stop(0);
executor.shutdownNow();
}
if (error)
throw new RuntimeException();
}
public static void test(HttpClient.Version version) throws Exception {
HttpRequest r = HttpRequest.newBuilder(uri)
.version(version)
.GET()
.build();
HttpResponse<Void> resp = client.send(r, discard(null));
System.out.printf("Client: response is %d\n", resp.statusCode());
if (resp.version() != HTTP_1_1) {
throw new RuntimeException();
}
//System.out.printf("Client: response body is %s\n", resp.body());
}
static void initServer() throws Exception {
InetSocketAddress addr = new InetSocketAddress (0);
s1 = HttpServer.create (addr, 0);
HttpHandler h = new Handler();
HttpContext c1 = s1.createContext("/", h);
executor = Executors.newCachedThreadPool();
s1.setExecutor(executor);
s1.start();
port = s1.getAddress().getPort();
uri = new URI("http://127.0.0.1:" + Integer.toString(port) + "/foo");
System.out.println("HTTP server port = " + port);
}
}
class Handler implements HttpHandler {
int counter = 0;
void checkHeader(Headers h) {
counter++;
if (counter == 1 && h.containsKey("Upgrade")) {
VersionTest.error = true;
}
if (counter > 1 && !h.containsKey("Upgrade")) {
VersionTest.error = true;
}
}
@Override
public synchronized void handle(HttpExchange t)
throws IOException
{
String reply = "Hello world";
int len = reply.length();
Headers h = t.getRequestHeaders();
checkHeader(h);
System.out.printf("Sending response 200\n");
t.sendResponseHeaders(200, len);
OutputStream o = t.getResponseBody();
o.write(reply.getBytes());
t.close();
}
}

View File

@ -31,7 +31,7 @@
* jdk.incubator.httpclient/jdk.incubator.http.internal.frame
* jdk.incubator.httpclient/jdk.incubator.http.internal.hpack
* java.security.jgss
* @run testng/othervm -Djdk.httpclient.HttpClient.log=ssl,errors ErrorTest
* @run testng/othervm/timeout=60 -Djavax.net.debug=ssl -Djdk.httpclient.HttpClient.log=all ErrorTest
* @summary check exception thrown when bad TLS parameters selected
*/
@ -76,10 +76,13 @@ public class ErrorTest {
Http2TestServer httpsServer = null;
try {
SSLContext serverContext = (new SimpleSSLContext()).get();
SSLParameters p = serverContext.getSupportedSSLParameters();
p.setApplicationProtocols(new String[]{"h2"});
httpsServer = new Http2TestServer(true,
0,
exec,
sslContext);
serverContext);
httpsServer.addHandler(new EchoHandler(), "/");
int httpsPort = httpsServer.getAddress().getPort();
String httpsURIString = "https://127.0.0.1:" + httpsPort + "/bar/";

View File

@ -32,6 +32,7 @@ import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.CompletionException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import static jdk.incubator.http.HttpRequest.BodyProcessor.fromString;
@ -75,6 +76,9 @@ public class Timeout {
Thread server = new Thread(() -> {
while (true) {
System.out.println("server: ready");
SSLParameters params = ssocket.getSSLParameters();
params.setApplicationProtocols(new String[]{"h2"});
ssocket.setSSLParameters(params);
ready = true;
try (SSLSocket socket = (SSLSocket) ssocket.accept()) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2017, 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
@ -33,6 +33,7 @@ import java.util.List;
import java.util.Scanner;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import java.util.stream.LambdaTestHelpers;
@ -44,7 +45,7 @@ import static org.testng.Assert.*;
/**
* @test
* @bug 8072722
* @bug 8072722 8150488
* @summary Tests of stream support in java.util.Scanner
* @library ../stream/bootlib
* @build java.base/java.util.stream.OpTestCase
@ -56,19 +57,22 @@ public class ScannerStreamTest extends OpTestCase {
static File inputFile = new File(System.getProperty("test.src", "."), "input.txt");
@DataProvider(name = "Patterns")
public static Object[][] makeStreamTestData() {
@DataProvider(name = "Tokens")
public static Object[][] makeTokensTestData() {
// each inner array is [String description, String input, String delimiter]
// delimiter may be null
List<Object[]> data = new ArrayList<>();
data.add(new Object[] { "default delimiter", "abc def ghi", null });
data.add(new Object[] { "fixed delimiter", "abc,def,,ghi", "," });
data.add(new Object[] { "regexp delimiter", "###abc##def###ghi###j", "#+" });
data.add(new Object[] { "regex delimiter", "###abc##def###ghi###j", "#+" });
return data.toArray(new Object[0][]);
}
/*
* Creates a scanner over the input, applying a delimiter if non-null.
*/
Scanner makeScanner(String input, String delimiter) {
Scanner sc = new Scanner(input);
if (delimiter != null) {
@ -77,7 +81,11 @@ public class ScannerStreamTest extends OpTestCase {
return sc;
}
@Test(dataProvider = "Patterns")
/*
* Given input and a delimiter, tests that tokens() returns the same
* results that would be provided by a Scanner hasNext/next loop.
*/
@Test(dataProvider = "Tokens")
public void tokensTest(String description, String input, String delimiter) {
// derive expected result by using conventional loop
Scanner sc = makeScanner(input, delimiter);
@ -93,6 +101,9 @@ public class ScannerStreamTest extends OpTestCase {
.exercise();
}
/*
* Creates a Scanner over the given input file.
*/
Scanner makeFileScanner(File file) {
try {
return new Scanner(file, "UTF-8");
@ -101,7 +112,12 @@ public class ScannerStreamTest extends OpTestCase {
}
}
public void findAllTest() {
/*
* Tests that the matches produced by findAll(pat) are the same
* as what are returned by findWithinHorizon(pat, 0). This tests
* a single pattern against a single input file.
*/
public void findAllFileTest() {
// derive expected result by using conventional loop
Pattern pat = Pattern.compile("[A-Z]{7,}");
List<String> expected = new ArrayList<>();
@ -116,10 +132,66 @@ public class ScannerStreamTest extends OpTestCase {
Supplier<Stream<String>> ss =
() -> makeFileScanner(inputFile).findAll(pat).map(MatchResult::group);
withData(TestData.Factory.ofSupplier("findAllTest", ss))
withData(TestData.Factory.ofSupplier("findAllFileTest", ss))
.stream(LambdaTestHelpers.identity())
.expectedResult(expected)
.exercise();
}
@DataProvider(name = "FindAllZero")
public static Object[][] makeFindAllZeroTestData() {
// each inner array is [String input, String patternString]
List<Object[]> data = new ArrayList<>();
data.add(new Object[] { "aaaaa", "a*" });
data.add(new Object[] { "aaaaab", "a*" });
data.add(new Object[] { "aaaaabb", "a*" });
data.add(new Object[] { "aaaaabbb", "a*" });
data.add(new Object[] { "aaabbaaaa", "a*" });
data.add(new Object[] { "aaabbaaaab", "a*" });
data.add(new Object[] { "aaabbaaaabb", "a*" });
data.add(new Object[] { "aaabbaaaabbb", "a*" });
data.add(new Object[] { "aaabbaaaa", "a*|b*" });
data.add(new Object[] { "aaabbaaaab", "a*|b*" });
data.add(new Object[] { "aaabbaaaabb", "a*|b*" });
data.add(new Object[] { "aaabbaaaabbb", "a*|b*" });
return data.toArray(new Object[0][]);
}
/*
* Tests findAll() using a pattern against an input string.
* The results from findAll() should equal the results obtained
* using a loop around Matcher.find().
*
* The provided regexes should allow zero-length matches.
* This primarily tests the auto-advance feature of findAll() that
* occurs if the regex match is of zero length to see if it has the
* same behavior as Matcher.find()'s auto-advance (JDK-8150488).
* Without auto-advance, findAll() would return an infinite stream
* of zero-length matches. Apply a limit to the stream so
* that an infinite stream will be truncated. The limit must be
* high enough that the resulting truncated stream won't be
* mistaken for a correct expected result.
*/
@Test(dataProvider = "FindAllZero")
public void findAllZeroTest(String input, String patternString) {
Pattern pattern = Pattern.compile(patternString);
// generate expected result using Matcher.find()
Matcher m = pattern.matcher(input);
List<String> expected = new ArrayList<>();
while (m.find()) {
expected.add(m.group());
}
Supplier<Stream<String>> ss = () -> new Scanner(input).findAll(pattern)
.limit(100)
.map(MatchResult::group);
withData(TestData.Factory.ofSupplier("findAllZeroTest", ss))
.stream(LambdaTestHelpers.identity())
.expectedResult(expected)
.exercise();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -26,6 +26,7 @@
* @bug 8170859
* @summary Basic test for incubator modules in jmods and images
* @library /lib/testlibrary
* @key intermittent
* @modules jdk.compiler jdk.jartool jdk.jlink
* @build CompilerUtils
* @run testng/othervm ImageModules

View File

@ -195,15 +195,19 @@ public class VerifyJimage {
.replaceAll("\\.class$", "").replace('/', '.');
}
private static Set<String> DEPLOY_MODULES =
Set.of("javafx.deploy", "jdk.deploy", "jdk.plugin", "jdk.javaws");
private static Set<String> EXCLUDED_MODULES =
Set.of("javafx.deploy", "jdk.deploy", "jdk.plugin", "jdk.javaws",
// All JVMCI packages other than jdk.vm.ci.services are dynamically
// exported to jdk.internal.vm.compiler and jdk.aot
"jdk.internal.vm.compiler", "jdk.aot"
);
private boolean accept(String entry) {
int index = entry.indexOf('/', 1);
String mn = index > 1 ? entry.substring(1, index) : "";
// filter deployment modules
if (mn.isEmpty() || DEPLOY_MODULES.contains(mn)) {
if (mn.isEmpty() || EXCLUDED_MODULES.contains(mn)) {
return false;
}
return entry.endsWith(".class") && !entry.endsWith(MODULE_INFO);