/
githubmirror
/
galahad
Обзор
Документация
Войти
/
githubmirror
/
galahad
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java
223 строки
9 KB
Jaikiran Pai
8371802: Do not let QUIC connection to idle terminate when HTTP/3 is configured with a higher idle timeout
29 ноя 2025, 04:25
29 ноя 2025, 04:25
92e1357
Код
Авторство
О чём код?
/* * Copyright (c) 2025, 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.http.HttpOption.Http3DiscoveryMode; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import jdk.internal.net.http.common.Logger; import static java.net.http.HttpOption.Http3DiscoveryMode.ALT_SVC; import static java.net.http.HttpOption.Http3DiscoveryMode.ANY; import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; /** * This class encapsulate the HTTP/3 connection pool managed * by an instance of {@link Http3ClientImpl}. */ class Http3ConnectionPool { /* Map key is "scheme:host:port" */ private final Map<String,Http3Connection> advertised = new ConcurrentHashMap<>(); /* Map key is "scheme:host:port" */ private final Map<String,Http3Connection> unadvertised = new ConcurrentHashMap<>(); private final Logger debug; Http3ConnectionPool(Logger logger) { this.debug = Objects.requireNonNull(logger); } // https:<host>:<port> String connectionKey(HttpRequestImpl request) { var uri = request.uri(); var scheme = uri.getScheme().toLowerCase(Locale.ROOT); var host = uri.getHost(); var port = uri.getPort(); assert scheme.equals("https"); if (port < 0) port = 443; // https return String.format("%s:%s:%d", scheme, host, port); } private Http3Connection lookupUnadvertised(String key, Http3DiscoveryMode discoveryMode) { var unadvertisedConn = unadvertised.get(key); if (unadvertisedConn == null) return null; if (discoveryMode == ANY) return unadvertisedConn; if (discoveryMode == ALT_SVC) return null; assert discoveryMode == HTTP_3_URI_ONLY : String.valueOf(discoveryMode); // Double check that if there is an alt service, it has same origin. final var altService = Optional.ofNullable(unadvertisedConn) .map(Http3Connection::connection) .flatMap(HttpQuicConnection::getSourceAltService) .orElse(null); if (altService == null || altService.originHasSameAuthority()) { return unadvertisedConn; } // We should never come here. assert false : "unadvertised connection with different origin: %s -> %s" .formatted(key, altService); return null; } Http3Connection lookupFor(HttpRequestImpl request) { var discoveryMode = request.http3Discovery(); var key = connectionKey(request); Http3Connection unadvertisedConn = null; // If not ALT_SVC, we can use unadvertised connections if (discoveryMode != ALT_SVC) { unadvertisedConn = lookupUnadvertised(key, discoveryMode); if (unadvertisedConn != null && discoveryMode == HTTP_3_URI_ONLY) { if (debug.on()) { debug.log("Direct HTTP/3 connection found for %s in connection pool %s", discoveryMode, unadvertisedConn.connection().label()); } return unadvertisedConn; } } // Then see if we have a connection which was advertised. var advertisedConn = advertised.get(key); // We can use it for HTTP3_URI_ONLY too if it has same origin if (advertisedConn != null) { final var altService = advertisedConn.connection() .getSourceAltService().orElse(null); assert altService != null && altService.wasAdvertised(); switch (discoveryMode) { case ANY -> { return advertisedConn; } case ALT_SVC -> { if (debug.on()) { debug.log("HTTP/3 connection found for %s in connection pool %s", discoveryMode, advertisedConn.connection().label()); } return advertisedConn; } case HTTP_3_URI_ONLY -> { if (altService != null && altService.originHasSameAuthority()) { if (debug.on()) { debug.log("Same authority HTTP/3 connection found for %s in connection pool %s", discoveryMode, advertisedConn.connection().label()); } return advertisedConn; } } } } if (unadvertisedConn != null) { assert discoveryMode != ALT_SVC; if (debug.on()) { debug.log("Direct HTTP/3 connection found for %s in connection pool %s", discoveryMode, unadvertisedConn.connection().label()); } return unadvertisedConn; } // do not log here: this produces confusing logs as this method // can be called several times when trying to establish a // connection, when no connection is found in the pool return null; } Http3Connection putIfAbsent(String key, Http3Connection c) { Objects.requireNonNull(key); Objects.requireNonNull(c); assert key.equals(c.key()); var altService = c.connection().getSourceAltService().orElse(null); if (altService != null && altService.wasAdvertised()) { final var prev = advertised.putIfAbsent(key, c); if (prev == null) { c.setPooled(true); // mark the newly pooled connection as pooled } return prev; } assert altService == null || altService.originHasSameAuthority(); final var prev = unadvertised.putIfAbsent(key, c); if (prev == null) { c.setPooled(true); // mark the newly pooled connection as pooled } return prev; } void put(String key, Http3Connection c) { Objects.requireNonNull(key); Objects.requireNonNull(c); assert key.equals(c.key()) : "key mismatch %s -> %s" .formatted(key, c.key()); var altService = c.connection().getSourceAltService().orElse(null); if (altService != null && altService.wasAdvertised()) { advertised.put(key, c); c.setPooled(true); return; } assert altService == null || altService.originHasSameAuthority(); unadvertised.put(key, c); c.setPooled(true); } boolean remove(String key, Http3Connection c) { Objects.requireNonNull(key); Objects.requireNonNull(c); assert key.equals(c.key()) : "key mismatch %s -> %s" .formatted(key, c.key()); var altService = c.connection().getSourceAltService().orElse(null); if (altService != null && altService.wasAdvertised()) { boolean remUndavertised = unadvertised.remove(key, c); assert !remUndavertised : "advertised connection found in unadvertised pool for " + key; return advertised.remove(key, c); } assert altService == null || altService.originHasSameAuthority(); final boolean removed = unadvertised.remove(key, c); if (removed) { c.setPooled(false); } return removed; } void clear() { advertised.values().forEach((c) -> c.setPooled(false)); advertised.clear(); unadvertised.values().forEach((c) -> c.setPooled(false)); unadvertised.clear(); } java.util.stream.Stream<Http3Connection> values() { return java.util.stream.Stream.concat( advertised.values().stream(), unadvertised.values().stream()); } }