92474f13f0
Reviewed-by: dfuchs
227 lines
11 KiB
Java
227 lines
11 KiB
Java
/*
|
|
* Copyright (c) 2022, 2023, 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 8288717
|
|
* @summary Tests that when the idleConnectionTimeoutEvent is configured in HTTP/2,
|
|
* an HTTP/2 connection will close within the specified interval if there
|
|
* are no active streams on the connection.
|
|
* @library /test/lib /test/jdk/java/net/httpclient/lib
|
|
* @build jdk.httpclient.test.lib.http2.Http2TestServer
|
|
*
|
|
* @run testng/othervm -Djdk.httpclient.HttpClient.log=errors -Djdk.httpclient.keepalive.timeout=1
|
|
* IdleConnectionTimeoutTest
|
|
* @run testng/othervm -Djdk.httpclient.HttpClient.log=errors -Djdk.httpclient.keepalive.timeout=2
|
|
* IdleConnectionTimeoutTest
|
|
*
|
|
* @run testng/othervm -Djdk.httpclient.HttpClient.log=errors -Djdk.httpclient.keepalive.timeout.h2=1
|
|
* IdleConnectionTimeoutTest
|
|
* @run testng/othervm -Djdk.httpclient.HttpClient.log=errors -Djdk.httpclient.keepalive.timeout.h2=2
|
|
* IdleConnectionTimeoutTest
|
|
*
|
|
* @run testng/othervm -Djdk.httpclient.HttpClient.log=errors -Djdk.httpclient.keepalive.timeout.h2=1
|
|
* -Djdk.httpclient.keepalive.timeout=2
|
|
* IdleConnectionTimeoutTest
|
|
*
|
|
* @run testng/othervm -Djdk.httpclient.HttpClient.log=errors IdleConnectionTimeoutTest
|
|
* @run testng/othervm -Djdk.httpclient.HttpClient.log=errors -Djdk.httpclient.keepalive.timeout.h2=-1
|
|
* IdleConnectionTimeoutTest
|
|
* @run testng/othervm -Djdk.httpclient.HttpClient.log=errors,trace -Djdk.httpclient.keepalive.timeout.h2=abc
|
|
* IdleConnectionTimeoutTest
|
|
*/
|
|
|
|
import jdk.httpclient.test.lib.http2.BodyOutputStream;
|
|
import jdk.httpclient.test.lib.http2.Http2TestExchangeImpl;
|
|
import jdk.httpclient.test.lib.http2.Http2TestServerConnection;
|
|
import jdk.internal.net.http.common.HttpHeadersBuilder;
|
|
import org.testng.annotations.BeforeTest;
|
|
import org.testng.annotations.Test;
|
|
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.PrintStream;
|
|
import java.net.URI;
|
|
import java.net.http.HttpClient;
|
|
import java.net.http.HttpHeaders;
|
|
import java.net.http.HttpRequest;
|
|
import java.net.http.HttpResponse;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import jdk.httpclient.test.lib.http2.Http2TestServer;
|
|
import jdk.httpclient.test.lib.http2.Http2TestExchange;
|
|
import jdk.httpclient.test.lib.http2.Http2Handler;
|
|
|
|
import javax.net.ssl.SSLSession;
|
|
|
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
|
import static java.net.http.HttpClient.Version.HTTP_2;
|
|
import static org.testng.Assert.assertEquals;
|
|
|
|
public class IdleConnectionTimeoutTest {
|
|
|
|
static Http2TestServer http2TestServer;
|
|
URI timeoutUri;
|
|
URI noTimeoutUri;
|
|
final String IDLE_CONN_PROPERTY = "jdk.httpclient.keepalive.timeout.h2";
|
|
final String KEEP_ALIVE_PROPERTY = "jdk.httpclient.keepalive.timeout";
|
|
final String TIMEOUT_PATH = "/serverTimeoutHandler";
|
|
final String NO_TIMEOUT_PATH = "/noServerTimeoutHandler";
|
|
static final PrintStream testLog = System.err;
|
|
|
|
@BeforeTest
|
|
public void setup() throws Exception {
|
|
http2TestServer = new Http2TestServer(false, 0);
|
|
http2TestServer.addHandler(new ServerTimeoutHandler(), TIMEOUT_PATH);
|
|
http2TestServer.addHandler(new ServerNoTimeoutHandler(), NO_TIMEOUT_PATH);
|
|
http2TestServer.setExchangeSupplier(TestExchangeSupplier::new);
|
|
|
|
http2TestServer.start();
|
|
int port = http2TestServer.getAddress().getPort();
|
|
timeoutUri = new URI("http://localhost:" + port + TIMEOUT_PATH);
|
|
noTimeoutUri = new URI("http://localhost:" + port + NO_TIMEOUT_PATH);
|
|
}
|
|
|
|
/*
|
|
If the InetSocketAddress of the first remote connection is not equal to the address of the
|
|
second remote connection, then the idleConnectionTimeoutEvent has occurred and a new connection
|
|
was made to carry out the second request by the client.
|
|
*/
|
|
@Test
|
|
public void test() throws InterruptedException {
|
|
String timeoutVal = System.getProperty(IDLE_CONN_PROPERTY);
|
|
String keepAliveVal = System.getProperty(KEEP_ALIVE_PROPERTY);
|
|
testLog.println("Test run for " + IDLE_CONN_PROPERTY + "=" + timeoutVal);
|
|
|
|
int sleepTime = 0;
|
|
HttpClient hc = HttpClient.newBuilder().version(HTTP_2).build();
|
|
HttpRequest hreq;
|
|
HttpResponse<String> hresp;
|
|
if (timeoutVal != null) {
|
|
if (keepAliveVal != null) {
|
|
// In this case, specified h2 timeout should override keep alive timeout.
|
|
// Timeout should occur
|
|
hreq = HttpRequest.newBuilder(timeoutUri).version(HTTP_2).GET().build();
|
|
sleepTime = 2000;
|
|
hresp = runRequest(hc, hreq, sleepTime);
|
|
assertEquals(hresp.statusCode(), 200, "idleConnectionTimeoutEvent was expected but did not occur");
|
|
} else if (timeoutVal.equals("1")) {
|
|
// Timeout should occur
|
|
hreq = HttpRequest.newBuilder(timeoutUri).version(HTTP_2).GET().build();
|
|
sleepTime = 2000;
|
|
hresp = runRequest(hc, hreq, sleepTime);
|
|
assertEquals(hresp.statusCode(), 200, "idleConnectionTimeoutEvent was expected but did not occur");
|
|
} else if (timeoutVal.equals("2")) {
|
|
// Timeout should not occur
|
|
hreq = HttpRequest.newBuilder(noTimeoutUri).version(HTTP_2).GET().build();
|
|
sleepTime = 1000;
|
|
hresp = runRequest(hc, hreq, sleepTime);
|
|
assertEquals(hresp.statusCode(), 200, "idleConnectionTimeoutEvent was not expected but occurred");
|
|
} else if (timeoutVal.equals("abc") || timeoutVal.equals("-1")) {
|
|
// Timeout should not occur
|
|
hreq = HttpRequest.newBuilder(noTimeoutUri).version(HTTP_2).GET().build();
|
|
hresp = runRequest(hc, hreq, sleepTime);
|
|
assertEquals(hresp.statusCode(), 200, "idleConnectionTimeoutEvent was not expected but occurred");
|
|
}
|
|
} else {
|
|
// When no value is specified then no timeout should occur (default keep alive value of 600 used)
|
|
hreq = HttpRequest.newBuilder(noTimeoutUri).version(HTTP_2).GET().build();
|
|
hresp = runRequest(hc, hreq, sleepTime);
|
|
assertEquals(hresp.statusCode(), 200, "idleConnectionTimeoutEvent should not occur, no value was specified for this property");
|
|
}
|
|
}
|
|
|
|
private HttpResponse<String> runRequest(HttpClient hc, HttpRequest req, int sleepTime) throws InterruptedException {
|
|
CompletableFuture<HttpResponse<String>> request = hc.sendAsync(req, HttpResponse.BodyHandlers.ofString(UTF_8));
|
|
HttpResponse<String> hresp = request.join();
|
|
assertEquals(hresp.statusCode(), 200);
|
|
|
|
Thread.sleep(sleepTime);
|
|
request = hc.sendAsync(req, HttpResponse.BodyHandlers.ofString(UTF_8));
|
|
return request.join();
|
|
}
|
|
|
|
static class ServerTimeoutHandler implements Http2Handler {
|
|
|
|
volatile Object firstConnection = null;
|
|
|
|
@Override
|
|
public void handle(Http2TestExchange exchange) throws IOException {
|
|
if (exchange instanceof TestExchangeSupplier exch) {
|
|
if (firstConnection == null) {
|
|
firstConnection = exch.getTestConnection();
|
|
exch.sendResponseHeaders(200, 0);
|
|
} else {
|
|
var secondConnection = exch.getTestConnection();
|
|
|
|
if (firstConnection != secondConnection) {
|
|
testLog.println("ServerTimeoutHandler: New Connection was used, idleConnectionTimeoutEvent fired."
|
|
+ " First Connection Hash: " + firstConnection + ", Second Connection Hash: " + secondConnection);
|
|
exch.sendResponseHeaders(200, 0);
|
|
} else {
|
|
testLog.println("ServerTimeoutHandler: Same Connection was used, idleConnectionTimeoutEvent did not fire."
|
|
+ " First Connection Hash: " + firstConnection + ", Second Connection Hash: " + secondConnection);
|
|
exch.sendResponseHeaders(400, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static class ServerNoTimeoutHandler implements Http2Handler {
|
|
|
|
volatile Object firstConnection = null;
|
|
|
|
@Override
|
|
public void handle(Http2TestExchange exchange) throws IOException {
|
|
if (exchange instanceof TestExchangeSupplier exch) {
|
|
if (firstConnection == null) {
|
|
firstConnection = exch.getTestConnection();
|
|
exch.sendResponseHeaders(200, 0);
|
|
} else {
|
|
var secondConnection = exch.getTestConnection();
|
|
|
|
if (firstConnection == secondConnection) {
|
|
testLog.println("ServerTimeoutHandler: Same Connection was used, idleConnectionTimeoutEvent did not fire."
|
|
+ " First Connection Hash: " + firstConnection + ", Second Connection Hash: " + secondConnection);
|
|
exch.sendResponseHeaders(200, 0);
|
|
} else {
|
|
testLog.println("ServerTimeoutHandler: Different Connection was used, idleConnectionTimeoutEvent fired."
|
|
+ " First Connection Hash: " + firstConnection + ", Second Connection Hash: " + secondConnection);
|
|
exch.sendResponseHeaders(400, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static class TestExchangeSupplier extends Http2TestExchangeImpl {
|
|
|
|
public TestExchangeSupplier(int streamid, String method, HttpHeaders reqheaders, HttpHeadersBuilder rspheadersBuilder, URI uri, InputStream is, SSLSession sslSession, BodyOutputStream os, Http2TestServerConnection conn, boolean pushAllowed) {
|
|
super(streamid, method, reqheaders, rspheadersBuilder, uri, is, sslSession, os, conn, pushAllowed);
|
|
}
|
|
|
|
public Http2TestServerConnection getTestConnection() {
|
|
return this.conn;
|
|
}
|
|
}
|
|
} |