Merge
This commit is contained in:
commit
83a51d869e
1
.hgtags
1
.hgtags
@ -499,6 +499,7 @@ e1b3def126240d5433902f3cb0e91a4c27f6db50 jdk-11+18
|
||||
1edcf36fe15f79d6228d1a63eb680878e2386480 jdk-11+23
|
||||
ea900a7dc7d77dee30865c60eabd87fc24b1037c jdk-11+24
|
||||
331888ea4a788df801b1edf8836646cd25fc758b jdk-11+25
|
||||
945ba9278a272a5477ffb1b3ea1b04174fed8036 jdk-11+26
|
||||
69b438908512d3dfef5852c6a843a5778333a309 jdk-12+2
|
||||
990db216e7199b2ba9989d8fa20b657e0ca7d969 jdk-12+3
|
||||
499b873761d8e8a1cc4aa649daf04cbe98cbce77 jdk-12+4
|
||||
|
@ -1094,7 +1094,7 @@ int NetworkPerformanceInterface::NetworkPerformance::network_utilization(Network
|
||||
|
||||
NetworkInterface* ret = NULL;
|
||||
for (cur_address = addresses; cur_address != NULL; cur_address = cur_address->ifa_next) {
|
||||
if (cur_address->ifa_addr->sa_family != AF_PACKET) {
|
||||
if ((cur_address->ifa_addr == NULL) || (cur_address->ifa_addr->sa_family != AF_PACKET)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1105,6 +1105,7 @@ int NetworkPerformanceInterface::NetworkPerformance::network_utilization(Network
|
||||
ret = cur;
|
||||
}
|
||||
|
||||
freeifaddrs(addresses);
|
||||
*network_interfaces = ret;
|
||||
|
||||
return OS_OK;
|
||||
|
@ -808,6 +808,7 @@ int NetworkPerformanceInterface::NetworkPerformance::network_utilization(Network
|
||||
}
|
||||
}
|
||||
|
||||
kstat_close(ctl);
|
||||
*network_interfaces = ret;
|
||||
|
||||
return OS_OK;
|
||||
|
@ -497,6 +497,7 @@ class ComputeLinearScanOrder : public StackObj {
|
||||
// computation of final block order
|
||||
BlockBegin* common_dominator(BlockBegin* a, BlockBegin* b);
|
||||
void compute_dominator(BlockBegin* cur, BlockBegin* parent);
|
||||
void compute_dominator_impl(BlockBegin* cur, BlockBegin* parent);
|
||||
int compute_weight(BlockBegin* cur);
|
||||
bool ready_for_processing(BlockBegin* cur);
|
||||
void sort_into_work_list(BlockBegin* b);
|
||||
@ -770,6 +771,14 @@ BlockBegin* ComputeLinearScanOrder::common_dominator(BlockBegin* a, BlockBegin*
|
||||
}
|
||||
|
||||
void ComputeLinearScanOrder::compute_dominator(BlockBegin* cur, BlockBegin* parent) {
|
||||
init_visited();
|
||||
compute_dominator_impl(cur, parent);
|
||||
}
|
||||
|
||||
void ComputeLinearScanOrder::compute_dominator_impl(BlockBegin* cur, BlockBegin* parent) {
|
||||
// Mark as visited to avoid recursive calls with same parent
|
||||
set_visited(cur);
|
||||
|
||||
if (cur->dominator() == NULL) {
|
||||
TRACE_LINEAR_SCAN(4, tty->print_cr("DOM: initializing dominator of B%d to B%d", cur->block_id(), parent->block_id()));
|
||||
cur->set_dominator(parent);
|
||||
@ -788,7 +797,9 @@ void ComputeLinearScanOrder::compute_dominator(BlockBegin* cur, BlockBegin* pare
|
||||
int num_cur_xhandler = cur->number_of_exception_handlers();
|
||||
for (int j = 0; j < num_cur_xhandler; j++) {
|
||||
BlockBegin* xhandler = cur->exception_handler_at(j);
|
||||
compute_dominator(xhandler, parent);
|
||||
if (!is_visited(xhandler)) {
|
||||
compute_dominator_impl(xhandler, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1070,6 +1070,11 @@ jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep
|
||||
# case-insensitive. Leading and trailing whitespaces, surrounding each value,
|
||||
# are ignored. Unknown values are ignored.
|
||||
#
|
||||
# NOTE: Use caution before setting this property. Setting this property
|
||||
# exposes sensitive information in Exceptions, which could, for example,
|
||||
# propagate to untrusted code or be emitted in stack traces that are
|
||||
# inadvertently disclosed and made accessible over a public network.
|
||||
#
|
||||
# The categories are:
|
||||
#
|
||||
# hostInfo - IOExceptions thrown by java.net.Socket and the socket types in the
|
||||
|
@ -42,7 +42,6 @@ import java.io.FilePermission;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Objects;
|
||||
@ -85,10 +84,6 @@ import sun.security.util.SecurityConstants;
|
||||
* application is executed, it will be executed on the same system as
|
||||
* the one on which the Java application was launched.
|
||||
*
|
||||
* <p> Note: the methods in the {@code Desktop} class may require
|
||||
* platform-dependent permissions in addition to those described in the
|
||||
* specification.
|
||||
*
|
||||
* @see Action
|
||||
*
|
||||
* @since 1.6
|
||||
@ -389,11 +384,12 @@ public class Desktop {
|
||||
|
||||
|
||||
/**
|
||||
* Calls to the security manager's {@code checkPermission} method with
|
||||
* an {@code AWTPermission("showWindowWithoutWarningBanner")}
|
||||
* permission.
|
||||
* Calls to the security manager's {@code checkPermission} method with an
|
||||
* {@code AWTPermission("showWindowWithoutWarningBanner")} permission. This
|
||||
* permission is needed, because we cannot add a security warning icon to
|
||||
* the windows of the external native application.
|
||||
*/
|
||||
private void checkAWTPermission(){
|
||||
private void checkAWTPermission() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new AWTPermission(
|
||||
@ -938,7 +934,11 @@ public class Desktop {
|
||||
* and registered in the Info.plist with CFBundleHelpBookFolder
|
||||
*
|
||||
* @throws SecurityException if a security manager exists and it denies the
|
||||
* {@code RuntimePermission("canProcessApplicationEvents")} permission.
|
||||
* {@code RuntimePermission("canProcessApplicationEvents")}
|
||||
* permission, or it denies the
|
||||
* {@code AWTPermission("showWindowWithoutWarningBanner")}
|
||||
* permission, or the calling thread is not allowed to create a
|
||||
* subprocess
|
||||
* @throws UnsupportedOperationException if the current platform
|
||||
* does not support the {@link Desktop.Action#APP_HELP_VIEWER} action
|
||||
* @since 9
|
||||
@ -982,12 +982,15 @@ public class Desktop {
|
||||
* @param file the file
|
||||
* @throws SecurityException If a security manager exists and its
|
||||
* {@link SecurityManager#checkRead(java.lang.String)} method
|
||||
* denies read access to the file
|
||||
* denies read access to the file or to its parent, or it denies the
|
||||
* {@code AWTPermission("showWindowWithoutWarningBanner")}
|
||||
* permission, or the calling thread is not allowed to create a
|
||||
* subprocess
|
||||
* @throws UnsupportedOperationException if the current platform
|
||||
* does not support the {@link Desktop.Action#BROWSE_FILE_DIR} action
|
||||
* @throws NullPointerException if {@code file} is {@code null}
|
||||
* @throws IllegalArgumentException if the specified file doesn't
|
||||
* exist
|
||||
* @throws IllegalArgumentException if the specified file or its parent
|
||||
* doesn't exist
|
||||
* @since 9
|
||||
*/
|
||||
public void browseFileDirectory(File file) {
|
||||
@ -1014,8 +1017,7 @@ public class Desktop {
|
||||
* @throws UnsupportedOperationException if the current platform
|
||||
* does not support the {@link Desktop.Action#MOVE_TO_TRASH} action
|
||||
* @throws NullPointerException if {@code file} is {@code null}
|
||||
* @throws IllegalArgumentException if the specified file doesn't
|
||||
* exist
|
||||
* @throws IllegalArgumentException if the specified file doesn't exist
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
|
@ -34,6 +34,7 @@ import java.net.ProxySelector;
|
||||
import java.net.URLPermission;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
@ -84,6 +85,7 @@ import jdk.internal.net.http.HttpClientBuilderImpl;
|
||||
* <pre>{@code HttpClient client = HttpClient.newBuilder()
|
||||
* .version(Version.HTTP_1_1)
|
||||
* .followRedirects(Redirect.NORMAL)
|
||||
* .connectTimeout(Duration.ofSeconds(20))
|
||||
* .proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
|
||||
* .authenticator(Authenticator.getDefault())
|
||||
* .build();
|
||||
@ -94,7 +96,7 @@ import jdk.internal.net.http.HttpClientBuilderImpl;
|
||||
* <p><b>Asynchronous Example</b>
|
||||
* <pre>{@code HttpRequest request = HttpRequest.newBuilder()
|
||||
* .uri(URI.create("https://foo.com/"))
|
||||
* .timeout(Duration.ofMinutes(1))
|
||||
* .timeout(Duration.ofMinutes(2))
|
||||
* .header("Content-Type", "application/json")
|
||||
* .POST(BodyPublishers.ofFile(Paths.get("file.json")))
|
||||
* .build();
|
||||
@ -196,6 +198,26 @@ public abstract class HttpClient {
|
||||
*/
|
||||
public Builder cookieHandler(CookieHandler cookieHandler);
|
||||
|
||||
/**
|
||||
* Sets the connect timeout duration for this client.
|
||||
*
|
||||
* <p> In the case where a new connection needs to be established, if
|
||||
* the connection cannot be established within the given {@code
|
||||
* duration}, then {@link HttpClient#send(HttpRequest,BodyHandler)
|
||||
* HttpClient::send} throws an {@link HttpConnectTimeoutException}, or
|
||||
* {@link HttpClient#sendAsync(HttpRequest,BodyHandler)
|
||||
* HttpClient::sendAsync} completes exceptionally with an
|
||||
* {@code HttpConnectTimeoutException}. If a new connection does not
|
||||
* need to be established, for example if a connection can be reused
|
||||
* from a previous request, then this timeout duration has no effect.
|
||||
*
|
||||
* @param duration the duration to allow the underlying connection to be
|
||||
* established
|
||||
* @return this builder
|
||||
* @throws IllegalArgumentException if the duration is non-positive
|
||||
*/
|
||||
public Builder connectTimeout(Duration duration);
|
||||
|
||||
/**
|
||||
* Sets an {@code SSLContext}.
|
||||
*
|
||||
@ -344,6 +366,17 @@ public abstract class HttpClient {
|
||||
*/
|
||||
public abstract Optional<CookieHandler> cookieHandler();
|
||||
|
||||
/**
|
||||
* Returns an {@code Optional} containing the <i>connect timeout duration</i>
|
||||
* for this client. If the {@linkplain Builder#connectTimeout(Duration)
|
||||
* connect timeout duration} was not set in the client's builder, then the
|
||||
* {@code Optional} is empty.
|
||||
*
|
||||
* @return an {@code Optional} containing this client's connect timeout
|
||||
* duration
|
||||
*/
|
||||
public abstract Optional<Duration> connectTimeout();
|
||||
|
||||
/**
|
||||
* Returns the follow redirects policy for this client. The default value
|
||||
* for client's built by builders that do not specify a redirect policy is
|
||||
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package java.net.http;
|
||||
|
||||
/**
|
||||
* Thrown when a connection, over which an {@code HttpRequest} is intended to be
|
||||
* sent, is not successfully established within a specified time period.
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public class HttpConnectTimeoutException extends HttpTimeoutException {
|
||||
|
||||
private static final long serialVersionUID = 321L + 11L;
|
||||
|
||||
/**
|
||||
* Constructs an {@code HttpConnectTimeoutException} with the given detail
|
||||
* message.
|
||||
*
|
||||
* @param message
|
||||
* The detail message; can be {@code null}
|
||||
*/
|
||||
public HttpConnectTimeoutException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -80,11 +80,9 @@ abstract class AbstractAsyncSSLConnection extends HttpConnection
|
||||
engine = createEngine(context, serverName.getName(), port, sslParameters);
|
||||
}
|
||||
|
||||
abstract HttpConnection plainConnection();
|
||||
abstract SSLTube getConnectionFlow();
|
||||
|
||||
final CompletableFuture<String> getALPN() {
|
||||
assert connected();
|
||||
return getConnectionFlow().getALPN();
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,8 @@ package jdk.internal.net.http;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
import jdk.internal.net.http.common.MinimalFuture;
|
||||
import jdk.internal.net.http.common.SSLTube;
|
||||
import jdk.internal.net.http.common.Utils;
|
||||
|
||||
@ -49,14 +51,9 @@ class AsyncSSLConnection extends AbstractAsyncSSLConnection {
|
||||
}
|
||||
|
||||
@Override
|
||||
PlainHttpConnection plainConnection() {
|
||||
return plainConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> connectAsync() {
|
||||
public CompletableFuture<Void> connectAsync(Exchange<?> exchange) {
|
||||
return plainConnection
|
||||
.connectAsync()
|
||||
.connectAsync(exchange)
|
||||
.thenApply( unused -> {
|
||||
// create the SSLTube wrapping the SocketTube, with the given engine
|
||||
flow = new SSLTube(engine,
|
||||
@ -66,6 +63,21 @@ class AsyncSSLConnection extends AbstractAsyncSSLConnection {
|
||||
return null; } );
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> finishConnect() {
|
||||
// The actual ALPN value, which may be the empty string, is not
|
||||
// interesting at this point, only that the handshake has completed.
|
||||
return getALPN()
|
||||
.handle((String unused, Throwable ex) -> {
|
||||
if (ex == null) {
|
||||
return plainConnection.finishConnect();
|
||||
} else {
|
||||
plainConnection.close();
|
||||
return MinimalFuture.<Void>failedFuture(ex);
|
||||
} })
|
||||
.thenCompose(Function.identity());
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean connected() {
|
||||
return plainConnection.connected();
|
||||
|
@ -29,6 +29,8 @@ import java.net.InetSocketAddress;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.net.http.HttpHeaders;
|
||||
import java.util.function.Function;
|
||||
import jdk.internal.net.http.common.MinimalFuture;
|
||||
import jdk.internal.net.http.common.SSLTube;
|
||||
import jdk.internal.net.http.common.Utils;
|
||||
|
||||
@ -53,13 +55,13 @@ class AsyncSSLTunnelConnection extends AbstractAsyncSSLConnection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> connectAsync() {
|
||||
public CompletableFuture<Void> connectAsync(Exchange<?> exchange) {
|
||||
if (debug.on()) debug.log("Connecting plain tunnel connection");
|
||||
// This will connect the PlainHttpConnection flow, so that
|
||||
// its HttpSubscriber and HttpPublisher are subscribed to the
|
||||
// SocketTube
|
||||
return plainConnection
|
||||
.connectAsync()
|
||||
.connectAsync(exchange)
|
||||
.thenApply( unused -> {
|
||||
if (debug.on()) debug.log("creating SSLTube");
|
||||
// create the SSLTube wrapping the SocketTube, with the given engine
|
||||
@ -70,6 +72,21 @@ class AsyncSSLTunnelConnection extends AbstractAsyncSSLConnection {
|
||||
return null;} );
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> finishConnect() {
|
||||
// The actual ALPN value, which may be the empty string, is not
|
||||
// interesting at this point, only that the handshake has completed.
|
||||
return getALPN()
|
||||
.handle((String unused, Throwable ex) -> {
|
||||
if (ex == null) {
|
||||
return plainConnection.finishConnect();
|
||||
} else {
|
||||
plainConnection.close();
|
||||
return MinimalFuture.<Void>failedFuture(ex);
|
||||
} })
|
||||
.thenCompose(Function.identity());
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isTunnel() { return true; }
|
||||
|
||||
@ -86,11 +103,6 @@ class AsyncSSLTunnelConnection extends AbstractAsyncSSLConnection {
|
||||
return "AsyncSSLTunnelConnection: " + super.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
PlainTunnelingConnection plainConnection() {
|
||||
return plainConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
ConnectionPool.CacheKey cacheKey() {
|
||||
return ConnectionPool.cacheKey(address, plainConnection.proxyAddr);
|
||||
|
@ -83,6 +83,10 @@ final class Exchange<T> {
|
||||
final PushGroup<T> pushGroup;
|
||||
final String dbgTag;
|
||||
|
||||
// Keeps track of the underlying connection when establishing an HTTP/2
|
||||
// exchange so that it can be aborted/timed out mid setup.
|
||||
final ConnectionAborter connectionAborter = new ConnectionAborter();
|
||||
|
||||
Exchange(HttpRequestImpl request, MultiExchange<T> multi) {
|
||||
this.request = request;
|
||||
this.upgrading = false;
|
||||
@ -125,6 +129,27 @@ final class Exchange<T> {
|
||||
return client;
|
||||
}
|
||||
|
||||
// Keeps track of the underlying connection when establishing an HTTP/2
|
||||
// exchange so that it can be aborted/timed out mid setup.
|
||||
static final class ConnectionAborter {
|
||||
private volatile HttpConnection connection;
|
||||
|
||||
void connection(HttpConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
void closeConnection() {
|
||||
HttpConnection connection = this.connection;
|
||||
this.connection = null;
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (Throwable t) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<T> readBodyAsync(HttpResponse.BodyHandler<T> handler) {
|
||||
// If we received a 407 while establishing the exchange
|
||||
@ -179,6 +204,7 @@ final class Exchange<T> {
|
||||
}
|
||||
|
||||
public void cancel(IOException cause) {
|
||||
if (debug.on()) debug.log("cancel exchImpl: %s, with \"%s\"", exchImpl, cause);
|
||||
// If the impl is non null, propagate the exception right away.
|
||||
// Otherwise record it so that it can be propagated once the
|
||||
// exchange impl has been established.
|
||||
@ -190,6 +216,11 @@ final class Exchange<T> {
|
||||
} else {
|
||||
// no impl yet. record the exception
|
||||
failed = cause;
|
||||
|
||||
// abort/close the connection if setting up the exchange. This can
|
||||
// be important when setting up HTTP/2
|
||||
connectionAborter.closeConnection();
|
||||
|
||||
// now call checkCancelled to recheck the impl.
|
||||
// if the failed state is set and the impl is not null, reset
|
||||
// the failed state and propagate the exception to the impl.
|
||||
|
@ -85,7 +85,7 @@ abstract class ExchangeImpl<T> {
|
||||
} else {
|
||||
Http2ClientImpl c2 = exchange.client().client2(); // #### improve
|
||||
HttpRequestImpl request = exchange.request();
|
||||
CompletableFuture<Http2Connection> c2f = c2.getConnectionFor(request);
|
||||
CompletableFuture<Http2Connection> c2f = c2.getConnectionFor(request, exchange);
|
||||
if (debug.on())
|
||||
debug.log("get: Trying to get HTTP/2 connection");
|
||||
return c2f.handle((h2c, t) -> createExchangeImpl(h2c, t, exchange, connection))
|
||||
|
@ -233,7 +233,8 @@ class Http1Exchange<T> extends ExchangeImpl<T> {
|
||||
CompletableFuture<Void> connectCF;
|
||||
if (!connection.connected()) {
|
||||
if (debug.on()) debug.log("initiating connect async");
|
||||
connectCF = connection.connectAsync();
|
||||
connectCF = connection.connectAsync(exchange)
|
||||
.thenCompose(unused -> connection.finishConnect());
|
||||
Throwable cancelled;
|
||||
synchronized (lock) {
|
||||
if ((cancelled = failed) == null) {
|
||||
|
@ -90,7 +90,8 @@ class Http2ClientImpl {
|
||||
* 3. completes normally with null: no connection in cache for h2c or h2 failed previously
|
||||
* 4. completes normally with connection: h2 or h2c connection in cache. Use it.
|
||||
*/
|
||||
CompletableFuture<Http2Connection> getConnectionFor(HttpRequestImpl req) {
|
||||
CompletableFuture<Http2Connection> getConnectionFor(HttpRequestImpl req,
|
||||
Exchange<?> exchange) {
|
||||
URI uri = req.uri();
|
||||
InetSocketAddress proxy = req.proxy();
|
||||
String key = Http2Connection.keyFor(uri, proxy);
|
||||
@ -123,7 +124,7 @@ class Http2ClientImpl {
|
||||
}
|
||||
}
|
||||
return Http2Connection
|
||||
.createAsync(req, this)
|
||||
.createAsync(req, this, exchange)
|
||||
.whenComplete((conn, t) -> {
|
||||
synchronized (Http2ClientImpl.this) {
|
||||
if (conn != null) {
|
||||
|
@ -353,7 +353,8 @@ class Http2Connection {
|
||||
|
||||
// Requires TLS handshake. So, is really async
|
||||
static CompletableFuture<Http2Connection> createAsync(HttpRequestImpl request,
|
||||
Http2ClientImpl h2client) {
|
||||
Http2ClientImpl h2client,
|
||||
Exchange<?> exchange) {
|
||||
assert request.secure();
|
||||
AbstractAsyncSSLConnection connection = (AbstractAsyncSSLConnection)
|
||||
HttpConnection.getConnection(request.getAddress(),
|
||||
@ -361,7 +362,12 @@ class Http2Connection {
|
||||
request,
|
||||
HttpClient.Version.HTTP_2);
|
||||
|
||||
return connection.connectAsync()
|
||||
// Expose the underlying connection to the exchange's aborter so it can
|
||||
// be closed if a timeout occurs.
|
||||
exchange.connectionAborter.connection(connection);
|
||||
|
||||
return connection.connectAsync(exchange)
|
||||
.thenCompose(unused -> connection.finishConnect())
|
||||
.thenCompose(unused -> checkSSLConfig(connection))
|
||||
.thenCompose(notused-> {
|
||||
CompletableFuture<Http2Connection> cf = new MinimalFuture<>();
|
||||
|
@ -28,6 +28,7 @@ package jdk.internal.net.http;
|
||||
import java.net.Authenticator;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.ProxySelector;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.Executor;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
@ -38,6 +39,7 @@ import static java.util.Objects.requireNonNull;
|
||||
public class HttpClientBuilderImpl implements HttpClient.Builder {
|
||||
|
||||
CookieHandler cookieHandler;
|
||||
Duration connectTimeout;
|
||||
HttpClient.Redirect followRedirects;
|
||||
ProxySelector proxy;
|
||||
Authenticator authenticator;
|
||||
@ -55,6 +57,14 @@ public class HttpClientBuilderImpl implements HttpClient.Builder {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClientBuilderImpl connectTimeout(Duration duration) {
|
||||
requireNonNull(duration);
|
||||
if (duration.isNegative() || Duration.ZERO.equals(duration))
|
||||
throw new IllegalArgumentException("Invalid duration: " + duration);
|
||||
this.connectTimeout = duration;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClientBuilderImpl sslContext(SSLContext sslContext) {
|
||||
|
@ -30,6 +30,7 @@ import java.lang.ref.Reference;
|
||||
import java.net.Authenticator;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.ProxySelector;
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
@ -69,6 +70,11 @@ final class HttpClientFacade extends HttpClient implements Trackable {
|
||||
return impl.cookieHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Duration> connectTimeout() {
|
||||
return impl.connectTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Redirect followRedirects() {
|
||||
return impl.followRedirects();
|
||||
|
@ -35,6 +35,7 @@ import java.net.Authenticator;
|
||||
import java.net.ConnectException;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.http.HttpConnectTimeoutException;
|
||||
import java.net.http.HttpTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.CancelledKeyException;
|
||||
@ -47,6 +48,7 @@ import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
@ -154,6 +156,7 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
}
|
||||
|
||||
private final CookieHandler cookieHandler;
|
||||
private final Duration connectTimeout;
|
||||
private final Redirect followRedirects;
|
||||
private final Optional<ProxySelector> userProxySelector;
|
||||
private final ProxySelector proxySelector;
|
||||
@ -278,6 +281,7 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
facadeRef = new WeakReference<>(facadeFactory.createFacade(this));
|
||||
client2 = new Http2ClientImpl(this);
|
||||
cookieHandler = builder.cookieHandler;
|
||||
connectTimeout = builder.connectTimeout;
|
||||
followRedirects = builder.followRedirects == null ?
|
||||
Redirect.NEVER : builder.followRedirects;
|
||||
this.userProxySelector = Optional.ofNullable(builder.proxy);
|
||||
@ -547,6 +551,10 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
throw new IllegalArgumentException(msg, throwable);
|
||||
} else if (throwable instanceof SecurityException) {
|
||||
throw new SecurityException(msg, throwable);
|
||||
} else if (throwable instanceof HttpConnectTimeoutException) {
|
||||
HttpConnectTimeoutException hcte = new HttpConnectTimeoutException(msg);
|
||||
hcte.initCause(throwable);
|
||||
throw hcte;
|
||||
} else if (throwable instanceof HttpTimeoutException) {
|
||||
throw new HttpTimeoutException(msg);
|
||||
} else if (throwable instanceof ConnectException) {
|
||||
@ -1123,6 +1131,11 @@ final class HttpClientImpl extends HttpClient implements Trackable {
|
||||
return Optional.ofNullable(cookieHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Duration> connectTimeout() {
|
||||
return Optional.ofNullable(connectTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ProxySelector> proxy() {
|
||||
return this.userProxySelector;
|
||||
|
@ -108,9 +108,20 @@ abstract class HttpConnection implements Closeable {
|
||||
return client;
|
||||
}
|
||||
|
||||
//public abstract void connect() throws IOException, InterruptedException;
|
||||
/**
|
||||
* Initiates the connect phase.
|
||||
*
|
||||
* Returns a CompletableFuture that completes when the underlying
|
||||
* TCP connection has been established or an error occurs.
|
||||
*/
|
||||
public abstract CompletableFuture<Void> connectAsync(Exchange<?> exchange);
|
||||
|
||||
public abstract CompletableFuture<Void> connectAsync();
|
||||
/**
|
||||
* Finishes the connection phase.
|
||||
*
|
||||
* Returns a CompletableFuture that completes when any additional,
|
||||
* type specific, setup has been done. Must be called after connectAsync. */
|
||||
public abstract CompletableFuture<Void> finishConnect();
|
||||
|
||||
/** Tells whether, or not, this connection is connected to its destination. */
|
||||
abstract boolean connected();
|
||||
|
@ -27,7 +27,7 @@ package jdk.internal.net.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.time.Duration;
|
||||
import java.net.http.HttpConnectTimeoutException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.security.AccessControlContext;
|
||||
@ -88,7 +88,7 @@ class MultiExchange<T> {
|
||||
);
|
||||
|
||||
private final LinkedList<HeaderFilter> filters;
|
||||
TimedEvent timedEvent;
|
||||
ResponseTimerEvent responseTimerEvent;
|
||||
volatile boolean cancelled;
|
||||
final PushGroup<T> pushGroup;
|
||||
|
||||
@ -134,7 +134,7 @@ class MultiExchange<T> {
|
||||
this.exchange = new Exchange<>(request, this);
|
||||
}
|
||||
|
||||
private synchronized Exchange<T> getExchange() {
|
||||
synchronized Exchange<T> getExchange() {
|
||||
return exchange;
|
||||
}
|
||||
|
||||
@ -157,8 +157,8 @@ class MultiExchange<T> {
|
||||
}
|
||||
|
||||
private void cancelTimer() {
|
||||
if (timedEvent != null) {
|
||||
client.cancelTimer(timedEvent);
|
||||
if (responseTimerEvent != null) {
|
||||
client.cancelTimer(responseTimerEvent);
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,8 +220,8 @@ class MultiExchange<T> {
|
||||
cf = failedFuture(new IOException("Too many retries", retryCause));
|
||||
} else {
|
||||
if (currentreq.timeout().isPresent()) {
|
||||
timedEvent = new TimedEvent(currentreq.timeout().get());
|
||||
client.registerTimer(timedEvent);
|
||||
responseTimerEvent = ResponseTimerEvent.of(this);
|
||||
client.registerTimer(responseTimerEvent);
|
||||
}
|
||||
try {
|
||||
// 1. apply request filters
|
||||
@ -344,7 +344,9 @@ class MultiExchange<T> {
|
||||
}
|
||||
}
|
||||
if (cancelled && t instanceof IOException) {
|
||||
t = new HttpTimeoutException("request timed out");
|
||||
if (!(t instanceof HttpTimeoutException)) {
|
||||
t = toTimeoutException((IOException)t);
|
||||
}
|
||||
} else if (retryOnFailure(t)) {
|
||||
Throwable cause = retryCause(t);
|
||||
|
||||
@ -378,17 +380,24 @@ class MultiExchange<T> {
|
||||
return failedFuture(t);
|
||||
}
|
||||
|
||||
class TimedEvent extends TimeoutEvent {
|
||||
TimedEvent(Duration duration) {
|
||||
super(duration);
|
||||
}
|
||||
@Override
|
||||
public void handle() {
|
||||
if (debug.on()) {
|
||||
debug.log("Cancelling MultiExchange due to timeout for request %s",
|
||||
request);
|
||||
private HttpTimeoutException toTimeoutException(IOException ioe) {
|
||||
HttpTimeoutException t = null;
|
||||
|
||||
// more specific, "request timed out", when connected
|
||||
Exchange<?> exchange = getExchange();
|
||||
if (exchange != null) {
|
||||
ExchangeImpl<?> exchangeImpl = exchange.exchImpl;
|
||||
if (exchangeImpl != null) {
|
||||
if (exchangeImpl.connection().connected()) {
|
||||
t = new HttpTimeoutException("request timed out");
|
||||
t.initCause(ioe);
|
||||
}
|
||||
}
|
||||
cancel(new HttpTimeoutException("request timed out"));
|
||||
}
|
||||
if (t == null) {
|
||||
t = new HttpConnectTimeoutException("HTTP connect timed out");
|
||||
t.initCause(new ConnectException("HTTP connect timed out"));
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
package jdk.internal.net.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.StandardSocketOptions;
|
||||
import java.nio.channels.SelectableChannel;
|
||||
@ -34,6 +35,7 @@ import java.nio.channels.SocketChannel;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import jdk.internal.net.http.common.FlowTube;
|
||||
import jdk.internal.net.http.common.Log;
|
||||
@ -53,9 +55,52 @@ class PlainHttpConnection extends HttpConnection {
|
||||
private final PlainHttpPublisher writePublisher = new PlainHttpPublisher(reading);
|
||||
private volatile boolean connected;
|
||||
private boolean closed;
|
||||
private volatile ConnectTimerEvent connectTimerEvent; // may be null
|
||||
|
||||
// should be volatile to provide proper synchronization(visibility) action
|
||||
|
||||
/**
|
||||
* Returns a ConnectTimerEvent iff there is a connect timeout duration,
|
||||
* otherwise null.
|
||||
*/
|
||||
private ConnectTimerEvent newConnectTimer(Exchange<?> exchange,
|
||||
CompletableFuture<Void> cf) {
|
||||
Duration duration = client().connectTimeout().orElse(null);
|
||||
if (duration != null) {
|
||||
ConnectTimerEvent cte = new ConnectTimerEvent(duration, exchange, cf);
|
||||
return cte;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
final class ConnectTimerEvent extends TimeoutEvent {
|
||||
private final CompletableFuture<Void> cf;
|
||||
private final Exchange<?> exchange;
|
||||
|
||||
ConnectTimerEvent(Duration duration,
|
||||
Exchange<?> exchange,
|
||||
CompletableFuture<Void> cf) {
|
||||
super(duration);
|
||||
this.exchange = exchange;
|
||||
this.cf = cf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() {
|
||||
if (debug.on()) {
|
||||
debug.log("HTTP connect timed out");
|
||||
}
|
||||
ConnectException ce = new ConnectException("HTTP connect timed out");
|
||||
exchange.multi.cancel(ce);
|
||||
client().theExecutor().execute(() -> cf.completeExceptionally(ce));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ConnectTimerEvent, " + super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
final class ConnectEvent extends AsyncEvent {
|
||||
private final CompletableFuture<Void> cf;
|
||||
|
||||
@ -85,7 +130,6 @@ class PlainHttpConnection extends HttpConnection {
|
||||
if (debug.on())
|
||||
debug.log("ConnectEvent: connect finished: %s Local addr: %s",
|
||||
finished, chan.getLocalAddress());
|
||||
connected = true;
|
||||
// complete async since the event runs on the SelectorManager thread
|
||||
cf.completeAsync(() -> null, client().theExecutor());
|
||||
} catch (Throwable e) {
|
||||
@ -103,12 +147,20 @@ class PlainHttpConnection extends HttpConnection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> connectAsync() {
|
||||
public CompletableFuture<Void> connectAsync(Exchange<?> exchange) {
|
||||
CompletableFuture<Void> cf = new MinimalFuture<>();
|
||||
try {
|
||||
assert !connected : "Already connected";
|
||||
assert !chan.isBlocking() : "Unexpected blocking channel";
|
||||
boolean finished = false;
|
||||
boolean finished;
|
||||
|
||||
connectTimerEvent = newConnectTimer(exchange, cf);
|
||||
if (connectTimerEvent != null) {
|
||||
if (debug.on())
|
||||
debug.log("registering connect timer: " + connectTimerEvent);
|
||||
client().registerTimer(connectTimerEvent);
|
||||
}
|
||||
|
||||
PrivilegedExceptionAction<Boolean> pa =
|
||||
() -> chan.connect(Utils.resolveAddress(address));
|
||||
try {
|
||||
@ -118,7 +170,6 @@ class PlainHttpConnection extends HttpConnection {
|
||||
}
|
||||
if (finished) {
|
||||
if (debug.on()) debug.log("connect finished without blocking");
|
||||
connected = true;
|
||||
cf.complete(null);
|
||||
} else {
|
||||
if (debug.on()) debug.log("registering connect event");
|
||||
@ -136,6 +187,16 @@ class PlainHttpConnection extends HttpConnection {
|
||||
return cf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> finishConnect() {
|
||||
assert connected == false;
|
||||
if (debug.on()) debug.log("finishConnect, setting connected=true");
|
||||
connected = true;
|
||||
if (connectTimerEvent != null)
|
||||
client().cancelTimer(connectTimerEvent);
|
||||
return MinimalFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
SocketChannel channel() {
|
||||
return chan;
|
||||
@ -210,6 +271,8 @@ class PlainHttpConnection extends HttpConnection {
|
||||
Log.logTrace("Closing: " + toString());
|
||||
if (debug.on())
|
||||
debug.log("Closing channel: " + client().debugInterestOps(chan));
|
||||
if (connectTimerEvent != null)
|
||||
client().cancelTimer(connectTimerEvent);
|
||||
chan.close();
|
||||
tube.signalClosed();
|
||||
} catch (IOException e) {
|
||||
|
@ -26,11 +26,13 @@
|
||||
package jdk.internal.net.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.System.Logger.Level;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.http.HttpTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.function.Function;
|
||||
import java.net.http.HttpHeaders;
|
||||
import jdk.internal.net.http.common.FlowTube;
|
||||
@ -60,9 +62,10 @@ final class PlainTunnelingConnection extends HttpConnection {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> connectAsync() {
|
||||
public CompletableFuture<Void> connectAsync(Exchange<?> exchange) {
|
||||
if (debug.on()) debug.log("Connecting plain connection");
|
||||
return delegate.connectAsync()
|
||||
return delegate.connectAsync(exchange)
|
||||
.thenCompose(unused -> delegate.finishConnect())
|
||||
.thenCompose((Void v) -> {
|
||||
if (debug.on()) debug.log("sending HTTP/1.1 CONNECT");
|
||||
HttpClientImpl client = client();
|
||||
@ -70,7 +73,7 @@ final class PlainTunnelingConnection extends HttpConnection {
|
||||
HttpRequestImpl req = new HttpRequestImpl("CONNECT", address, proxyHeaders);
|
||||
MultiExchange<Void> mulEx = new MultiExchange<>(null, req,
|
||||
client, discarding(), null, null);
|
||||
Exchange<Void> connectExchange = new Exchange<>(req, mulEx);
|
||||
Exchange<Void> connectExchange = mulEx.getExchange();
|
||||
|
||||
return connectExchange
|
||||
.responseAsyncImpl(delegate)
|
||||
@ -96,14 +99,36 @@ final class PlainTunnelingConnection extends HttpConnection {
|
||||
ByteBuffer b = ((Http1Exchange<?>)connectExchange.exchImpl).drainLeftOverBytes();
|
||||
int remaining = b.remaining();
|
||||
assert remaining == 0: "Unexpected remaining: " + remaining;
|
||||
connected = true;
|
||||
cf.complete(null);
|
||||
}
|
||||
return cf;
|
||||
});
|
||||
})
|
||||
.handle((result, ex) -> {
|
||||
if (ex == null) {
|
||||
return MinimalFuture.completedFuture(result);
|
||||
} else {
|
||||
if (debug.on())
|
||||
debug.log("tunnel failed with \"%s\"", ex.toString());
|
||||
Throwable t = ex;
|
||||
if (t instanceof CompletionException)
|
||||
t = t.getCause();
|
||||
if (t instanceof HttpTimeoutException) {
|
||||
String msg = "proxy tunneling CONNECT request timed out";
|
||||
t = new HttpTimeoutException(msg);
|
||||
t.initCause(ex);
|
||||
}
|
||||
return MinimalFuture.<Void>failedFuture(t);
|
||||
}
|
||||
})
|
||||
.thenCompose(Function.identity());
|
||||
});
|
||||
}
|
||||
|
||||
public CompletableFuture<Void> finishConnect() {
|
||||
connected = true;
|
||||
return MinimalFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isTunnel() { return true; }
|
||||
|
||||
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.internal.net.http;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.net.http.HttpConnectTimeoutException;
|
||||
import java.net.http.HttpTimeoutException;
|
||||
import jdk.internal.net.http.common.Logger;
|
||||
import jdk.internal.net.http.common.Utils;
|
||||
|
||||
public class ResponseTimerEvent extends TimeoutEvent {
|
||||
private static final Logger debug =
|
||||
Utils.getDebugLogger("ResponseTimerEvent"::toString, Utils.DEBUG);
|
||||
|
||||
private final MultiExchange<?> multiExchange;
|
||||
|
||||
static ResponseTimerEvent of(MultiExchange<?> exchange) {
|
||||
return new ResponseTimerEvent(exchange);
|
||||
}
|
||||
|
||||
private ResponseTimerEvent(MultiExchange<?> multiExchange) {
|
||||
super(multiExchange.exchange.request.timeout().get());
|
||||
this.multiExchange = multiExchange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() {
|
||||
if (debug.on()) {
|
||||
debug.log("Cancelling MultiExchange due to timeout for request %s",
|
||||
multiExchange.exchange.request);
|
||||
}
|
||||
HttpTimeoutException t = null;
|
||||
|
||||
// more specific, "request timed out", message when connected
|
||||
Exchange<?> exchange = multiExchange.getExchange();
|
||||
if (exchange != null) {
|
||||
ExchangeImpl<?> exchangeImpl = exchange.exchImpl;
|
||||
if (exchangeImpl != null) {
|
||||
if (exchangeImpl.connection().connected()) {
|
||||
t = new HttpTimeoutException("request timed out");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (t == null) {
|
||||
t = new HttpConnectTimeoutException("HTTP connect timed out");
|
||||
t.initCause(new ConnectException("HTTP connect timed out"));
|
||||
}
|
||||
multiExchange.cancel(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ResponseTimerEvent[" + super.toString() + "]";
|
||||
}
|
||||
}
|
@ -43,9 +43,11 @@ abstract class TimeoutEvent implements Comparable<TimeoutEvent> {
|
||||
// we use id in compareTo to make compareTo consistent with equals
|
||||
// see TimeoutEvent::compareTo below;
|
||||
private final long id = COUNTER.incrementAndGet();
|
||||
private final Duration duration;
|
||||
private final Instant deadline;
|
||||
|
||||
TimeoutEvent(Duration duration) {
|
||||
this.duration = duration;
|
||||
deadline = Instant.now().plus(duration);
|
||||
}
|
||||
|
||||
@ -75,6 +77,7 @@ abstract class TimeoutEvent implements Comparable<TimeoutEvent> {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TimeoutEvent[id=" + id + ", deadline=" + deadline + "]";
|
||||
return "TimeoutEvent[id=" + id + ", duration=" + duration
|
||||
+ ", deadline=" + deadline + "]";
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines the core Java SE API.
|
||||
* Defines the API of the Java SE Platform.
|
||||
* <P>
|
||||
*
|
||||
* <dl>
|
||||
|
@ -98,42 +98,42 @@ doclet.Window_Help_title=API\u30D8\u30EB\u30D7
|
||||
|
||||
doclet.help.main_heading=API\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306E\u69CB\u6210
|
||||
doclet.help.intro=\u3053\u306EAPI(Application Programming Interface)\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306B\u306F\u3001\u6B21\u306B\u8AAC\u660E\u3059\u308B\u30CA\u30D3\u30B2\u30FC\u30B7\u30E7\u30F3\u30FB\u30D0\u30FC\u306B\u3042\u308B\u9805\u76EE\u306B\u5BFE\u5FDC\u3059\u308B\u30DA\u30FC\u30B8\u304C\u542B\u307E\u308C\u307E\u3059\u3002
|
||||
doclet.help.overview.modules.body=The {0} page is the front page of this API document and provides a list of all modules with a summary for each. This page can also contain an overall description of the set of modules.
|
||||
doclet.help.overview.modules.body={0}\u30DA\u30FC\u30B8\u306FAPI\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306E\u30D5\u30ED\u30F3\u30C8\u30FB\u30DA\u30FC\u30B8\u3067\u3001\u5404\u30E2\u30B8\u30E5\u30FC\u30EB\u306E\u6982\u8981\u3092\u542B\u3080\u5168\u30E2\u30B8\u30E5\uFF0D\u30EB\u306E\u30EA\u30B9\u30C8\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002\u4E00\u9023\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u306E\u6982\u8981\u8AAC\u660E\u3082\u8868\u793A\u3055\u308C\u307E\u3059\u3002
|
||||
doclet.help.overview.packages.body={0}\u30DA\u30FC\u30B8\u306FAPI\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306E\u30D5\u30ED\u30F3\u30C8\u30FB\u30DA\u30FC\u30B8\u3067\u3001\u5404\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u6982\u8981\u3092\u542B\u3080\u5168\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u30EA\u30B9\u30C8\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002\u4E00\u9023\u306E\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u6982\u8981\u8AAC\u660E\u3082\u8868\u793A\u3055\u308C\u307E\u3059\u3002
|
||||
doclet.help.package.intro=Each package has a page that contains a list of its classes and interfaces, with a summary for each. These pages may contain six categories:
|
||||
doclet.help.module.intro=Each module has a page that contains a list of its packages, dependencies on other modules, and services, with a summary for each. These page may contain three categories:
|
||||
doclet.help.class_interface.head=Class or Interface
|
||||
doclet.help.package.intro=\u5404\u30D1\u30C3\u30B1\u30FC\u30B8\u306B\u306F\u3001\u305D\u306E\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u30AF\u30E9\u30B9\u304A\u3088\u3073\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u306E\u30EA\u30B9\u30C8\u3068\u3001\u305D\u308C\u305E\u308C\u306E\u6982\u8981\u3092\u542B\u3080\u30DA\u30FC\u30B8\u304C\u3042\u308A\u307E\u3059\u3002\u3053\u308C\u3089\u306E\u30DA\u30FC\u30B8\u306F6\u3064\u306E\u30AB\u30C6\u30B4\u30EA\u3067\u69CB\u6210\u3055\u308C\u307E\u3059\u3002
|
||||
doclet.help.module.intro=\u5404\u30E2\u30B8\u30E5\u30FC\u30EB\u306B\u306F\u3001\u305D\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u306E\u30D1\u30C3\u30B1\u30FC\u30B8\u3001\u4ED6\u306E\u30E2\u30B8\u30E5\u30FC\u30EB\u306B\u5BFE\u3059\u308B\u4F9D\u5B58\u6027\u3001\u304A\u3088\u3073\u30B5\u30FC\u30D3\u30B9\u306E\u30EA\u30B9\u30C8\u3068\u3001\u305D\u308C\u305E\u308C\u306E\u6982\u8981\u3092\u542B\u3080\u30DA\u30FC\u30B8\u304C\u3042\u308A\u307E\u3059\u3002\u3053\u308C\u3089\u306E\u30DA\u30FC\u30B8\u306F3\u3064\u306E\u30AB\u30C6\u30B4\u30EA\u3067\u69CB\u6210\u3055\u308C\u307E\u3059\u3002
|
||||
doclet.help.class_interface.head=\u30AF\u30E9\u30B9\u307E\u305F\u306F\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9
|
||||
doclet.help.class_interface.intro=\u5404\u30AF\u30E9\u30B9\u3001\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u3001\u30CD\u30B9\u30C8\u3055\u308C\u305F\u30AF\u30E9\u30B9\u304A\u3088\u3073\u30CD\u30B9\u30C8\u3055\u308C\u305F\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u306B\u306F\u500B\u5225\u306E\u30DA\u30FC\u30B8\u304C\u3042\u308A\u307E\u3059\u3002\u5404\u30DA\u30FC\u30B8\u306B\u306F\u6B21\u306E\u3088\u3046\u306B\u3001\u30AF\u30E9\u30B9\u307E\u305F\u306F\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u306E\u8AAC\u660E\u3068\u3001\u6982\u8981\u8868\u304A\u3088\u3073\u30E1\u30F3\u30D0\u30FC\u306E\u8A73\u7D30\u8AAC\u660E\u304C\u542B\u307E\u308C\u307E\u3059\u3002
|
||||
doclet.help.class_interface.inheritance_diagram=Class Inheritance Diagram
|
||||
doclet.help.class_interface.inheritance_diagram=\u30AF\u30E9\u30B9\u968E\u5C64\u8868\u793A
|
||||
doclet.help.class_interface.subclasses=\u76F4\u7CFB\u306E\u30B5\u30D6\u30AF\u30E9\u30B9
|
||||
doclet.help.class_interface.subinterfaces=\u65E2\u77E5\u306E\u30B5\u30D6\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u306E\u30EA\u30B9\u30C8
|
||||
doclet.help.class_interface.implementations=\u65E2\u77E5\u306E\u5B9F\u88C5\u30AF\u30E9\u30B9\u306E\u30EA\u30B9\u30C8
|
||||
doclet.help.class_interface.declaration=Class or Interface Declaration
|
||||
doclet.help.class_interface.description=Class or Interface Description
|
||||
doclet.help.class_interface.declaration=\u30AF\u30E9\u30B9\u307E\u305F\u306F\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u306E\u5BA3\u8A00
|
||||
doclet.help.class_interface.description=\u30AF\u30E9\u30B9\u307E\u305F\u306F\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u306E\u8AAC\u660E
|
||||
doclet.help.class_interface.summary=\u5404\u6982\u8981\u30A8\u30F3\u30C8\u30EA\u306B\u306F\u3001\u305D\u306E\u9805\u76EE\u306E\u8A73\u7D30\u306A\u8AAC\u660E\u306E\u4E2D\u304B\u30891\u884C\u76EE\u306E\u6587\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002\u8A73\u7D30\u306A\u8AAC\u660E\u306F\u30BD\u30FC\u30B9\u30FB\u30B3\u30FC\u30C9\u306B\u73FE\u308C\u308B\u9806\u306B\u4E26\u3079\u3089\u308C\u307E\u3059\u304C\u3001\u6982\u8981\u30A8\u30F3\u30C8\u30EA\u306F\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8\u9806\u306B\u4E26\u3079\u3089\u308C\u307E\u3059\u3002\u3053\u308C\u306B\u3088\u3063\u3066\u3001\u30D7\u30ED\u30B0\u30E9\u30DE\u304C\u8A2D\u5B9A\u3057\u305F\u8AD6\u7406\u7684\u306A\u30B0\u30EB\u30FC\u30D7\u5206\u3051\u304C\u4FDD\u6301\u3055\u308C\u307E\u3059\u3002
|
||||
doclet.help.use.head=\u4F7F\u7528
|
||||
doclet.help.use.body=Each documented package, class and interface has its own Use page. This page describes what packages, classes, methods, constructors and fields use any part of the given class or package. Given a class or interface A, its "Use" page includes subclasses of A, fields declared as A, methods that return A, and methods and constructors with parameters of type A. You can access this page by first going to the package, class or interface, then clicking on the "Use" link in the navigation bar.
|
||||
doclet.help.use.body=\u5404\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u5316\u3055\u308C\u305F\u30D1\u30C3\u30B1\u30FC\u30B8\u3001\u30AF\u30E9\u30B9\u304A\u3088\u3073\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u306B\u306F\u305D\u308C\u305E\u308C\u300C\u4F7F\u7528\u300D\u30DA\u30FC\u30B8\u304C\u3042\u308A\u307E\u3059\u3002\u3053\u306E\u30DA\u30FC\u30B8\u306B\u306F\u3001\u3069\u306E\u3088\u3046\u306A\u30D1\u30C3\u30B1\u30FC\u30B8\u3001\u30AF\u30E9\u30B9\u3001\u30E1\u30BD\u30C3\u30C9\u3001\u30B3\u30F3\u30B9\u30C8\u30E9\u30AF\u30BF\u304A\u3088\u3073\u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u3001\u7279\u5B9A\u306E\u30AF\u30E9\u30B9\u307E\u305F\u306F\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u4E00\u90E8\u3092\u4F7F\u7528\u3057\u3066\u3044\u308B\u304B\u304C\u8A18\u8FF0\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u305F\u3068\u3048\u3070\u3001\u30AF\u30E9\u30B9A\u307E\u305F\u306F\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9A\u306E\u5834\u5408\u3001\u305D\u306E\u300C\u4F7F\u7528\u300D\u30DA\u30FC\u30B8\u306B\u306F\u3001A\u306E\u30B5\u30D6\u30AF\u30E9\u30B9\u3001A\u3068\u3057\u3066\u5BA3\u8A00\u3055\u308C\u308B\u30D5\u30A3\u30FC\u30EB\u30C9\u3001A\u3092\u8FD4\u3059\u30E1\u30BD\u30C3\u30C9\u3068\u3001\u578BA\u3092\u6301\u3064\u30E1\u30BD\u30C3\u30C9\u304A\u3088\u3073\u30B3\u30F3\u30B9\u30C8\u30E9\u30AF\u30BF\u304C\u542B\u307E\u308C\u307E\u3059\u3002\u3053\u306E\u30DA\u30FC\u30B8\u306B\u30A2\u30AF\u30BB\u30B9\u3059\u308B\u306B\u306F\u3001\u307E\u305A\u305D\u306E\u30D1\u30C3\u30B1\u30FC\u30B8\u3001\u30AF\u30E9\u30B9\u307E\u305F\u306F\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u306B\u79FB\u52D5\u3057\u3001\u30CA\u30D3\u30B2\u30FC\u30B7\u30E7\u30F3\u30FB\u30D0\u30FC\u306E\u300C\u4F7F\u7528\u300D\u30EA\u30F3\u30AF\u3092\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
||||
doclet.help.tree.head=\u968E\u5C64\u30C4\u30EA\u30FC(\u30AF\u30E9\u30B9\u968E\u5C64)
|
||||
doclet.help.tree.intro=There is a {0} page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. Classes are organized by inheritance structure starting with {1}. Interfaces do not inherit from {1}.
|
||||
doclet.help.tree.intro=\u3059\u3079\u3066\u306E\u30D1\u30C3\u30B1\u30FC\u30B8\u306B\u306F{0}\u30DA\u30FC\u30B8\u304C\u3042\u308A\u3001\u3055\u3089\u306B\u5404\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u968E\u5C64\u304C\u3042\u308A\u307E\u3059\u3002\u5404\u968E\u5C64\u30DA\u30FC\u30B8\u306F\u3001\u30AF\u30E9\u30B9\u306E\u30EA\u30B9\u30C8\u3068\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u306E\u30EA\u30B9\u30C8\u3092\u542B\u307F\u307E\u3059\u3002\u30AF\u30E9\u30B9\u306F{1}\u3092\u958B\u59CB\u70B9\u3068\u3059\u308B\u7D99\u627F\u69CB\u9020\u3067\u7DE8\u6210\u3055\u308C\u307E\u3059\u3002\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u306F\u3001{1}\u304B\u3089\u306F\u7D99\u627F\u3057\u307E\u305B\u3093\u3002
|
||||
doclet.help.tree.overview=\u6982\u8981\u30DA\u30FC\u30B8\u3092\u8868\u793A\u3057\u3066\u3044\u308B\u3068\u304D\u306B\u300C\u968E\u5C64\u30C4\u30EA\u30FC\u300D\u3092\u30AF\u30EA\u30C3\u30AF\u3059\u308B\u3068\u3001\u5168\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u968E\u5C64\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002
|
||||
doclet.help.tree.package=When viewing a particular package, class or interface page, clicking on "Tree" displays the hierarchy for only that package.
|
||||
doclet.help.tree.package=\u7279\u5B9A\u306E\u30D1\u30C3\u30B1\u30FC\u30B8\u3001\u30AF\u30E9\u30B9\u307E\u305F\u306F\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u306E\u30DA\u30FC\u30B8\u3092\u8868\u793A\u3057\u3066\u3044\u308B\u3068\u304D\u306B\u300C\u968E\u5C64\u30C4\u30EA\u30FC\u300D\u3092\u30AF\u30EA\u30C3\u30AF\u3059\u308B\u3068\u3001\u8A72\u5F53\u3059\u308B\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u307F\u306E\u968E\u5C64\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002
|
||||
doclet.help.deprecated.body={0}\u30DA\u30FC\u30B8\u306F\u3001\u63A8\u5968\u3055\u308C\u3066\u3044\u306A\u3044\u3059\u3079\u3066\u306EAPI\u306E\u30EA\u30B9\u30C8\u3092\u8868\u793A\u3057\u307E\u3059\u3002\u975E\u63A8\u5968API\u3068\u306F\u3001\u6A5F\u80FD\u6539\u826F\u306A\u3069\u306E\u7406\u7531\u304B\u3089\u4F7F\u7528\u3092\u304A\u85A6\u3081\u3067\u304D\u306A\u304F\u306A\u3063\u305FAPI\u306E\u3053\u3068\u3067\u3001\u901A\u5E38\u306F\u305D\u308C\u306B\u4EE3\u308F\u308BAPI\u304C\u63D0\u4F9B\u3055\u308C\u307E\u3059\u3002\u975E\u63A8\u5968API\u306F\u4ECA\u5F8C\u306E\u5B9F\u88C5\u3067\u524A\u9664\u3055\u308C\u308B\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002
|
||||
doclet.help.index.head=\u7D22\u5F15
|
||||
doclet.help.index.body=The {0} contains an alphabetic index of all classes, interfaces, constructors, methods, and fields, as well as lists of all packages and all classes.
|
||||
doclet.help.index.body={0}\u306B\u306F\u3001\u3059\u3079\u3066\u306E\u30AF\u30E9\u30B9\u3001\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9\u3001\u30B3\u30F3\u30B9\u30C8\u30E9\u30AF\u30BF\u3001\u30E1\u30BD\u30C3\u30C9\u304A\u3088\u3073\u30D5\u30A3\u30FC\u30EB\u30C9\u306E\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8\u9806\u306E\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u3068\u3001\u3059\u3079\u3066\u306E\u30D1\u30C3\u30B1\u30FC\u30B8\u304A\u3088\u3073\u3059\u3079\u3066\u306E\u30AF\u30E9\u30B9\u306E\u30EA\u30B9\u30C8\u304C\u542B\u307E\u308C\u307E\u3059\u3002
|
||||
doclet.help.frames.head=\u30D5\u30EC\u30FC\u30E0/\u30D5\u30EC\u30FC\u30E0\u306A\u3057
|
||||
doclet.help.frames.body=\u3053\u308C\u3089\u306E\u30EA\u30F3\u30AF\u306FHTML\u30D5\u30EC\u30FC\u30E0\u306E\u8868\u793A\u3068\u975E\u8868\u793A\u3092\u5207\u308A\u66FF\u3048\u307E\u3059\u3002\u3059\u3079\u3066\u306E\u30DA\u30FC\u30B8\u306F\u30D5\u30EC\u30FC\u30E0\u3042\u308A\u3067\u3082\u3001\u30D5\u30EC\u30FC\u30E0\u306A\u3057\u3067\u3082\u8868\u793A\u3067\u304D\u307E\u3059\u3002
|
||||
doclet.help.all_classes.body={0}\u30EA\u30F3\u30AF\u306B\u306F\u3001\u3059\u3079\u3066\u306E\u30AF\u30E9\u30B9\u304A\u3088\u3073\u30A4\u30F3\u30BF\u30D5\u30A7\u30FC\u30B9(\u975Estatic\u306E\u30CD\u30B9\u30C8\u3055\u308C\u305F\u578B\u3092\u9664\u304F)\u304C\u8868\u793A\u3055\u308C\u307E\u3059\u3002
|
||||
doclet.help.serial_form.body=\u76F4\u5217\u5316\u53EF\u80FD\u307E\u305F\u306F\u5916\u90E8\u5316\u53EF\u80FD\u306A\u5404\u30AF\u30E9\u30B9\u306F\u3001\u76F4\u5217\u5316\u30D5\u30A3\u30FC\u30EB\u30C9\u3068\u30E1\u30BD\u30C3\u30C9\u306E\u8AAC\u660E\u3092\u542B\u307F\u307E\u3059\u3002\u3053\u306E\u60C5\u5831\u306F\u3001API\u3092\u4F7F\u7528\u3059\u308B\u958B\u767A\u8005\u3067\u306F\u306A\u304F\u3001\u518D\u5B9F\u88C5\u3092\u884C\u3046\u62C5\u5F53\u8005\u306B\u5F79\u7ACB\u3061\u307E\u3059\u3002\u30CA\u30D3\u30B2\u30FC\u30B7\u30E7\u30F3\u30FB\u30D0\u30FC\u306B\u30EA\u30F3\u30AF\u304C\u306A\u3044\u5834\u5408\u3001\u76F4\u5217\u5316\u3055\u308C\u305F\u30AF\u30E9\u30B9\u306B\u79FB\u52D5\u3057\u3066\u3001\u30AF\u30E9\u30B9\u8A18\u8FF0\u306E\u300C\u95A2\u9023\u9805\u76EE\u300D\u30BB\u30AF\u30B7\u30E7\u30F3\u306B\u3042\u308B\u300C\u76F4\u5217\u5316\u3055\u308C\u305F\u5F62\u5F0F\u300D\u3092\u30AF\u30EA\u30C3\u30AF\u3059\u308B\u3053\u3068\u306B\u3088\u308A\u3001\u3053\u306E\u60C5\u5831\u3092\u8868\u793A\u3067\u304D\u307E\u3059\u3002
|
||||
doclet.help.constants.body={0}\u30DA\u30FC\u30B8\u306B\u306F\u3001static final\u30D5\u30A3\u30FC\u30EB\u30C9\u3068\u305D\u306E\u5024\u306E\u30EA\u30B9\u30C8\u304C\u3042\u308A\u307E\u3059\u3002
|
||||
doclet.help.footnote=This help file applies to API documentation generated by the standard doclet.
|
||||
doclet.help.footnote=\u3053\u306E\u30D8\u30EB\u30D7\u30FB\u30D5\u30A1\u30A4\u30EB\u306F\u3001\u6A19\u6E96doclet\u306B\u3088\u3063\u3066\u751F\u6210\u3055\u308C\u305FAPI\u30C9\u30AD\u30E5\u30E1\u30F3\u30C8\u306B\u9069\u7528\u3055\u308C\u307E\u3059\u3002
|
||||
doclet.help.enum.intro=\u5404\u5217\u6319\u578B\u306B\u306F\u3001\u305D\u308C\u81EA\u8EAB\u306E\u500B\u5225\u306E\u30DA\u30FC\u30B8\u3068\u6B21\u306E\u30BB\u30AF\u30B7\u30E7\u30F3\u304C\u3042\u308A\u307E\u3059:
|
||||
doclet.help.enum.declaration=\u5217\u6319\u5BA3\u8A00
|
||||
doclet.help.enum.definition=Enum Description
|
||||
doclet.help.enum.definition=\u5217\u6319\u578B\u306E\u8AAC\u660E
|
||||
doclet.help.annotation_type.intro=\u5404\u6CE8\u91C8\u578B\u306B\u306F\u3001\u305D\u308C\u81EA\u8EAB\u306E\u500B\u5225\u306E\u30DA\u30FC\u30B8\u3068\u6B21\u306E\u30BB\u30AF\u30B7\u30E7\u30F3\u304C\u3042\u308A\u307E\u3059:
|
||||
doclet.help.annotation_type.declaration=Annotation Type Declaration
|
||||
doclet.help.annotation_type.description=Annotation Type Description
|
||||
doclet.help.search.head=Search
|
||||
doclet.help.search.body=You can search for definitions of modules, packages, types, fields, methods and other terms defined in the API, using some or all of the name. "Camel-case" abbreviations are supported: for example, "InpStr" will find "InputStream" and "InputStreamReader".
|
||||
doclet.help.annotation_type.declaration=\u6CE8\u91C8\u578B\u306E\u5BA3\u8A00
|
||||
doclet.help.annotation_type.description=\u6CE8\u91C8\u578B\u306E\u8AAC\u660E
|
||||
doclet.help.search.head=\u691C\u7D22
|
||||
doclet.help.search.body=\u30E2\u30B8\u30E5\u30FC\u30EB\u3001\u30D1\u30C3\u30B1\u30FC\u30B8\u3001\u30BF\u30A4\u30D7\u3001\u30D5\u30A3\u30FC\u30EB\u30C9\u3001\u30E1\u30BD\u30C3\u30C9\u3001\u304A\u3088\u3073API\u3067\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u308B\u305D\u306E\u4ED6\u306E\u8A9E\u3092\u3001\u540D\u524D\u306E\u4E00\u90E8\u307E\u305F\u306F\u5168\u4F53\u3092\u4F7F\u7528\u3057\u3066\u691C\u7D22\u3067\u304D\u307E\u3059\u3002\u30AD\u30E3\u30E1\u30EB\u30B1\u30FC\u30B9\u306E\u7701\u7565\u5F62\u304C\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u3059: \u305F\u3068\u3048\u3070\u3001"InpStr"\u3068\u6307\u5B9A\u3059\u308B\u3068"InputStream"\u3068"InputStreamReader"\u304C\u691C\u7D22\u3055\u308C\u307E\u3059\u3002
|
||||
|
||||
doclet.ClassUse_Packages.that.use.0={0}\u3092\u4F7F\u7528\u3057\u3066\u3044\u308B\u30D1\u30C3\u30B1\u30FC\u30B8
|
||||
doclet.ClassUse_Uses.of.0.in.1={1}\u3067\u306E{0}\u306E\u4F7F\u7528
|
||||
|
@ -98,42 +98,42 @@ doclet.Window_Help_title=API \u5E2E\u52A9
|
||||
|
||||
doclet.help.main_heading=\u6B64 API \u6587\u6863\u7684\u7EC4\u7EC7\u65B9\u5F0F
|
||||
doclet.help.intro=\u6B64 API (\u5E94\u7528\u7A0B\u5E8F\u7F16\u7A0B\u63A5\u53E3) \u6587\u6863\u5305\u542B\u5BF9\u5E94\u4E8E\u5BFC\u822A\u680F\u4E2D\u7684\u9879\u76EE\u7684\u9875\u9762, \u5982\u4E0B\u6240\u8FF0\u3002
|
||||
doclet.help.overview.modules.body=The {0} page is the front page of this API document and provides a list of all modules with a summary for each. This page can also contain an overall description of the set of modules.
|
||||
doclet.help.overview.modules.body={0} \u9875\u662F\u6B64 API \u6587\u6863\u7684\u9996\u9875\uFF0C\u63D0\u4F9B\u4E86\u6240\u6709\u6A21\u5757\u7684\u5217\u8868\u53CA\u5176\u6982\u8981\u3002\u6B64\u9875\u4E5F\u53EF\u80FD\u5305\u542B\u8FD9\u4E9B\u6A21\u5757\u7684\u603B\u4F53\u8BF4\u660E\u3002
|
||||
doclet.help.overview.packages.body={0} \u9875\u9762\u662F\u6B64 API \u6587\u6863\u7684\u9996\u9875, \u63D0\u4F9B\u4E86\u6240\u6709\u7A0B\u5E8F\u5305\u7684\u5217\u8868\u53CA\u5176\u6982\u8981\u3002\u6B64\u9875\u9762\u4E5F\u53EF\u80FD\u5305\u542B\u8FD9\u4E9B\u7A0B\u5E8F\u5305\u7684\u603B\u4F53\u8BF4\u660E\u3002
|
||||
doclet.help.package.intro=Each package has a page that contains a list of its classes and interfaces, with a summary for each. These pages may contain six categories:
|
||||
doclet.help.module.intro=Each module has a page that contains a list of its packages, dependencies on other modules, and services, with a summary for each. These page may contain three categories:
|
||||
doclet.help.class_interface.head=Class or Interface
|
||||
doclet.help.package.intro=\u6BCF\u4E2A\u7A0B\u5E8F\u5305\u90FD\u6709\u4E00\u9875\uFF0C\u5176\u4E2D\u5305\u542B\u5B83\u7684\u7C7B\u548C\u63A5\u53E3\u7684\u5217\u8868\u53CA\u5176\u6982\u8981\u3002\u8FD9\u4E9B\u9875\u53EF\u4EE5\u5305\u542B\u516D\u4E2A\u7C7B\u522B\uFF1A
|
||||
doclet.help.module.intro=\u6BCF\u4E2A\u6A21\u5757\u90FD\u6709\u4E00\u9875\uFF0C\u5176\u4E2D\u5305\u542B\u5B83\u7684\u7A0B\u5E8F\u5305\u3001\u4E0E\u5176\u4ED6\u6A21\u5757\u7684\u4F9D\u8D56\u5173\u7CFB\u548C\u670D\u52A1\u7684\u5217\u8868\u4EE5\u53CA\u5404\u4E2A\u6A21\u5757\u7684\u6982\u8981\u3002\u8FD9\u4E9B\u9875\u53EF\u4EE5\u5305\u542B\u4E09\u4E2A\u7C7B\u522B\uFF1A
|
||||
doclet.help.class_interface.head=\u7C7B\u6216\u63A5\u53E3
|
||||
doclet.help.class_interface.intro=\u6BCF\u4E2A\u7C7B, \u63A5\u53E3, \u5D4C\u5957\u7C7B\u548C\u5D4C\u5957\u63A5\u53E3\u90FD\u6709\u5404\u81EA\u7684\u9875\u9762\u3002\u5176\u4E2D\u6BCF\u4E2A\u9875\u9762\u90FD\u7531\u4E09\u90E8\u5206 (\u7C7B/\u63A5\u53E3\u8BF4\u660E, \u6982\u8981\u8868, \u4EE5\u53CA\u8BE6\u7EC6\u7684\u6210\u5458\u8BF4\u660E) \u7EC4\u6210:
|
||||
doclet.help.class_interface.inheritance_diagram=Class Inheritance Diagram
|
||||
doclet.help.class_interface.inheritance_diagram=\u7C7B\u7EE7\u627F\u56FE
|
||||
doclet.help.class_interface.subclasses=\u76F4\u63A5\u5B50\u7C7B
|
||||
doclet.help.class_interface.subinterfaces=\u6240\u6709\u5DF2\u77E5\u5B50\u63A5\u53E3
|
||||
doclet.help.class_interface.implementations=\u6240\u6709\u5DF2\u77E5\u5B9E\u73B0\u7C7B
|
||||
doclet.help.class_interface.declaration=Class or Interface Declaration
|
||||
doclet.help.class_interface.description=Class or Interface Description
|
||||
doclet.help.class_interface.declaration=\u7C7B\u6216\u63A5\u53E3\u58F0\u660E
|
||||
doclet.help.class_interface.description=\u7C7B\u6216\u63A5\u53E3\u8BF4\u660E
|
||||
doclet.help.class_interface.summary=\u6BCF\u4E2A\u6982\u8981\u6761\u76EE\u90FD\u5305\u542B\u8BE5\u9879\u76EE\u7684\u8BE6\u7EC6\u8BF4\u660E\u7684\u7B2C\u4E00\u53E5\u3002\u6982\u8981\u6761\u76EE\u6309\u5B57\u6BCD\u987A\u5E8F\u6392\u5217, \u800C\u8BE6\u7EC6\u8BF4\u660E\u5219\u6309\u5176\u5728\u6E90\u4EE3\u7801\u4E2D\u51FA\u73B0\u7684\u987A\u5E8F\u6392\u5217\u3002\u8FD9\u6837\u4FDD\u6301\u4E86\u7A0B\u5E8F\u5458\u6240\u5EFA\u7ACB\u7684\u903B\u8F91\u5206\u7EC4\u3002
|
||||
doclet.help.use.head=\u4F7F\u7528
|
||||
doclet.help.use.body=Each documented package, class and interface has its own Use page. This page describes what packages, classes, methods, constructors and fields use any part of the given class or package. Given a class or interface A, its "Use" page includes subclasses of A, fields declared as A, methods that return A, and methods and constructors with parameters of type A. You can access this page by first going to the package, class or interface, then clicking on the "Use" link in the navigation bar.
|
||||
doclet.help.use.body=\u6BCF\u4E2A\u5DF2\u6587\u6863\u5316\u7684\u7A0B\u5E8F\u5305\u3001\u7C7B\u548C\u63A5\u53E3\u90FD\u6709\u5404\u81EA\u7684\u201C\u4F7F\u7528\u201D\u9875\u3002\u6B64\u9875\u4ECB\u7ECD\u4E86\u4F7F\u7528\u7ED9\u5B9A\u7C7B\u6216\u7A0B\u5E8F\u5305\u7684\u4EFB\u4F55\u90E8\u5206\u7684\u7A0B\u5E8F\u5305\u3001\u7C7B\u3001\u65B9\u6CD5\u3001\u6784\u9020\u5668\u548C\u5B57\u6BB5\u3002\u5BF9\u4E8E\u7ED9\u5B9A\u7684\u7C7B\u6216\u63A5\u53E3 A\uFF0C\u5176\u201C\u4F7F\u7528\u201D\u9875\u5305\u542B A \u7684\u5B50\u7C7B\u3001\u58F0\u660E\u4E3A A \u7684\u5B57\u6BB5\u3001\u8FD4\u56DE A \u7684\u65B9\u6CD5\u4EE5\u53CA\u5E26\u6709\u7C7B\u578B\u4E3A A \u7684\u53C2\u6570\u7684\u65B9\u6CD5\u548C\u6784\u9020\u5668\u3002\u8BBF\u95EE\u6B64\u9875\u7684\u65B9\u6CD5\u662F\uFF1A\u9996\u5148\u8F6C\u81F3\u7A0B\u5E8F\u5305\u3001\u7C7B\u6216\u63A5\u53E3\uFF0C\u7136\u540E\u5355\u51FB\u5BFC\u822A\u680F\u4E2D\u7684\u201C\u4F7F\u7528\u201D\u94FE\u63A5\u3002
|
||||
doclet.help.tree.head=\u6811 (\u7C7B\u5206\u5C42\u7ED3\u6784)
|
||||
doclet.help.tree.intro=There is a {0} page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. Classes are organized by inheritance structure starting with {1}. Interfaces do not inherit from {1}.
|
||||
doclet.help.tree.intro=\u5BF9\u4E8E\u6240\u6709\u7A0B\u5E8F\u5305\uFF0C\u90FD\u6709\u4E00\u4E2A {0} \u9875\uFF0C\u4EE5\u53CA\u6BCF\u4E2A\u7A0B\u5E8F\u5305\u7684\u5206\u5C42\u7ED3\u6784\u3002\u6BCF\u4E2A\u5206\u5C42\u7ED3\u6784\u9875\u90FD\u5305\u542B\u7C7B\u7684\u5217\u8868\u548C\u63A5\u53E3\u7684\u5217\u8868\u3002\u4ECE {1} \u5F00\u59CB\uFF0C\u6309\u7EE7\u627F\u7ED3\u6784\u5BF9\u7C7B\u8FDB\u884C\u6392\u5217\u3002\u63A5\u53E3\u4E0D\u4ECE {1} \u7EE7\u627F\u3002
|
||||
doclet.help.tree.overview=\u67E5\u770B\u201C\u6982\u89C8\u201D\u9875\u9762\u65F6, \u5355\u51FB "\u6811" \u5C06\u663E\u793A\u6240\u6709\u7A0B\u5E8F\u5305\u7684\u5206\u5C42\u7ED3\u6784\u3002
|
||||
doclet.help.tree.package=When viewing a particular package, class or interface page, clicking on "Tree" displays the hierarchy for only that package.
|
||||
doclet.help.tree.package=\u67E5\u770B\u7279\u5B9A\u7A0B\u5E8F\u5305\u3001\u7C7B\u6216\u63A5\u53E3\u9875\u65F6\uFF0C\u5355\u51FB\u201C\u6811\u201D\u5C06\u4EC5\u663E\u793A\u8BE5\u7A0B\u5E8F\u5305\u7684\u5206\u5C42\u7ED3\u6784\u3002
|
||||
doclet.help.deprecated.body={0} \u9875\u9762\u5217\u51FA\u4E86\u6240\u6709\u5DF2\u8FC7\u65F6\u7684 API\u3002\u4E00\u822C\u7531\u4E8E\u8FDB\u884C\u4E86\u6539\u8FDB\u5E76\u4E14\u901A\u5E38\u63D0\u4F9B\u4E86\u66FF\u4EE3\u7684 API, \u6240\u4EE5\u5EFA\u8BAE\u4E0D\u8981\u4F7F\u7528\u5DF2\u8FC7\u65F6\u7684 API\u3002\u5728\u5C06\u6765\u7684\u5B9E\u73B0\u8FC7\u7A0B\u4E2D, \u53EF\u80FD\u4F1A\u5220\u9664\u5DF2\u8FC7\u65F6\u7684 API\u3002
|
||||
doclet.help.index.head=\u7D22\u5F15
|
||||
doclet.help.index.body=The {0} contains an alphabetic index of all classes, interfaces, constructors, methods, and fields, as well as lists of all packages and all classes.
|
||||
doclet.help.index.body={0} \u5305\u542B\u6240\u6709\u7C7B\u3001\u63A5\u53E3\u3001\u6784\u9020\u5668\u3001\u65B9\u6CD5\u548C\u5B57\u6BB5\u7684\u6309\u5B57\u6BCD\u987A\u5E8F\u6392\u5217\u7684\u7D22\u5F15\uFF0C\u4EE5\u53CA\u6240\u6709\u7A0B\u5E8F\u5305\u548C\u6240\u6709\u7C7B\u7684\u5217\u8868\u3002
|
||||
doclet.help.frames.head=\u6846\u67B6/\u65E0\u6846\u67B6
|
||||
doclet.help.frames.body=\u8FD9\u4E9B\u94FE\u63A5\u7528\u4E8E\u663E\u793A\u548C\u9690\u85CF HTML \u6846\u67B6\u3002\u6240\u6709\u9875\u9762\u5747\u5177\u6709\u6709\u6846\u67B6\u548C\u65E0\u6846\u67B6\u4E24\u79CD\u663E\u793A\u65B9\u5F0F\u3002
|
||||
doclet.help.all_classes.body={0}\u94FE\u63A5\u663E\u793A\u6240\u6709\u7C7B\u548C\u63A5\u53E3 (\u9664\u4E86\u975E\u9759\u6001\u5D4C\u5957\u7C7B\u578B)\u3002
|
||||
doclet.help.serial_form.body=\u6BCF\u4E2A\u53EF\u5E8F\u5217\u5316\u6216\u53EF\u5916\u90E8\u5316\u7684\u7C7B\u90FD\u6709\u5176\u5E8F\u5217\u5316\u5B57\u6BB5\u548C\u65B9\u6CD5\u7684\u8BF4\u660E\u3002\u6B64\u4FE1\u606F\u5BF9\u91CD\u65B0\u5B9E\u73B0\u8005\u6709\u7528, \u800C\u5BF9\u4F7F\u7528 API \u7684\u5F00\u53D1\u8005\u5219\u6CA1\u6709\u4EC0\u4E48\u7528\u5904\u3002\u5C3D\u7BA1\u5BFC\u822A\u680F\u4E2D\u6CA1\u6709\u94FE\u63A5, \u4F46\u60A8\u53EF\u4EE5\u901A\u8FC7\u4E0B\u5217\u65B9\u5F0F\u83B7\u53D6\u6B64\u4FE1\u606F: \u8F6C\u81F3\u4EFB\u4F55\u5E8F\u5217\u5316\u7C7B, \u7136\u540E\u5355\u51FB\u7C7B\u8BF4\u660E\u7684 "\u53E6\u8BF7\u53C2\u9605" \u90E8\u5206\u4E2D\u7684 "\u5E8F\u5217\u5316\u8868\u683C"\u3002
|
||||
doclet.help.constants.body={0}\u9875\u9762\u5217\u51FA\u4E86\u9759\u6001\u6700\u7EC8\u5B57\u6BB5\u53CA\u5176\u503C\u3002
|
||||
doclet.help.footnote=This help file applies to API documentation generated by the standard doclet.
|
||||
doclet.help.footnote=\u6B64\u5E2E\u52A9\u6587\u4EF6\u9002\u7528\u4E8E\u7531\u6807\u51C6 doclet \u751F\u6210\u7684 API \u6587\u6863\u3002
|
||||
doclet.help.enum.intro=\u6BCF\u4E2A\u679A\u4E3E\u90FD\u6709\u5404\u81EA\u7684\u9875\u9762, \u5176\u4E2D\u5305\u542B\u4EE5\u4E0B\u90E8\u5206:
|
||||
doclet.help.enum.declaration=\u679A\u4E3E\u58F0\u660E
|
||||
doclet.help.enum.definition=Enum Description
|
||||
doclet.help.enum.definition=\u679A\u4E3E\u8BF4\u660E
|
||||
doclet.help.annotation_type.intro=\u6BCF\u4E2A\u6CE8\u91CA\u7C7B\u578B\u90FD\u6709\u5404\u81EA\u7684\u9875\u9762, \u5176\u4E2D\u5305\u542B\u4EE5\u4E0B\u90E8\u5206:
|
||||
doclet.help.annotation_type.declaration=Annotation Type Declaration
|
||||
doclet.help.annotation_type.description=Annotation Type Description
|
||||
doclet.help.search.head=Search
|
||||
doclet.help.search.body=You can search for definitions of modules, packages, types, fields, methods and other terms defined in the API, using some or all of the name. "Camel-case" abbreviations are supported: for example, "InpStr" will find "InputStream" and "InputStreamReader".
|
||||
doclet.help.annotation_type.declaration=\u6CE8\u91CA\u7C7B\u578B\u58F0\u660E
|
||||
doclet.help.annotation_type.description=\u6CE8\u91CA\u7C7B\u578B\u8BF4\u660E
|
||||
doclet.help.search.head=\u641C\u7D22
|
||||
doclet.help.search.body=\u53EF\u4EE5\u4F7F\u7528\u90E8\u5206\u6216\u5B8C\u6574\u540D\u79F0\u641C\u7D22\u6A21\u5757\u3001\u7A0B\u5E8F\u5305\u3001\u7C7B\u578B\u3001\u5B57\u6BB5\u3001\u65B9\u6CD5\u4EE5\u53CA\u5728 API \u4E2D\u5B9A\u4E49\u7684\u5176\u4ED6\u672F\u8BED\u7684\u5B9A\u4E49\u3002\u652F\u6301\u201C\u9A7C\u5CF0\u5927\u5C0F\u5199\u5F0F\u201D\u7F29\u5199\uFF1A\u4F8B\u5982\uFF0C"InpStr" \u5C06\u67E5\u627E "InputStream" \u548C "InputStreamReader"\u3002
|
||||
|
||||
doclet.ClassUse_Packages.that.use.0=\u4F7F\u7528{0}\u7684\u7A0B\u5E8F\u5305
|
||||
doclet.ClassUse_Uses.of.0.in.1={1}\u4E2D{0}\u7684\u4F7F\u7528
|
||||
|
3090
test/hotspot/jtreg/compiler/c1/TestLinearScanOrder.jasm
Normal file
3090
test/hotspot/jtreg/compiler/c1/TestLinearScanOrder.jasm
Normal file
File diff suppressed because it is too large
Load Diff
42
test/hotspot/jtreg/compiler/c1/TestLinearScanOrderMain.java
Normal file
42
test/hotspot/jtreg/compiler/c1/TestLinearScanOrderMain.java
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 8207355
|
||||
* @compile TestLinearScanOrder.jasm
|
||||
* @run main/othervm -Xcomp -XX:+TieredCompilation -XX:TieredStopAtLevel=1
|
||||
* -XX:CompileCommand=compileonly,compiler.c1.TestLinearScanOrder::test
|
||||
* compiler.c1.TestLinearScanOrderMain
|
||||
*/
|
||||
|
||||
package compiler.c1;
|
||||
|
||||
// WARNING: This test will not fail but time out in C1's ComputeLinearScanOrder phase
|
||||
public class TestLinearScanOrderMain {
|
||||
public static void main(String[] args) {
|
||||
if (TestLinearScanOrder.test() != 42) {
|
||||
throw new RuntimeException("Test failed");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
@ -21,12 +21,6 @@
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
super class compiler/linkage/I
|
||||
version 52:0
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
super class compiler/linkage/CallSites
|
||||
version 52:0
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
@ -54,11 +54,24 @@ class X {
|
||||
public class LinkageErrors {
|
||||
final static MethodHandles.Lookup L = MethodHandles.lookup();
|
||||
|
||||
static void test(MethodHandle mh) {
|
||||
static void testICCE(MethodHandle mh) {
|
||||
try {
|
||||
mh.invokeExact();
|
||||
throw new AssertionError("No exception thrown");
|
||||
} catch (LinkageError e) {
|
||||
} catch (IncompatibleClassChangeError e) {
|
||||
return; // expected
|
||||
} catch (AssertionError e) {
|
||||
throw e; // rethrow
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError("Unexpected exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
static void testNSME(MethodHandle mh) {
|
||||
try {
|
||||
mh.invokeExact();
|
||||
throw new AssertionError("No exception thrown");
|
||||
} catch (NoSuchMethodError e) {
|
||||
return; // expected
|
||||
} catch (AssertionError e) {
|
||||
throw e; // rethrow
|
||||
@ -93,18 +106,18 @@ public class LinkageErrors {
|
||||
MethodHandle testX3_null = testX3.bindTo(null);
|
||||
|
||||
for (int i = 0; i < 20_000; i++) {
|
||||
test(testI1_A);
|
||||
test(testI1_null);
|
||||
test(testX1_X);
|
||||
test(testX1_null);
|
||||
testNSME(testI1_A);
|
||||
testNSME(testI1_null);
|
||||
testNSME(testX1_X);
|
||||
testNSME(testX1_null);
|
||||
|
||||
test(testI2);
|
||||
test(testX2);
|
||||
testICCE(testI2);
|
||||
testICCE(testX2);
|
||||
|
||||
test(testI3_A);
|
||||
test(testI3_null);
|
||||
test(testX3_X);
|
||||
test(testX3_null);
|
||||
testICCE(testI3_A);
|
||||
testICCE(testI3_null);
|
||||
testICCE(testX3_X);
|
||||
testICCE(testX3_null);
|
||||
}
|
||||
|
||||
System.out.println("TEST PASSED");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2018, 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
|
||||
@ -85,8 +85,8 @@ public abstract class CompilerWhiteBoxTest {
|
||||
BACKEDGE_THRESHOLD = THRESHOLD = 150000;
|
||||
} else {
|
||||
THRESHOLD = COMPILE_THRESHOLD;
|
||||
BACKEDGE_THRESHOLD = COMPILE_THRESHOLD * Long.parseLong(getVMOption(
|
||||
"OnStackReplacePercentage"));
|
||||
BACKEDGE_THRESHOLD = Math.max(10000, COMPILE_THRESHOLD *
|
||||
Long.parseLong(getVMOption("OnStackReplacePercentage")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,12 @@
|
||||
* @test
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.Utils
|
||||
* @bug 8204233 8207846
|
||||
* @bug 8204233 8207846 8208691
|
||||
* @summary Add configurable option for enhanced socket IOException messages
|
||||
* @run main/othervm
|
||||
* ExceptionText
|
||||
* @run main/othervm
|
||||
* ExceptionText
|
||||
* WITHOUT_Enhanced_Text
|
||||
* @run main/othervm
|
||||
* -Djdk.includeInExceptions=
|
||||
@ -62,6 +64,7 @@ import java.net.Socket;
|
||||
import java.nio.channels.AsynchronousSocketChannel;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.security.Security;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import jdk.test.lib.Utils;
|
||||
|
||||
@ -70,20 +73,33 @@ public class ExceptionText {
|
||||
enum TestTarget {SOCKET, CHANNEL, ASYNC_CHANNEL};
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
String passOrFail = args[0];
|
||||
boolean expectEnhancedText;
|
||||
if (passOrFail.equals("expectEnhancedText")) {
|
||||
expectEnhancedText = true;
|
||||
if (args.length == 0) {
|
||||
testSecProp();
|
||||
} else {
|
||||
expectEnhancedText = false;
|
||||
String passOrFail = args[0];
|
||||
boolean expectEnhancedText;
|
||||
if (passOrFail.equals("expectEnhancedText")) {
|
||||
expectEnhancedText = true;
|
||||
} else {
|
||||
expectEnhancedText = false;
|
||||
}
|
||||
test(expectEnhancedText);
|
||||
}
|
||||
test(expectEnhancedText);
|
||||
}
|
||||
|
||||
static final InetSocketAddress dest = Utils.refusingEndpoint();
|
||||
static final String PORT = ":" + Integer.toString(dest.getPort());
|
||||
static final String HOST = dest.getHostString();
|
||||
|
||||
static void testSecProp() {
|
||||
String incInExc = Security.getProperty("jdk.includeInExceptions");
|
||||
if (incInExc != null) {
|
||||
throw new RuntimeException("Test failed: default value of " +
|
||||
"jdk.includeInExceptions security property is not null: " +
|
||||
incInExc);
|
||||
}
|
||||
}
|
||||
|
||||
static void test(boolean withProperty) {
|
||||
// Socket
|
||||
IOException e = getException(TestTarget.SOCKET);
|
||||
|
257
test/jdk/java/net/httpclient/AbstractConnectTimeout.java
Normal file
257
test/jdk/java/net/httpclient/AbstractConnectTimeout.java
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpClient.Version;
|
||||
import java.net.http.HttpConnectTimeoutException;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpRequest.BodyPublishers;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.HttpResponse.BodyHandlers;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import static java.lang.System.out;
|
||||
import static java.net.http.HttpClient.Builder.NO_PROXY;
|
||||
import static java.net.http.HttpClient.Version.HTTP_1_1;
|
||||
import static java.net.http.HttpClient.Version.HTTP_2;
|
||||
import static java.time.Duration.*;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
public abstract class AbstractConnectTimeout {
|
||||
|
||||
static final Duration NO_DURATION = null;
|
||||
|
||||
static List<List<Duration>> TIMEOUTS = List.of(
|
||||
// connectTimeout HttpRequest timeout
|
||||
Arrays.asList( NO_DURATION, ofSeconds(1) ),
|
||||
Arrays.asList( NO_DURATION, ofMillis(100) ),
|
||||
Arrays.asList( NO_DURATION, ofNanos(99) ),
|
||||
Arrays.asList( NO_DURATION, ofNanos(1) ),
|
||||
|
||||
Arrays.asList( ofSeconds(1), NO_DURATION ),
|
||||
Arrays.asList( ofMillis(100), NO_DURATION ),
|
||||
Arrays.asList( ofNanos(99), NO_DURATION ),
|
||||
Arrays.asList( ofNanos(1), NO_DURATION ),
|
||||
|
||||
Arrays.asList( ofSeconds(1), ofMinutes(1) ),
|
||||
Arrays.asList( ofMillis(100), ofMinutes(1) ),
|
||||
Arrays.asList( ofNanos(99), ofMinutes(1) ),
|
||||
Arrays.asList( ofNanos(1), ofMinutes(1) )
|
||||
);
|
||||
|
||||
static final List<String> METHODS = List.of("GET", "POST");
|
||||
static final List<Version> VERSIONS = List.of(HTTP_2, HTTP_1_1);
|
||||
static final List<String> SCHEMES = List.of("https", "http");
|
||||
|
||||
@DataProvider(name = "variants")
|
||||
public Object[][] variants() {
|
||||
List<Object[]> l = new ArrayList<>();
|
||||
for (List<Duration> timeouts : TIMEOUTS) {
|
||||
Duration connectTimeout = timeouts.get(0);
|
||||
Duration requestTimeout = timeouts.get(1);
|
||||
for (String method: METHODS) {
|
||||
for (String scheme : SCHEMES) {
|
||||
for (Version requestVersion : VERSIONS) {
|
||||
l.add(new Object[] {requestVersion, scheme, method, connectTimeout, requestTimeout});
|
||||
}}}}
|
||||
return l.stream().toArray(Object[][]::new);
|
||||
}
|
||||
|
||||
static final ProxySelector EXAMPLE_DOT_COM_PROXY = ProxySelector.of(
|
||||
InetSocketAddress.createUnresolved("example.com", 8080));
|
||||
|
||||
//@Test(dataProvider = "variants")
|
||||
protected void timeoutNoProxySync(Version requestVersion,
|
||||
String scheme,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout)
|
||||
throws Exception
|
||||
{
|
||||
timeoutSync(requestVersion, scheme, method, connectTimeout, requestTimeout, NO_PROXY);
|
||||
}
|
||||
|
||||
//@Test(dataProvider = "variants")
|
||||
protected void timeoutWithProxySync(Version requestVersion,
|
||||
String scheme,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout)
|
||||
throws Exception
|
||||
{
|
||||
timeoutSync(requestVersion, scheme, method, connectTimeout, requestTimeout, EXAMPLE_DOT_COM_PROXY);
|
||||
}
|
||||
|
||||
private void timeoutSync(Version requestVersion,
|
||||
String scheme,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout,
|
||||
ProxySelector proxy)
|
||||
throws Exception
|
||||
{
|
||||
out.printf("%ntimeoutSync(requestVersion=%s, scheme=%s, method=%s,"
|
||||
+ " connectTimeout=%s, requestTimeout=%s, proxy=%s)%n",
|
||||
requestVersion, scheme, method, connectTimeout, requestTimeout, proxy);
|
||||
|
||||
HttpClient client = newClient(connectTimeout, proxy);
|
||||
HttpRequest request = newRequest(scheme, requestVersion, method, requestTimeout);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
out.printf("iteration %d%n", i);
|
||||
long startTime = System.nanoTime();
|
||||
try {
|
||||
HttpResponse<?> resp = client.send(request, BodyHandlers.ofString());
|
||||
printResponse(resp);
|
||||
fail("Unexpected response: " + resp);
|
||||
} catch (HttpConnectTimeoutException expected) { // blocking thread-specific exception
|
||||
long elapsedTime = NANOSECONDS.toMillis(System.nanoTime() - startTime);
|
||||
out.printf("Client: received in %d millis%n", elapsedTime);
|
||||
assertExceptionTypeAndCause(expected.getCause());
|
||||
} catch (ConnectException e) {
|
||||
long elapsedTime = NANOSECONDS.toMillis(System.nanoTime() - startTime);
|
||||
out.printf("Client: received in %d millis%n", elapsedTime);
|
||||
Throwable t = e.getCause().getCause(); // blocking thread-specific exception
|
||||
if (!(t instanceof NoRouteToHostException)) { // tolerate only NRTHE
|
||||
e.printStackTrace(out);
|
||||
fail("Unexpected exception:" + e);
|
||||
} else {
|
||||
out.printf("Caught ConnectException with NoRouteToHostException"
|
||||
+ " cause: %s - skipping%n", t.getCause());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//@Test(dataProvider = "variants")
|
||||
protected void timeoutNoProxyAsync(Version requestVersion,
|
||||
String scheme,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout) {
|
||||
timeoutAsync(requestVersion, scheme, method, connectTimeout, requestTimeout, NO_PROXY);
|
||||
}
|
||||
|
||||
//@Test(dataProvider = "variants")
|
||||
protected void timeoutWithProxyAsync(Version requestVersion,
|
||||
String scheme,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout) {
|
||||
timeoutAsync(requestVersion, scheme, method, connectTimeout, requestTimeout, EXAMPLE_DOT_COM_PROXY);
|
||||
}
|
||||
|
||||
private void timeoutAsync(Version requestVersion,
|
||||
String scheme,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout,
|
||||
ProxySelector proxy) {
|
||||
out.printf("%ntimeoutAsync(requestVersion=%s, scheme=%s, method=%s, "
|
||||
+ "connectTimeout=%s, requestTimeout=%s, proxy=%s)%n",
|
||||
requestVersion, scheme, method, connectTimeout, requestTimeout, proxy);
|
||||
|
||||
HttpClient client = newClient(connectTimeout, proxy);
|
||||
HttpRequest request = newRequest(scheme, requestVersion, method, requestTimeout);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
out.printf("iteration %d%n", i);
|
||||
long startTime = System.nanoTime();
|
||||
try {
|
||||
HttpResponse<?> resp = client.sendAsync(request, BodyHandlers.ofString()).join();
|
||||
printResponse(resp);
|
||||
fail("Unexpected response: " + resp);
|
||||
} catch (CompletionException e) {
|
||||
long elapsedTime = NANOSECONDS.toMillis(System.nanoTime() - startTime);
|
||||
out.printf("Client: received in %d millis%n", elapsedTime);
|
||||
Throwable t = e.getCause();
|
||||
if (t instanceof ConnectException &&
|
||||
t.getCause() instanceof NoRouteToHostException) { // tolerate only NRTHE
|
||||
out.printf("Caught ConnectException with NoRouteToHostException"
|
||||
+ " cause: %s - skipping%n", t.getCause());
|
||||
} else {
|
||||
assertExceptionTypeAndCause(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static HttpClient newClient(Duration connectTimeout, ProxySelector proxy) {
|
||||
HttpClient.Builder builder = HttpClient.newBuilder().proxy(proxy);
|
||||
if (connectTimeout != NO_DURATION)
|
||||
builder.connectTimeout(connectTimeout);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static HttpRequest newRequest(String scheme,
|
||||
Version reqVersion,
|
||||
String method,
|
||||
Duration requestTimeout) {
|
||||
// Resolvable address. Most tested environments just ignore the TCP SYN,
|
||||
// or occasionally return ICMP no route to host
|
||||
URI uri = URI.create(scheme +"://example.com:81/");
|
||||
HttpRequest.Builder reqBuilder = HttpRequest.newBuilder(uri);
|
||||
reqBuilder = reqBuilder.version(reqVersion);
|
||||
switch (method) {
|
||||
case "GET" : reqBuilder.GET(); break;
|
||||
case "POST" : reqBuilder.POST(BodyPublishers.noBody()); break;
|
||||
default: throw new AssertionError("Unknown method:" + method);
|
||||
}
|
||||
if (requestTimeout != NO_DURATION)
|
||||
reqBuilder.timeout(requestTimeout);
|
||||
return reqBuilder.build();
|
||||
}
|
||||
|
||||
static void assertExceptionTypeAndCause(Throwable t) {
|
||||
if (!(t instanceof HttpConnectTimeoutException)) {
|
||||
t.printStackTrace(out);
|
||||
fail("Expected HttpConnectTimeoutException, got:" + t);
|
||||
}
|
||||
Throwable connEx = t.getCause();
|
||||
if (!(connEx instanceof ConnectException)) {
|
||||
t.printStackTrace(out);
|
||||
fail("Expected ConnectException cause in:" + connEx);
|
||||
}
|
||||
out.printf("Caught expected HttpConnectTimeoutException with ConnectException"
|
||||
+ " cause: %n%s%n%s%n", t, connEx);
|
||||
final String EXPECTED_MESSAGE = "HTTP connect timed out"; // impl dependent
|
||||
if (!connEx.getMessage().equals(EXPECTED_MESSAGE))
|
||||
fail("Expected: \"" + EXPECTED_MESSAGE + "\", got: \"" + connEx.getMessage() + "\"");
|
||||
|
||||
}
|
||||
|
||||
static void printResponse(HttpResponse<?> response) {
|
||||
out.println("Unexpected response: " + response);
|
||||
out.println("Headers: " + response.headers());
|
||||
out.println("Body: " + response.body());
|
||||
}
|
||||
}
|
@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpClient.Version;
|
||||
import java.net.http.HttpConnectTimeoutException;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpRequest.BodyPublishers;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.HttpResponse.BodyHandlers;
|
||||
import org.testng.annotations.AfterTest;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import static java.lang.String.format;
|
||||
import static java.lang.System.out;
|
||||
import static java.net.http.HttpClient.Builder.NO_PROXY;
|
||||
import static java.net.http.HttpClient.Version.HTTP_1_1;
|
||||
import static java.net.http.HttpClient.Version.HTTP_2;
|
||||
import static java.time.Duration.*;
|
||||
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
public abstract class AbstractConnectTimeoutHandshake {
|
||||
|
||||
// The number of iterations each testXXXClient performs.
|
||||
static final int TIMES = 2;
|
||||
|
||||
Server server;
|
||||
URI httpsURI;
|
||||
|
||||
static final Duration NO_DURATION = null;
|
||||
|
||||
static List<List<Duration>> TIMEOUTS = List.of(
|
||||
// connectTimeout HttpRequest timeout
|
||||
Arrays.asList( NO_DURATION, ofSeconds(1) ),
|
||||
Arrays.asList( NO_DURATION, ofSeconds(2) ),
|
||||
Arrays.asList( NO_DURATION, ofMillis(500) ),
|
||||
|
||||
Arrays.asList( ofSeconds(1), NO_DURATION ),
|
||||
Arrays.asList( ofSeconds(2), NO_DURATION ),
|
||||
Arrays.asList( ofMillis(500), NO_DURATION ),
|
||||
|
||||
Arrays.asList( ofSeconds(1), ofMinutes(1) ),
|
||||
Arrays.asList( ofSeconds(2), ofMinutes(1) ),
|
||||
Arrays.asList( ofMillis(500), ofMinutes(1) )
|
||||
);
|
||||
|
||||
static final List<String> METHODS = List.of("GET" , "POST");
|
||||
static final List<Version> VERSIONS = List.of(HTTP_2, HTTP_1_1);
|
||||
|
||||
@DataProvider(name = "variants")
|
||||
public Object[][] variants() {
|
||||
List<Object[]> l = new ArrayList<>();
|
||||
for (List<Duration> timeouts : TIMEOUTS) {
|
||||
Duration connectTimeout = timeouts.get(0);
|
||||
Duration requestTimeout = timeouts.get(1);
|
||||
for (String method: METHODS) {
|
||||
for (Version requestVersion : VERSIONS) {
|
||||
l.add(new Object[] {requestVersion, method, connectTimeout, requestTimeout});
|
||||
}}}
|
||||
return l.stream().toArray(Object[][]::new);
|
||||
}
|
||||
|
||||
//@Test(dataProvider = "variants")
|
||||
protected void timeoutSync(Version requestVersion,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout)
|
||||
throws Exception
|
||||
{
|
||||
out.printf("%n--- timeoutSync requestVersion=%s, method=%s, "
|
||||
+ "connectTimeout=%s, requestTimeout=%s ---%n",
|
||||
requestVersion, method, connectTimeout, requestTimeout);
|
||||
HttpClient client = newClient(connectTimeout);
|
||||
HttpRequest request = newRequest(requestVersion, method, requestTimeout);
|
||||
|
||||
for (int i = 0; i < TIMES; i++) {
|
||||
out.printf("iteration %d%n", i);
|
||||
long startTime = System.nanoTime();
|
||||
try {
|
||||
HttpResponse<String> resp = client.send(request, BodyHandlers.ofString());
|
||||
printResponse(resp);
|
||||
fail("Unexpected response: " + resp);
|
||||
} catch (HttpConnectTimeoutException expected) {
|
||||
long elapsedTime = NANOSECONDS.toMillis(System.nanoTime() - startTime);
|
||||
out.printf("Client: received in %d millis%n", elapsedTime);
|
||||
out.printf("Client: caught expected HttpConnectTimeoutException: %s%n", expected);
|
||||
checkExceptionOrCause(ConnectException.class, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//@Test(dataProvider = "variants")
|
||||
protected void timeoutAsync(Version requestVersion,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout) {
|
||||
out.printf("%n--- timeoutAsync requestVersion=%s, method=%s, "
|
||||
+ "connectTimeout=%s, requestTimeout=%s ---%n",
|
||||
requestVersion, method, connectTimeout, requestTimeout);
|
||||
HttpClient client = newClient(connectTimeout);
|
||||
HttpRequest request = newRequest(requestVersion, method, requestTimeout);
|
||||
|
||||
for (int i = 0; i < TIMES; i++) {
|
||||
out.printf("iteration %d%n", i);
|
||||
long startTime = System.nanoTime();
|
||||
CompletableFuture<HttpResponse<String>> cf =
|
||||
client.sendAsync(request, BodyHandlers.ofString());
|
||||
try {
|
||||
HttpResponse<String> resp = cf.join();
|
||||
printResponse(resp);
|
||||
fail("Unexpected response: " + resp);
|
||||
} catch (CompletionException ce) {
|
||||
long elapsedTime = NANOSECONDS.toMillis(System.nanoTime() - startTime);
|
||||
out.printf("Client: received in %d millis%n", elapsedTime);
|
||||
Throwable expected = ce.getCause();
|
||||
if (expected instanceof HttpConnectTimeoutException) {
|
||||
out.printf("Client: caught expected HttpConnectTimeoutException: %s%n", expected);
|
||||
checkExceptionOrCause(ConnectException.class, expected);
|
||||
} else {
|
||||
out.printf("Client: caught UNEXPECTED exception: %s%n", expected);
|
||||
throw ce;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static HttpClient newClient(Duration connectTimeout) {
|
||||
HttpClient.Builder builder = HttpClient.newBuilder().proxy(NO_PROXY);
|
||||
if (connectTimeout != NO_DURATION)
|
||||
builder.connectTimeout(connectTimeout);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
HttpRequest newRequest(Version reqVersion,
|
||||
String method,
|
||||
Duration requestTimeout) {
|
||||
HttpRequest.Builder reqBuilder = HttpRequest.newBuilder(httpsURI);
|
||||
reqBuilder = reqBuilder.version(reqVersion);
|
||||
switch (method) {
|
||||
case "GET" : reqBuilder.GET(); break;
|
||||
case "POST" : reqBuilder.POST(BodyPublishers.noBody()); break;
|
||||
default: throw new AssertionError("Unknown method:" + method);
|
||||
}
|
||||
if (requestTimeout != NO_DURATION)
|
||||
reqBuilder.timeout(requestTimeout);
|
||||
return reqBuilder.build();
|
||||
}
|
||||
|
||||
static void checkExceptionOrCause(Class<? extends Throwable> clazz, Throwable t) {
|
||||
final Throwable original = t;
|
||||
do {
|
||||
if (clazz.isInstance(t)) {
|
||||
System.out.println("Found expected exception/cause: " + t);
|
||||
return; // found
|
||||
}
|
||||
} while ((t = t.getCause()) != null);
|
||||
original.printStackTrace(System.out);
|
||||
throw new RuntimeException("Expected " + clazz + "in " + original);
|
||||
}
|
||||
|
||||
static void printResponse(HttpResponse<?> response) {
|
||||
out.println("Unexpected response: " + response);
|
||||
out.println("Headers: " + response.headers());
|
||||
out.println("Body: " + response.body());
|
||||
}
|
||||
|
||||
// -- Infrastructure
|
||||
|
||||
static String serverAuthority(Server server) {
|
||||
return InetAddress.getLoopbackAddress().getHostName() + ":"
|
||||
+ server.getPort();
|
||||
}
|
||||
|
||||
@BeforeTest
|
||||
public void setup() throws Exception {
|
||||
server = new Server();
|
||||
httpsURI = URI.create("https://" + serverAuthority(server) + "/foo");
|
||||
out.println("HTTPS URI: " + httpsURI);
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
public void teardown() throws Exception {
|
||||
server.close();
|
||||
out.printf("%n--- teardown ---%n");
|
||||
|
||||
int numClientConnections = variants().length * TIMES;
|
||||
int serverCount = server.count;
|
||||
out.printf("Client made %d connections.%n", numClientConnections);
|
||||
out.printf("Server received %d connections.%n", serverCount);
|
||||
|
||||
// This is usually the case, but not always, do not assert. Remains
|
||||
// as an informative message only.
|
||||
//if (numClientConnections != serverCount)
|
||||
// fail(format("[numTests: %d] != [serverCount: %d]",
|
||||
// numClientConnections, serverCount));
|
||||
}
|
||||
|
||||
/**
|
||||
* Emulates a server-side, using plain cleartext Sockets, that just reads
|
||||
* initial client hello and does nothing more.
|
||||
*/
|
||||
static class Server extends Thread implements AutoCloseable {
|
||||
private final ServerSocket ss;
|
||||
private volatile boolean closed;
|
||||
volatile int count;
|
||||
|
||||
Server() throws IOException {
|
||||
super("Server");
|
||||
ss = new ServerSocket();
|
||||
ss.setReuseAddress(false);
|
||||
ss.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
|
||||
this.start();
|
||||
}
|
||||
|
||||
int getPort() {
|
||||
return ss.getLocalPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (closed)
|
||||
return;
|
||||
closed = true;
|
||||
try {
|
||||
ss.close();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Unexpected", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!closed) {
|
||||
try (Socket s = ss.accept()) {
|
||||
count++;
|
||||
out.println("Server: accepted new connection");
|
||||
InputStream is = new BufferedInputStream(s.getInputStream());
|
||||
|
||||
out.println("Server: starting to read");
|
||||
while (is.read() != -1) ;
|
||||
|
||||
out.println("Server: closing connection");
|
||||
s.close(); // close without giving any reply
|
||||
} catch (IOException e) {
|
||||
if (!closed)
|
||||
out.println("UNEXPECTED " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
import java.net.http.HttpClient.Version;
|
||||
import java.time.Duration;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Tests connection timeouts during SSL handshake
|
||||
* @bug 8208391
|
||||
* @run testng/othervm ConnectTimeoutHandshakeAsync
|
||||
*/
|
||||
|
||||
public class ConnectTimeoutHandshakeAsync
|
||||
extends AbstractConnectTimeoutHandshake
|
||||
{
|
||||
@Test(dataProvider = "variants")
|
||||
@Override
|
||||
public void timeoutAsync(Version requestVersion,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout) {
|
||||
super.timeoutAsync(requestVersion, method, connectTimeout, requestTimeout);
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
import java.net.http.HttpClient.Version;
|
||||
import java.time.Duration;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Tests connection timeouts during SSL handshake
|
||||
* @bug 8208391
|
||||
* @run testng/othervm ConnectTimeoutHandshakeSync
|
||||
*/
|
||||
|
||||
public class ConnectTimeoutHandshakeSync
|
||||
extends AbstractConnectTimeoutHandshake
|
||||
{
|
||||
@Test(dataProvider = "variants")
|
||||
@Override
|
||||
public void timeoutSync(Version requestVersion,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout)
|
||||
throws Exception
|
||||
{
|
||||
super.timeoutSync(requestVersion, method, connectTimeout, requestTimeout);
|
||||
}
|
||||
}
|
47
test/jdk/java/net/httpclient/ConnectTimeoutNoProxyAsync.java
Normal file
47
test/jdk/java/net/httpclient/ConnectTimeoutNoProxyAsync.java
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
import java.net.http.HttpClient.Version;
|
||||
import java.time.Duration;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Tests for connection related timeouts
|
||||
* @bug 8208391
|
||||
* @run testng/othervm ConnectTimeoutNoProxyAsync
|
||||
*/
|
||||
|
||||
public class ConnectTimeoutNoProxyAsync extends AbstractConnectTimeout {
|
||||
|
||||
@Test(dataProvider = "variants")
|
||||
@Override
|
||||
public void timeoutNoProxyAsync(Version requestVersion,
|
||||
String scheme,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestduration)
|
||||
{
|
||||
super.timeoutNoProxyAsync(requestVersion, scheme, method, connectTimeout, requestduration);
|
||||
}
|
||||
}
|
48
test/jdk/java/net/httpclient/ConnectTimeoutNoProxySync.java
Normal file
48
test/jdk/java/net/httpclient/ConnectTimeoutNoProxySync.java
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
import java.net.http.HttpClient.Version;
|
||||
import java.time.Duration;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Tests for connection related timeouts
|
||||
* @bug 8208391
|
||||
* @run testng/othervm ConnectTimeoutNoProxySync
|
||||
*/
|
||||
|
||||
public class ConnectTimeoutNoProxySync extends AbstractConnectTimeout {
|
||||
|
||||
@Test(dataProvider = "variants")
|
||||
@Override
|
||||
public void timeoutNoProxySync(Version requestVersion,
|
||||
String scheme,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout)
|
||||
throws Exception
|
||||
{
|
||||
super.timeoutNoProxySync(requestVersion, scheme, method, connectTimeout, requestTimeout);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
import java.net.http.HttpClient.Version;
|
||||
import java.time.Duration;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Tests for connection related timeouts
|
||||
* @bug 8208391
|
||||
* @run testng/othervm ConnectTimeoutWithProxyAsync
|
||||
*/
|
||||
|
||||
public class ConnectTimeoutWithProxyAsync extends AbstractConnectTimeout {
|
||||
|
||||
@Test(dataProvider = "variants")
|
||||
@Override
|
||||
public void timeoutWithProxyAsync(Version requestVersion,
|
||||
String scheme,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout)
|
||||
{
|
||||
super.timeoutWithProxyAsync(requestVersion, scheme, method, connectTimeout, requestTimeout);
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
import java.net.http.HttpClient.Version;
|
||||
import java.time.Duration;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Tests for connection related timeouts
|
||||
* @bug 8208391
|
||||
* @run testng/othervm ConnectTimeoutWithProxySync
|
||||
*/
|
||||
|
||||
public class ConnectTimeoutWithProxySync extends AbstractConnectTimeout {
|
||||
|
||||
@Test(dataProvider = "variants")
|
||||
@Override
|
||||
public void timeoutWithProxySync(Version requestVersion,
|
||||
String scheme,
|
||||
String method,
|
||||
Duration connectTimeout,
|
||||
Duration requestTimeout)
|
||||
throws Exception
|
||||
{
|
||||
super.timeoutWithProxySync(requestVersion, scheme, method, connectTimeout, requestTimeout);
|
||||
}
|
||||
}
|
@ -50,6 +50,7 @@ import java.net.http.HttpClient.Redirect;
|
||||
import java.net.http.HttpClient.Version;
|
||||
import jdk.testlibrary.SimpleSSLContext;
|
||||
import org.testng.annotations.Test;
|
||||
import static java.time.Duration.*;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/*
|
||||
@ -74,6 +75,7 @@ public class HttpClientBuilderTest {
|
||||
// Empty optionals and defaults
|
||||
assertFalse(client.authenticator().isPresent());
|
||||
assertFalse(client.cookieHandler().isPresent());
|
||||
assertFalse(client.connectTimeout().isPresent());
|
||||
assertFalse(client.executor().isPresent());
|
||||
assertFalse(client.proxy().isPresent());
|
||||
assertTrue(client.sslParameters() != null);
|
||||
@ -88,6 +90,7 @@ public class HttpClientBuilderTest {
|
||||
HttpClient.Builder builder = HttpClient.newBuilder();
|
||||
assertThrows(NPE, () -> builder.authenticator(null));
|
||||
assertThrows(NPE, () -> builder.cookieHandler(null));
|
||||
assertThrows(NPE, () -> builder.connectTimeout(null));
|
||||
assertThrows(NPE, () -> builder.executor(null));
|
||||
assertThrows(NPE, () -> builder.proxy(null));
|
||||
assertThrows(NPE, () -> builder.sslParameters(null));
|
||||
@ -128,6 +131,26 @@ public class HttpClientBuilderTest {
|
||||
assertTrue(builder.build().cookieHandler().get() == c);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectTimeout() {
|
||||
HttpClient.Builder builder = HttpClient.newBuilder();
|
||||
Duration a = Duration.ofSeconds(5);
|
||||
builder.connectTimeout(a);
|
||||
assertTrue(builder.build().connectTimeout().get() == a);
|
||||
Duration b = Duration.ofMinutes(1);
|
||||
builder.connectTimeout(b);
|
||||
assertTrue(builder.build().connectTimeout().get() == b);
|
||||
assertThrows(NPE, () -> builder.cookieHandler(null));
|
||||
Duration c = Duration.ofHours(100);
|
||||
builder.connectTimeout(c);
|
||||
assertTrue(builder.build().connectTimeout().get() == c);
|
||||
|
||||
assertThrows(IAE, () -> builder.connectTimeout(ZERO));
|
||||
assertThrows(IAE, () -> builder.connectTimeout(ofSeconds(0)));
|
||||
assertThrows(IAE, () -> builder.connectTimeout(ofSeconds(-1)));
|
||||
assertThrows(IAE, () -> builder.connectTimeout(ofNanos(-100)));
|
||||
}
|
||||
|
||||
static class TestExecutor implements Executor {
|
||||
public void execute(Runnable r) { }
|
||||
}
|
||||
@ -292,6 +315,7 @@ public class HttpClientBuilderTest {
|
||||
|
||||
static class MockHttpClient extends HttpClient {
|
||||
@Override public Optional<CookieHandler> cookieHandler() { return null; }
|
||||
@Override public Optional<Duration> connectTimeout() { return null; }
|
||||
@Override public Redirect followRedirects() { return null; }
|
||||
@Override public Optional<ProxySelector> proxy() { return null; }
|
||||
@Override public SSLContext sslContext() { return null; }
|
||||
|
@ -164,6 +164,7 @@ public class TimeoutBasic {
|
||||
throw new RuntimeException("Unexpected response: " + resp.statusCode());
|
||||
} catch (CompletionException e) {
|
||||
if (!(e.getCause() instanceof HttpTimeoutException)) {
|
||||
e.printStackTrace(out);
|
||||
throw new RuntimeException("Unexpected exception: " + e.getCause());
|
||||
} else {
|
||||
out.println("Caught expected timeout: " + e.getCause());
|
||||
|
@ -64,6 +64,7 @@ public class JavadocExamples {
|
||||
HttpClient client = HttpClient.newBuilder()
|
||||
.version(Version.HTTP_1_1)
|
||||
.followRedirects(Redirect.NORMAL)
|
||||
.connectTimeout(Duration.ofSeconds(20))
|
||||
.proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
|
||||
.authenticator(Authenticator.getDefault())
|
||||
.build();
|
||||
@ -74,7 +75,7 @@ public class JavadocExamples {
|
||||
//Asynchronous Example
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create("https://foo.com/"))
|
||||
.timeout(Duration.ofMinutes(1))
|
||||
.timeout(Duration.ofMinutes(2))
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(BodyPublishers.ofFile(Paths.get("file.json")))
|
||||
.build();
|
||||
|
@ -27,6 +27,7 @@ import java.io.IOException;
|
||||
import java.net.Authenticator;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.ProxySelector;
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
@ -50,6 +51,11 @@ public class DelegatingHttpClient extends HttpClient {
|
||||
return client.cookieHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Duration> connectTimeout() {
|
||||
return client.connectTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Redirect followRedirects() {
|
||||
return client.followRedirects();
|
||||
|
@ -31,6 +31,7 @@ import java.net.InetSocketAddress;
|
||||
import java.net.ProxySelector;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@ -284,7 +285,8 @@ public class ConnectionPoolTest {
|
||||
|
||||
// All these throw errors
|
||||
@Override public HttpPublisher publisher() {return error();}
|
||||
@Override public CompletableFuture<Void> connectAsync() {return error();}
|
||||
@Override public CompletableFuture<Void> connectAsync(Exchange<?> e) {return error();}
|
||||
@Override public CompletableFuture<Void> finishConnect() {return error();}
|
||||
@Override SocketChannel channel() {return error();}
|
||||
@Override
|
||||
FlowTube getConnectionFlow() {return flow;}
|
||||
@ -296,6 +298,7 @@ public class ConnectionPoolTest {
|
||||
}
|
||||
final ConnectionPool pool;
|
||||
@Override public Optional<CookieHandler> cookieHandler() {return error();}
|
||||
@Override public Optional<Duration> connectTimeout() {return error();}
|
||||
@Override public HttpClient.Redirect followRedirects() {return error();}
|
||||
@Override public Optional<ProxySelector> proxy() {return error();}
|
||||
@Override public SSLContext sslContext() {return error();}
|
||||
|
390
test/jdk/javax/net/ssl/TLSCommon/ConcurrentClientAccessTest.java
Normal file
390
test/jdk/javax/net/ssl/TLSCommon/ConcurrentClientAccessTest.java
Normal file
@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Security;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLServerSocket;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8208496
|
||||
* @summary Test to verify concurrent behavior of TLS.
|
||||
* @run main/othervm ConcurrentClientAccessTest
|
||||
*/
|
||||
public class ConcurrentClientAccessTest {
|
||||
|
||||
private static final int THREADS = 50;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
Security.setProperty("jdk.tls.disabledAlgorithms", "");
|
||||
for (String tlsProtocol : new String[]{"TLSv1.3", "TLSv1.2",
|
||||
"TLSv1.1", "TLSv1"}) {
|
||||
System.out.printf("Protocol: %s%n", tlsProtocol);
|
||||
CountDownLatch tillServerReady = new CountDownLatch(1);
|
||||
Server server = new Server(tlsProtocol, tillServerReady);
|
||||
server.start();
|
||||
|
||||
// Wait till server is ready to accept connection.
|
||||
tillServerReady.await();
|
||||
CountDownLatch tillClientComplete = new CountDownLatch(THREADS);
|
||||
ExecutorService executor = null;
|
||||
try {
|
||||
executor = newExecutorService();
|
||||
// Run 50 TLS clients for concurrent access to TLS Port.
|
||||
for (int count = 1; count <= THREADS; count++) {
|
||||
Client client = new Client(tlsProtocol, server.port,
|
||||
tillClientComplete);
|
||||
executor.execute(client);
|
||||
// If Client has any Exception indicates problem
|
||||
if (client.exception != null) {
|
||||
throw new RuntimeException(client.exception);
|
||||
}
|
||||
}
|
||||
// Wait till all client thread complete execution
|
||||
tillClientComplete.await();
|
||||
System.out.println("All client processed successfully.");
|
||||
} finally {
|
||||
if (executor != null) {
|
||||
executor.shutdown();
|
||||
}
|
||||
// Fail Safe: Shutdown the server
|
||||
server.stopServer();
|
||||
}
|
||||
// If Sever has any Exception indicates problem
|
||||
if (server.exception != null) {
|
||||
throw new RuntimeException(server.exception);
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Server implements Runnable {
|
||||
|
||||
private volatile int port = 0;
|
||||
private final String tlsProtocol;
|
||||
private final CountDownLatch tillServerReady;
|
||||
private volatile Exception exception;
|
||||
private SSLServerSocket sslServerSocket;
|
||||
|
||||
public Server(String tlsProtocol, CountDownLatch tillServerReady) {
|
||||
this.tlsProtocol = tlsProtocol;
|
||||
this.tillServerReady = tillServerReady;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
|
||||
ExecutorService executor = null;
|
||||
try {
|
||||
executor = newExecutorService();
|
||||
executor.execute(this);
|
||||
} finally {
|
||||
if (executor != null) {
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Define the server side operation.
|
||||
*/
|
||||
void doServerSide() throws Exception {
|
||||
|
||||
SSLContext ctx = getSSLContext(tlsProtocol);
|
||||
SSLServerSocketFactory sslssf = ctx.getServerSocketFactory();
|
||||
sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(port);
|
||||
port = sslServerSocket.getLocalPort();
|
||||
System.out.println("Server listening on port: " + port);
|
||||
sslServerSocket.setEnabledProtocols(new String[]{tlsProtocol});
|
||||
// ServerSocket will timeout after waiting for 20 seconds
|
||||
// before accepting a connection
|
||||
sslServerSocket.setSoTimeout(20000);
|
||||
// Signal Client, the server is ready to accept client request.
|
||||
tillServerReady.countDown();
|
||||
while (sslServerSocket != null && !sslServerSocket.isClosed()) {
|
||||
try (SSLSocket sslSocket
|
||||
= (SSLSocket) sslServerSocket.accept()) {
|
||||
try (InputStream sslIS = sslSocket.getInputStream();
|
||||
OutputStream sslOS
|
||||
= sslSocket.getOutputStream();) {
|
||||
sslIS.read();
|
||||
sslOS.write(85);
|
||||
sslOS.flush();
|
||||
}
|
||||
} catch (SocketTimeoutException | SocketException e) {
|
||||
// Let the server exit
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
doServerSide();
|
||||
} catch (Exception e) {
|
||||
this.exception = e;
|
||||
} finally {
|
||||
// Stop server
|
||||
stopServer();
|
||||
}
|
||||
}
|
||||
|
||||
public void stopServer() {
|
||||
if (sslServerSocket != null && !sslServerSocket.isClosed()) {
|
||||
System.out.println("Stopping Server.");
|
||||
try {
|
||||
sslServerSocket.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Define the client side of the test.
|
||||
*/
|
||||
public static class Client implements Runnable {
|
||||
|
||||
private final int serverPort;
|
||||
private final String tlsProtocol;
|
||||
private final CountDownLatch tillClientComplete;
|
||||
private volatile Exception exception;
|
||||
|
||||
public Client(String tlsProtocol, int serverPort,
|
||||
CountDownLatch tillClientComplete) {
|
||||
this.tlsProtocol = tlsProtocol;
|
||||
this.serverPort = serverPort;
|
||||
this.tillClientComplete = tillClientComplete;
|
||||
}
|
||||
|
||||
void doClientSide() throws Exception {
|
||||
|
||||
SSLContext ctx = getSSLContext(this.tlsProtocol);
|
||||
SSLSocketFactory sslsf = ctx.getSocketFactory();
|
||||
try (SSLSocket sslSocket
|
||||
= (SSLSocket) sslsf.createSocket("localhost", serverPort)) {
|
||||
sslSocket.setEnabledProtocols(new String[]{this.tlsProtocol});
|
||||
try (InputStream sslIS = sslSocket.getInputStream();
|
||||
OutputStream sslOS = sslSocket.getOutputStream()) {
|
||||
sslOS.write(86);
|
||||
sslOS.flush();
|
||||
sslIS.read();
|
||||
}
|
||||
} finally {
|
||||
tillClientComplete.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
doClientSide();
|
||||
} catch (Exception e) {
|
||||
// Print the exception for debug purpose.
|
||||
e.printStackTrace(System.out);
|
||||
this.exception = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the ssl context
|
||||
protected static SSLContext getSSLContext(String tlsProtocol)
|
||||
throws Exception {
|
||||
|
||||
// Generate certificate from cert string
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
|
||||
// Create a key store
|
||||
KeyStore ts = KeyStore.getInstance("PKCS12");
|
||||
KeyStore ks = KeyStore.getInstance("PKCS12");
|
||||
ts.load(null, null);
|
||||
ks.load(null, null);
|
||||
char passphrase[] = "passphrase".toCharArray();
|
||||
|
||||
// Import the trusted cert
|
||||
ts.setCertificateEntry("trusted-cert-"
|
||||
+ KeyType.rsa_pkcs1_sha256.getKeyType(),
|
||||
cf.generateCertificate(new ByteArrayInputStream(
|
||||
KeyType.rsa_pkcs1_sha256.getTrustedCert().getBytes())));
|
||||
|
||||
boolean hasKeyMaterials = KeyType.rsa_pkcs1_sha256.getEndCert() != null
|
||||
&& KeyType.rsa_pkcs1_sha256.getPrivateKey() != null;
|
||||
if (hasKeyMaterials) {
|
||||
|
||||
// Generate the private key.
|
||||
PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
|
||||
Base64.getMimeDecoder().decode(
|
||||
KeyType.rsa_pkcs1_sha256.getPrivateKey()));
|
||||
KeyFactory kf = KeyFactory.getInstance(
|
||||
KeyType.rsa_pkcs1_sha256.getKeyType());
|
||||
PrivateKey priKey = kf.generatePrivate(priKeySpec);
|
||||
|
||||
// Generate certificate chain
|
||||
Certificate keyCert = cf.generateCertificate(
|
||||
new ByteArrayInputStream(
|
||||
KeyType.rsa_pkcs1_sha256.getEndCert().getBytes()));
|
||||
Certificate[] chain = new Certificate[]{keyCert};
|
||||
|
||||
// Import the key entry.
|
||||
ks.setKeyEntry("cert-" + KeyType.rsa_pkcs1_sha256.getKeyType(),
|
||||
priKey, passphrase, chain);
|
||||
}
|
||||
|
||||
// Create SSL context
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
|
||||
tmf.init(ts);
|
||||
|
||||
SSLContext context = SSLContext.getInstance(tlsProtocol);
|
||||
if (hasKeyMaterials) {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
|
||||
kmf.init(ks, passphrase);
|
||||
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
||||
} else {
|
||||
context.init(null, tmf.getTrustManagers(), null);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
private static ExecutorService newExecutorService() {
|
||||
return Executors.newCachedThreadPool((Runnable r) -> {
|
||||
Thread t = Executors.defaultThreadFactory()
|
||||
.newThread(r);
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
enum KeyType {
|
||||
|
||||
rsa_pkcs1_sha256(
|
||||
"RSA",
|
||||
/**
|
||||
* Signature Algorithm: sha256WithRSAEncryption
|
||||
* Issuer: CN = localhost
|
||||
* Validity Not Before: Jun 4 15:22:04 2018 GMT
|
||||
* Not After: May 30 15:22:04 2038 GMT
|
||||
* Subject: CN = localhost
|
||||
* Public Key Algorithm: rsaEncryption
|
||||
*/
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
+ "MIIDBjCCAe6gAwIBAgIUc8yTYekR2LuXkkCJYqWlS/pBMKIwDQYJKoZIhvcNAQEL\n"
|
||||
+ "BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE4MDYwNDE1MjIwNFoXDTM4MDUz\n"
|
||||
+ "MDE1MjIwNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF\n"
|
||||
+ "AAOCAQ8AMIIBCgKCAQEA2jDPGMogc9dq2w5b+FHqbfaGPokRmyObiU8y/l/dqkM5\n"
|
||||
+ "9IV+qj8VQUI4NtpdCTWr16812z4AjXrk5HIBrECfQbHPUcm1rme5YVZ0WxV0+Ufy\n"
|
||||
+ "hDmrGwDLhkxGqc3hOhRrlF2wdXeUfjIzhvS9+S/401++t/jvq+cqFF1BHnzYOu+l\n"
|
||||
+ "nbi/o95Oqo8MlwiRqg3xy3fNRfqXk7DWy+QT8s+Vc3Pcj1EW6K0iJJ23BVTdv6YT\n"
|
||||
+ "Ja5IKiWL4XsLht3fWvZwF+PoYfKb+JYflt0rafpxg9xkowe7GnGh2SpV7bJaH/QN\n"
|
||||
+ "3PTFEKQWgWHjWwjR171GOzSaEgaklvKde6+zNWeYKwIDAQABo1AwTjAdBgNVHQ4E\n"
|
||||
+ "FgQUqCtGe8/Ky4O6pH7xeTUy9yrv4n0wHwYDVR0jBBgwFoAUqCtGe8/Ky4O6pH7x\n"
|
||||
+ "eTUy9yrv4n0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAuqch30im\n"
|
||||
+ "M09sARarbfK3OExqYK2xoyuUscgTqQNDpNL2gMdXY9e0lTmGVgw9pVYtNZPZRxem\n"
|
||||
+ "jR5an2XegvG9qVU6vLENDwLCqZgsTb2gvmXngiG8NVcYd81GNqD228mkgBosNJku\n"
|
||||
+ "6BR+C8zlURzsNEt657eVvIp9ObGomdAbWhpdqihBD180PP18DIBWopyfHfJtT5FA\n"
|
||||
+ "U2kSPBp+P1EtdceW0zfwv3rF8hwRbnQBzuoYrZfn2PiMYaGUqOgbqUltCMD/Dp9G\n"
|
||||
+ "xK0nfAXEwIqHWWnijGwAd6YrszMjBUcSGmlehdF+XZK6jHNlw64RB4WTfavr+rY0\n"
|
||||
+ "dTe6g4o5GYr9nQ==\n"
|
||||
+ "-----END CERTIFICATE-----\n",
|
||||
//
|
||||
// Private key.
|
||||
//
|
||||
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDaMM8YyiBz12rb\n"
|
||||
+ "Dlv4Uept9oY+iRGbI5uJTzL+X92qQzn0hX6qPxVBQjg22l0JNavXrzXbPgCNeuTk\n"
|
||||
+ "cgGsQJ9Bsc9RybWuZ7lhVnRbFXT5R/KEOasbAMuGTEapzeE6FGuUXbB1d5R+MjOG\n"
|
||||
+ "9L35L/jTX763+O+r5yoUXUEefNg676WduL+j3k6qjwyXCJGqDfHLd81F+peTsNbL\n"
|
||||
+ "5BPyz5Vzc9yPURborSIknbcFVN2/phMlrkgqJYvhewuG3d9a9nAX4+hh8pv4lh+W\n"
|
||||
+ "3Stp+nGD3GSjB7sacaHZKlXtslof9A3c9MUQpBaBYeNbCNHXvUY7NJoSBqSW8p17\n"
|
||||
+ "r7M1Z5grAgMBAAECggEAHs/7vw10TcejEHJTrJqs14CT7qresKDzqw1jLycMn6nE\n"
|
||||
+ "unJLs/EaqE+Yrq5hqxZIQTo+CcsUuuYbAuPStqedleJtW6h3nryJImTaI67BCR8O\n"
|
||||
+ "8XtPXY3cMAf/hqVLZC9UDey5Ka2Ma9HdEvbnCRSsN/VycnqWJhmMCLouowaQZqoE\n"
|
||||
+ "VopscUix8GqELv0vEo2CszZfUjtSVbNTlNgwDf5U7eSKXMuFsnSn/LE7AMvHsEyo\n"
|
||||
+ "HatxogwlM/WjpTnf/WIeJY3VhaK10IsP6OEgUn/p4VtI2DQ/TJdgYrvD5vhjY8ip\n"
|
||||
+ "XuUPuPILRvJWo8dRXJqa4diXB12q5YhP8iiOp4BgkQKBgQD1GtlOR+JVgOzpQ11h\n"
|
||||
+ "s5/iJOsczee80pQscbSRJnzSsIaP9WM8CyJgvbPxIQxLUQeYnxM/bxNKkpJtzxRK\n"
|
||||
+ "pob+v4NoRn8PTpqbOp1obmWJT7uHTaoeavQo7r7uZI4i3eEgHCCQkMzpqzz7UFTY\n"
|
||||
+ "2Yst7bBTPUivlSVQQBEc8bLpeQKBgQDj47EjpAlh8DmJRTElg58t+XJehXGTqmlx\n"
|
||||
+ "nYu8DQLSzGbOQ/Z4srakC1mkM0LHCmULIIWk3KhV1GBCeArv7DlZ9A1SkI95bsq9\n"
|
||||
+ "GBeQpovL0PXKkOOWMJBklP/CTECO4eyA8r6c1d8wytBb6MrJ8bi74DdT+JlFjK5A\n"
|
||||
+ "zNoeNx6JwwKBgQCehIPABeuSYvRVlDTDqFkh98B6+4wBaatc5xjhuyOFW5dbaVeJ\n"
|
||||
+ "kKXmLSpAK6B44WnpQhA/uUWfuBWtoPy9nt+1yARjnxwzuSFyfUEqNiPC32coBYmd\n"
|
||||
+ "bIyGIIopQa1PTXJ4wtgoxw1PnmitHHITYPaLeKrN2te0fuAH+7dVodeU+QKBgAct\n"
|
||||
+ "VJbaw7Dh7+3yz+lui8TW5lMzwK/13fxGCfCSOFSLO3Gjkk+a0UW5VclmE+RQ333K\n"
|
||||
+ "OGtIx8RsO9vcC/wiZGwA06qWAu7AHoJ2D8fudtikbBlFFuXUAbgpOSTVYfMeCmTF\n"
|
||||
+ "QFuQIMdYm9dJLZnOkxLXrOZoHeui0poX2Ya6FawhAoGAAI/QCyDbuvnJzGmjSbvl\n"
|
||||
+ "5Ndr9lNAansCXaUzXuVLp6dD6PnB8HVCE8tdETZrcXseyTBeltaxAhj+tCybJvDO\n"
|
||||
+ "sV8UmPR0w9ibExmUIVGX5BpoRlB/KWxEG3ar/wJbUZVZ2oSdIAZvCvdbN956SLDg\n"
|
||||
+ "Pg5M5wrRqs71s2EiIJd0HrU="
|
||||
);
|
||||
private final String keyType;
|
||||
private final String trustedCert;
|
||||
private final String endCert;
|
||||
private final String privateKey;
|
||||
|
||||
private KeyType(String keyType, String selfCert, String privateKey) {
|
||||
this.keyType = keyType;
|
||||
this.trustedCert = selfCert;
|
||||
this.endCert = selfCert;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public String getKeyType() {
|
||||
return keyType;
|
||||
}
|
||||
|
||||
public String getTrustedCert() {
|
||||
return trustedCert;
|
||||
}
|
||||
|
||||
public String getEndCert() {
|
||||
return endCert;
|
||||
}
|
||||
|
||||
public String getPrivateKey() {
|
||||
return privateKey;
|
||||
}
|
||||
}
|
@ -671,7 +671,7 @@ public abstract class PKCS11Test {
|
||||
"/usr/lib/arm-linux-gnueabi/nss/",
|
||||
"/usr/lib/arm-linux-gnueabihf/nss/"});
|
||||
osMap.put("Linux-aarch64-64", new String[]{
|
||||
"/usr/lib/aarch64-linux-gnu/nss/"});
|
||||
"/usr/lib/aarch64-linux-gnu/", "/usr/lib/aarch64-linux-gnu/nss/"});
|
||||
}
|
||||
|
||||
private final static char[] hexDigits = "0123456789abcdef".toCharArray();
|
||||
|
Loading…
x
Reference in New Issue
Block a user