/
githubmirror
/
panama-vector
Обзор
Документация
Войти
/
githubmirror
/
panama-vector
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
test/jdk/java/net/httpclient/http3/H3HeadersEncoding.java
312 строк
13 KB
Daisuke Yamazaki
8372325: Refactor tests under jdk/java/net/httpclient to use ${test.main.class}
09 апр 2026, 13:51
09 апр 2026, 13:51
261011a
Код
Авторство
О чём код?
/* * Copyright (c) 2024, 2026, 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 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters * jdk.test.lib.net.SimpleSSLContext * @compile ../ReferenceTracker.java * @run junit/othervm -Djdk.httpclient.qpack.encoderTableCapacityLimit=4096 * -Djdk.httpclient.qpack.decoderMaxTableCapacity=4096 * -Dhttp3.test.server.encoderAllowedHeaders=* * -Dhttp3.test.server.decoderMaxTableCapacity=4096 * -Dhttp3.test.server.encoderTableCapacityLimit=4096 * -Djdk.internal.httpclient.qpack.log.level=NORMAL * ${test.main.class} * @summary this test verifies that when QPACK dynamic table is enabled multiple * random headers can be encoded/decoded correctly */ import jdk.test.lib.RandomFactory; import jdk.test.lib.net.SimpleSSLContext; import javax.net.ssl.SSLContext; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpHeaders; import java.net.http.HttpRequest; import java.net.http.HttpOption.Http3DiscoveryMode; import java.net.http.HttpResponse; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; import static java.net.http.HttpClient.Version.HTTP_3; import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; import static java.net.http.HttpOption.H3_DISCOVERY; import static jdk.httpclient.test.lib.common.HttpServerAdapters.*; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; public class H3HeadersEncoding { private static final int REQUESTS_COUNT = 500; private static final int HEADERS_PER_REQUEST = 20; private static final SSLContext sslContext = SimpleSSLContext.findSSLContext(); private static HttpTestServer http3TestServer; private static HeadersHandler serverHeadersHandler; private static String http3URI; @BeforeAll public static void setup() throws Exception { System.out.println("Creating servers"); http3TestServer = HttpTestServer.create(Http3DiscoveryMode.HTTP_3_URI_ONLY, sslContext); serverHeadersHandler = new HeadersHandler(); http3TestServer.addHandler(serverHeadersHandler, "/http3/headers"); http3URI = "https://" + http3TestServer.serverAuthority() + "/http3/headers"; http3TestServer.start(); } @AfterAll public static void tearDown() { http3TestServer.stop(); } @Test public void serialRequests() throws Exception { try (HttpClient client = newClient()) { for (int i = 0; i < REQUESTS_COUNT; i++) { HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(URI.create(http3URI)) .version(HTTP_3) .setOption(H3_DISCOVERY, HTTP_3_URI_ONLY); List<TestHeader> rndHeaders = TestHeader.randomHeaders(HEADERS_PER_REQUEST); String[] requestHeaders = rndHeaders.stream() .flatMap(th -> Stream.of(th.name(), th.value())) .toArray(String[]::new); requestBuilder.headers(requestHeaders); // Send client request headers in request body for further check // on the server handler side requestBuilder.POST(HttpRequest.BodyPublishers.ofString( TestHeader.headersToBodyContent(rndHeaders))); HttpResponse<String> response = client.send(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()); // Headers received by the client var serverHeadersClientSide = TestHeader.fromHttpHeaders(response.headers()); // Headers sent by the server handler var serverHeadersServerSide = TestHeader.bodyContentToHeaders(response.body()); // Check that all headers that server sent are received on client side checkHeaders(serverHeadersServerSide, serverHeadersClientSide, "client"); } } } @Test public void asyncRequests() throws Exception { try (HttpClient client = newClient()) { ArrayList<List<TestHeader>> requestsHeaders = new ArrayList<>(REQUESTS_COUNT); ArrayList<HttpRequest> requests = new ArrayList<>(REQUESTS_COUNT); CopyOnWriteArrayList<CompletableFuture<HttpResponse<String>>> futureReplies = new CopyOnWriteArrayList<>(); // Prepare all requests first for (int i = 0; i < REQUESTS_COUNT; i++) { HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(URI.create(http3URI)) .version(HTTP_3) .setOption(H3_DISCOVERY, HTTP_3_URI_ONLY); List<TestHeader> rndHeaders = TestHeader.randomHeaders(HEADERS_PER_REQUEST); String[] requestHeaders = rndHeaders.stream() .flatMap(th -> Stream.of(th.name(), th.value())) .toArray(String[]::new); requestBuilder.headers(requestHeaders); requestsHeaders.add(i, rndHeaders); // Send client request headers in request body for further check // on the server handler side requestBuilder.POST(HttpRequest.BodyPublishers.ofString( TestHeader.headersToBodyContent(rndHeaders))); requests.add(i, requestBuilder.build()); } // Send async request for (int i = 0; i < REQUESTS_COUNT; i++) { CompletableFuture<HttpResponse<String>> cf = client.sendAsync(requests.get(i), HttpResponse.BodyHandlers.ofString()); futureReplies.add(i, cf); } // Join on all CF responses for (int i = 0; i < REQUESTS_COUNT; i++) { futureReplies.get(i).join(); } // Check the responses for (int i = 0; i < REQUESTS_COUNT; i++) { HttpResponse<String> reply = futureReplies.get(i).get(); // Headers received by the client var serverHeadersClientSide = TestHeader.fromHttpHeaders(reply.headers()); // Headers sent by the server handler var serverHeadersServerSide = TestHeader.bodyContentToHeaders(reply.body()); // Check that all headers that server sent are received on client side checkHeaders(serverHeadersServerSide, serverHeadersClientSide, "client"); } } } private static void checkHeaders(List<TestHeader> mustPresent, List<TestHeader> allHeaders, String sideDescription) { List<TestHeader> notFound = new ArrayList<>(); for (var header : mustPresent) { if (!allHeaders.contains(header)) { notFound.add(header); } } if (!notFound.isEmpty()) { System.err.println("The following headers was not found on " + sideDescription + " side: " + notFound); throw new RuntimeException("Headers not found: " + notFound); } } HttpClient newClient() { var builder = createClientBuilderForH3() .sslContext(sslContext) .version(HTTP_3) .proxy(HttpClient.Builder.NO_PROXY); return builder.build(); } private static final Random RND = RandomFactory.getRandom(); record TestHeader(String name, String value) { static TestHeader randomHeader() { // It is better to have same id generated two or more // times during the test run, therefore the range below int headerId = RND.nextInt(10, 10 + HEADERS_PER_REQUEST * 3); return new TestHeader("test_header" + headerId, "TestValue"); } static List<TestHeader> randomHeaders(int count) { return IntStream .range(0, count) .boxed() .map(ign -> TestHeader.randomHeader()) .toList(); } static List<TestHeader> fromHttpHeaders(HttpHeaders httpHeaders) { var headersMap = httpHeaders.map(); return fromHeadersEntrySet(headersMap.entrySet()); } static List<TestHeader> fromTestHttpHeaders(HttpTestRequestHeaders requestHeaders) { var headersSet = requestHeaders.entrySet(); return fromHeadersEntrySet(headersSet); } private static List<TestHeader> fromHeadersEntrySet(Set<Map.Entry<String, List<String>>> entrySet) { return entrySet.stream() .flatMap(entry -> { var name = entry.getKey(); return entry.getValue() .stream() .map(value -> new TestHeader(name, value)); }).toList(); } public static String headersToBodyContent(List<TestHeader> rndHeaders) { return rndHeaders.stream() .map(TestHeader::toString) .collect(Collectors.joining(System.lineSeparator())); } public static List<TestHeader> bodyContentToHeaders(String bodyContent) { return Arrays.stream(bodyContent.split(System.lineSeparator())) .filter(Predicate.not(String::isBlank)) .map(String::strip) .map(TestHeader::fromBodyHeaderLine) .toList(); } public static TestHeader fromBodyHeaderLine(String headerLine) { String[] parts = headerLine.split(":"); if (parts.length != 2) { throw new RuntimeException("Internal test error"); } return new TestHeader(parts[0], parts[1]); } public String toString() { return name + ":" + value; } } private static class HeadersHandler implements HttpTestHandler { @Override public void handle(HttpTestExchange t) throws IOException { var clientHeadersServerSide = TestHeader.fromTestHttpHeaders(t.getRequestHeaders()); String requestBody; try (InputStream is = t.getRequestBody()) { byte[] body = is.readAllBytes(); requestBody = new String(body); } var clientHeadersClientSide = TestHeader.bodyContentToHeaders(requestBody); // Check that all headers that client sent are received on tne server side checkHeaders(clientHeadersClientSide, clientHeadersServerSide, "server handler"); // Response back with a set of random headers var responseHeaders = t.getResponseHeaders(); List<TestHeader> serverResp = new ArrayList<>(); for (TestHeader h : TestHeader.randomHeaders(HEADERS_PER_REQUEST)) { serverResp.add(h); responseHeaders.addHeader(h.name(), h.value()); } String responseBody = TestHeader.headersToBodyContent(serverResp); try (OutputStream os = t.getResponseBody()) { byte[] responseBodyBytes = responseBody.getBytes(); t.sendResponseHeaders(200, responseBodyBytes.length); if (!t.getRequestMethod().equals("HEAD")) { os.write(responseBodyBytes); } } } } }