diff --git a/src/java.base/share/classes/java/net/HostPortrange.java b/src/java.base/share/classes/java/net/HostPortrange.java index fd516b8d2d7..289846841c9 100644 --- a/src/java.base/share/classes/java/net/HostPortrange.java +++ b/src/java.base/share/classes/java/net/HostPortrange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -29,6 +29,9 @@ import java.util.Formatter; import java.util.Locale; import sun.net.util.IPAddressUtil; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; + /** * Parses a string containing a host/domain name and port range */ @@ -56,7 +59,7 @@ class HostPortrange { return hostname.hashCode() + portrange[0] + portrange[1]; } - HostPortrange(String scheme, String str) { + HostPortrange(String scheme, String host) { // Parse the host name. A name has up to three components, the // hostname, a port number, or two numbers representing a port // range. "www.example.com:8080-9090" is a valid host name. @@ -67,21 +70,23 @@ class HostPortrange { // Refer to RFC 2732 for more information. // first separate string into two fields: hoststr, portstr - String hoststr, portstr = null; + String hoststr = null, portstr = null; this.scheme = scheme; // check for IPv6 address - if (str.charAt(0) == '[') { + if (host.charAt(0) == '[') { ipv6 = literal = true; - int rb = str.indexOf(']'); + int rb = host.indexOf(']'); if (rb != -1) { - hoststr = str.substring(1, rb); + hoststr = host.substring(1, rb); } else { - throw new IllegalArgumentException("invalid IPv6 address: " + str); + throw new IllegalArgumentException( + formatMsg("invalid IPv6 address%s", + filterNonSocketInfo(host).prefixWith(": "))); } - int sep = str.indexOf(':', rb + 1); - if (sep != -1 && str.length() > sep) { - portstr = str.substring(sep + 1); + int sep = host.indexOf(':', rb + 1); + if (sep != -1 && host.length() > sep) { + portstr = host.substring(sep + 1); } // need to normalize hoststr now byte[] ip = IPAddressUtil.textToNumericFormatV6(hoststr); @@ -94,16 +99,16 @@ class HostPortrange { + "%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15]); - hostname = sb.toString(); + this.hostname = sb.toString(); } else { // not IPv6 therefore ':' is the port separator - int sep = str.indexOf(':'); - if (sep != -1 && str.length() > sep) { - hoststr = str.substring(0, sep); - portstr = str.substring(sep + 1); + int sep = host.indexOf(':'); + if (sep != -1 && host.length() > sep) { + hoststr = host.substring(0, sep); + portstr = host.substring(sep + 1); } else { - hoststr = sep == -1 ? str : str.substring(0, sep); + hoststr = sep == -1 ? host : host.substring(0, sep); } // is this a domain wildcard specification? if (hoststr.lastIndexOf('*') > 0) { @@ -150,13 +155,14 @@ class HostPortrange { } } } - hostname = hoststr; + this.hostname = hoststr; } try { portrange = parsePort(portstr); } catch (Exception e) { - throw new IllegalArgumentException("invalid port range: " + portstr); + throw new IllegalArgumentException( + formatMsg("invalid port range%s", filterNonSocketInfo(portstr).prefixWith(": "))); } } diff --git a/src/java.base/share/classes/java/net/Inet4AddressImpl.java b/src/java.base/share/classes/java/net/Inet4AddressImpl.java index c7feaf4c195..3d8ea56d99f 100644 --- a/src/java.base/share/classes/java/net/Inet4AddressImpl.java +++ b/src/java.base/share/classes/java/net/Inet4AddressImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -27,6 +27,8 @@ import java.io.IOException; import java.net.spi.InetAddressResolver.LookupPolicy; import static java.net.spi.InetAddressResolver.LookupPolicy.IPV4; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /* * Package private implementation of InetAddressImpl for IPv4. @@ -38,7 +40,7 @@ final class Inet4AddressImpl implements InetAddressImpl { public InetAddress[] lookupAllHostAddr(String hostname, LookupPolicy lookupPolicy) throws UnknownHostException { if ((lookupPolicy.characteristics() & IPV4) == 0) { - throw new UnknownHostException(hostname); + throw new UnknownHostException(formatMsg("%s", filterNonSocketInfo(hostname))); } return lookupAllHostAddr(hostname); } diff --git a/src/java.base/share/classes/java/net/Inet6Address.java b/src/java.base/share/classes/java/net/Inet6Address.java index 06a74ca3adc..f0f386a9d29 100644 --- a/src/java.base/share/classes/java/net/Inet6Address.java +++ b/src/java.base/share/classes/java/net/Inet6Address.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -35,6 +35,8 @@ import java.io.ObjectStreamField; import java.util.Enumeration; import java.util.Arrays; import java.util.Objects; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * This class represents an Internet Protocol version 6 (IPv6) address. @@ -581,7 +583,9 @@ class Inet6Address extends InetAddress { if (addrBytes.length == Inet4Address.INADDRSZ) { if (numericZone != -1 || ifname != null) { // IPv4-mapped address must not contain zone-id - throw new UnknownHostException(addressLiteral + ": invalid IPv4-mapped address"); + throw new UnknownHostException( + formatMsg("%sinvalid IPv4-mapped address", + filterNonSocketInfo(addressLiteral).suffixWith(": "))); } return new Inet4Address(null, addrBytes); } diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java index 4bceebdcd0e..4d8a00249a9 100644 --- a/src/java.base/share/classes/java/net/InetAddress.java +++ b/src/java.base/share/classes/java/net/InetAddress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -54,6 +54,7 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Stream; +import jdk.internal.util.Exceptions; import jdk.internal.access.JavaNetInetAddressAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.misc.Blocker; @@ -68,6 +69,8 @@ import static java.net.spi.InetAddressResolver.LookupPolicy.IPV4; import static java.net.spi.InetAddressResolver.LookupPolicy.IPV4_FIRST; import static java.net.spi.InetAddressResolver.LookupPolicy.IPV6; import static java.net.spi.InetAddressResolver.LookupPolicy.IPV6_FIRST; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * This class represents an Internet Protocol (IP) address. @@ -382,6 +385,7 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In } } ); + Exceptions.setup(); // needed for native exceptions init(); } @@ -902,7 +906,7 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In @Override public InetAddress[] get() throws UnknownHostException { if (inetAddresses == null) { - throw new UnknownHostException(host); + throw new UnknownHostException(formatMsg("%s", filterNonSocketInfo(host))); } return inetAddresses; } @@ -1095,7 +1099,9 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In } } if (inetAddresses == null || inetAddresses.length == 0) { - throw ex == null ? new UnknownHostException(host) : ex; + throw ex == null + ? new UnknownHostException(formatMsg("%s", filterNonSocketInfo(host))) + : ex; } return inetAddresses; } @@ -1203,16 +1209,19 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In } } } catch (IOException e) { - throw new UnknownHostException("Unable to resolve address " - + Arrays.toString(addr) + " as hosts file " + hostsFile - + " not found "); + throw new UnknownHostException( + formatMsg("Unable to resolve address %s as hosts file %s not found", + filterNonSocketInfo(Arrays.toString(addr)), + filterNonSocketInfo(hostsFile) + .replaceWith("from ${jdk.net.hosts.file} system property"))); } if ((host == null) || (host.isEmpty()) || (host.equals(" "))) { - throw new UnknownHostException("Requested address " - + Arrays.toString(addr) - + " resolves to an invalid entry in hosts file " - + hostsFile); + throw new UnknownHostException( + formatMsg("Requested address %s resolves to an invalid entry in hosts file %s", + filterNonSocketInfo(Arrays.toString(addr)), + filterNonSocketInfo(hostsFile) + .replaceWith("from ${jdk.net.hosts.file} system property"))); } return host; } @@ -1273,8 +1282,11 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In } } } catch (IOException e) { - throw new UnknownHostException("Unable to resolve host " + host - + " as hosts file " + hostsFile + " not found "); + throw new UnknownHostException( + formatMsg("Unable to resolve host %s as hosts file %s not found", + filterNonSocketInfo(host), filterNonSocketInfo(hostsFile) + .replaceWith("from ${jdk.net.hosts.file} system property"))); + } // Check if only IPv4 addresses are requested if (needIPv4 && !needIPv6) { @@ -1305,8 +1317,10 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In private void checkResultsList(List addressesList, String hostName) throws UnknownHostException { if (addressesList.isEmpty()) { - throw new UnknownHostException("Unable to resolve host " + hostName - + " in hosts file " + hostsFile); + throw new UnknownHostException( + formatMsg("Unable to resolve host %s in hosts file %s", + filterNonSocketInfo(hostName), filterNonSocketInfo(hostsFile) + .replaceWith("from ${jdk.net.hosts.file} system property"))); } } @@ -1543,7 +1557,7 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In // Here we check the address string for ambiguity only inetAddress = Inet4Address.parseAddressString(host, false); } catch (IllegalArgumentException iae) { - var uhe = new UnknownHostException(host); + var uhe = new UnknownHostException(formatMsg("%s", filterNonSocketInfo(host))); uhe.initCause(iae); throw uhe; } @@ -1570,7 +1584,8 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In private static UnknownHostException invalidIPv6LiteralException(String host, boolean wrapInBrackets) { String hostString = wrapInBrackets ? "[" + host + "]" : host; - return new UnknownHostException(hostString + ": invalid IPv6 address literal"); + return new UnknownHostException(formatMsg("%sinvalid IPv6 address literal", + filterNonSocketInfo(hostString).suffixWith(": "))); } /** @@ -1708,7 +1723,8 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In InetAddress[] result = addresses == null ? null : addresses.toArray(InetAddress[]::new); if (result == null || result.length == 0) { - throw ex == null ? new UnknownHostException(host) : ex; + throw ex == null ? new UnknownHostException(formatMsg("%s", filterNonSocketInfo(host))) + : ex; } return result; } @@ -1780,9 +1796,9 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In localAddr = getAllByName0(local, false)[0]; } catch (UnknownHostException uhe) { // Rethrow with a more informative error message. - UnknownHostException uhe2 = - new UnknownHostException(local + ": " + - uhe.getMessage()); + UnknownHostException uhe2 = + new UnknownHostException(formatMsg(filterNonSocketInfo(local) + .suffixWith(": ") + uhe.getMessage())); uhe2.initCause(uhe); throw uhe2; } diff --git a/src/java.base/share/classes/java/net/NetworkInterface.java b/src/java.base/share/classes/java/net/NetworkInterface.java index 8e0f7137315..f6f7d438864 100644 --- a/src/java.base/share/classes/java/net/NetworkInterface.java +++ b/src/java.base/share/classes/java/net/NetworkInterface.java @@ -34,6 +34,8 @@ import java.util.Spliterator; import java.util.Spliterators; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * This class represents a Network Interface. @@ -323,7 +325,9 @@ public final class NetworkInterface { + addr.holder.family); } } else { - throw new IllegalArgumentException("invalid address type: " + addr); + throw new IllegalArgumentException( + formatMsg("invalid address type%s", + filterNonSocketInfo(addr.toString()).prefixWith(": "))); } return getByInetAddress0(addr); } diff --git a/src/java.base/share/classes/java/net/Proxy.java b/src/java.base/share/classes/java/net/Proxy.java index db434238558..4109c586058 100644 --- a/src/java.base/share/classes/java/net/Proxy.java +++ b/src/java.base/share/classes/java/net/Proxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -26,6 +26,8 @@ package java.net; import java.util.Objects; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * This class represents a proxy setting, typically a type (http, socks) and @@ -93,8 +95,11 @@ public class Proxy { * incompatible */ public Proxy(Type type, SocketAddress sa) { - if ((type == Type.DIRECT) || !(sa instanceof InetSocketAddress)) - throw new IllegalArgumentException("type " + type + " is not compatible with address " + sa); + if ((type == Type.DIRECT) || !(sa instanceof InetSocketAddress)) { + throw new IllegalArgumentException( + formatMsg("type " + type + " is not compatible with address %s", + filterNonSocketInfo(String.valueOf(sa)))); + } this.type = type; this.sa = sa; } diff --git a/src/java.base/share/classes/java/net/SocketPermission.java b/src/java.base/share/classes/java/net/SocketPermission.java index e3a85bbf856..eb14099f686 100644 --- a/src/java.base/share/classes/java/net/SocketPermission.java +++ b/src/java.base/share/classes/java/net/SocketPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -46,6 +46,8 @@ import sun.security.util.RegisteredDomain; import sun.security.util.SecurityConstants; import sun.security.util.Debug; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * This class represents access to a network via sockets. @@ -392,8 +394,8 @@ public final class SocketPermission extends Permission if (rb != -1) { host = host.substring(start, rb); } else { - throw new - IllegalArgumentException("invalid host/port: "+host); + throw new IllegalArgumentException( + formatMsg("invalid host/port%s", filterNonSocketInfo(host).prefixWith(": "))); } sep = hostport.indexOf(':', rb+1); } else { @@ -410,8 +412,8 @@ public final class SocketPermission extends Permission try { portrange = parsePort(port); } catch (Exception e) { - throw new - IllegalArgumentException("invalid port range: "+port); + throw new IllegalArgumentException( + formatMsg("invalid port range%s", filterNonSocketInfo(port).prefixWith(": "))); } } else { portrange = new int[] { PORT_MIN, PORT_MAX }; @@ -784,7 +786,7 @@ public final class SocketPermission extends Permission throw uhe; } catch (IndexOutOfBoundsException iobe) { invalid = true; - throw new UnknownHostException(getName()); + throw new UnknownHostException(formatMsg("%s", filterNonSocketInfo(getName()))); } } diff --git a/src/java.base/share/classes/java/net/SocksSocketImpl.java b/src/java.base/share/classes/java/net/SocksSocketImpl.java index 54ff612be02..71794d7a0a6 100644 --- a/src/java.base/share/classes/java/net/SocksSocketImpl.java +++ b/src/java.base/share/classes/java/net/SocksSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -37,6 +37,8 @@ import sun.net.spi.DefaultProxySelector; import sun.net.www.ParseUtil; import static sun.net.util.IPAddressUtil.isIPv6LiteralAddress; +import static jdk.internal.util.Exceptions.filterSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * SOCKS (V4 & V5) TCP socket implementation (RFC 1928). @@ -330,7 +332,7 @@ class SocksSocketImpl extends DelegatingSocketImpl implements SocksConsts { // SOCKS Protocol version 4 doesn't know how to deal with // DOMAIN type of addresses (unresolved addresses here) if (epoint.isUnresolved()) - throw new UnknownHostException(epoint.toString()); + throw new UnknownHostException(formatMsg("%s", filterSocketInfo(epoint.toString()))); connectV4(in, out, epoint, deadlineMillis); return; } @@ -349,7 +351,7 @@ class SocksSocketImpl extends DelegatingSocketImpl implements SocksConsts { // SOCKS Protocol version 4 doesn't know how to deal with // DOMAIN type of addresses (unresolved addresses here) if (epoint.isUnresolved()) - throw new UnknownHostException(epoint.toString()); + throw new UnknownHostException(formatMsg("%s", filterSocketInfo(epoint.toString()))); connectV4(in, out, epoint, deadlineMillis); return; } diff --git a/src/java.base/share/classes/java/net/URI.java b/src/java.base/share/classes/java/net/URI.java index cd116f3877b..daf63d19032 100644 --- a/src/java.base/share/classes/java/net/URI.java +++ b/src/java.base/share/classes/java/net/URI.java @@ -42,8 +42,12 @@ import java.nio.file.Path; import java.text.Normalizer; import jdk.internal.access.JavaNetUriAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.util.Exceptions; import sun.nio.cs.UTF_8; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; + /** * Represents a Uniform Resource Identifier (URI) reference. * @@ -2032,7 +2036,8 @@ public final class URI { if (scheme != null) { if (path != null && !path.isEmpty() && path.charAt(0) != '/') - throw new URISyntaxException(s, "Relative path in absolute URI"); + throw new URISyntaxException(formatMsg("%s", filterNonSocketInfo(s)), + "Relative path in absolute URI"); } } @@ -2988,11 +2993,14 @@ public final class URI // -- Methods for throwing URISyntaxException in various ways -- private void fail(String reason) throws URISyntaxException { - throw new URISyntaxException(input, reason); + throw new URISyntaxException(formatMsg("%s", filterNonSocketInfo(input)), reason); } private void fail(String reason, int p) throws URISyntaxException { - throw new URISyntaxException(input, reason, p); + if (!Exceptions.enhancedNonSocketExceptions()) { + p = -1; + } + throw new URISyntaxException(formatMsg("%s", filterNonSocketInfo(input)), reason, p); } private void failExpecting(String expected, int p) diff --git a/src/java.base/share/classes/java/net/URL.java b/src/java.base/share/classes/java/net/URL.java index be4daa28f33..9266b6c94f1 100644 --- a/src/java.base/share/classes/java/net/URL.java +++ b/src/java.base/share/classes/java/net/URL.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -44,6 +44,8 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.misc.ThreadTracker; import jdk.internal.misc.VM; import sun.net.util.IPAddressUtil; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * Class {@code URL} represents a Uniform Resource @@ -1168,7 +1170,8 @@ public final class URL implements java.io.Serializable { URI uri = new URI(toString()); if (authority != null && isBuiltinStreamHandler(handler)) { String s = IPAddressUtil.checkAuthority(this); - if (s != null) throw new URISyntaxException(authority, s); + if (s != null) + throw new URISyntaxException(formatMsg("%s", filterNonSocketInfo(authority)), s); } return uri; } diff --git a/src/java.base/share/classes/java/net/URLStreamHandler.java b/src/java.base/share/classes/java/net/URLStreamHandler.java index 1400741b2bb..f66902a451e 100644 --- a/src/java.base/share/classes/java/net/URLStreamHandler.java +++ b/src/java.base/share/classes/java/net/URLStreamHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 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 @@ -30,6 +30,9 @@ import java.util.Locale; import java.util.Objects; import sun.net.util.IPAddressUtil; +import static jdk.internal.util.Exceptions.formatMsg; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; + /** * The abstract class {@code URLStreamHandler} is the common * superclass for all stream protocol handlers. A stream protocol @@ -206,7 +209,7 @@ public abstract class URLStreamHandler { if (!IPAddressUtil. isIPv6LiteralAddress(host.substring(1, ind))) { throw new IllegalArgumentException( - "Invalid host: "+ host); + formatMsg("Invalid host%s", filterNonSocketInfo(host).prefixWith(": "))); } port = -1 ; @@ -220,12 +223,14 @@ public abstract class URLStreamHandler { } } else { throw new IllegalArgumentException( - "Invalid authority field: " + authority); + formatMsg("Invalid authority field%s", + filterNonSocketInfo(authority).prefixWith(": "))); } } } else { throw new IllegalArgumentException( - "Invalid authority field: " + authority); + formatMsg("Invalid authority field%s", + filterNonSocketInfo(authority).prefixWith(": "))); } } else { ind = host.indexOf(':'); diff --git a/src/java.base/share/classes/jdk/internal/util/Exceptions.java b/src/java.base/share/classes/jdk/internal/util/Exceptions.java new file mode 100644 index 00000000000..eb4286cd1af --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/util/Exceptions.java @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2018, 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.util; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import sun.security.util.SecurityProperties; +import jdk.internal.misc.VM; + +/** + * Contains static utility methods which can filter exception + * message strings for sensitive information. + * + * Code using this mechanism should use formatMsg() + * to generate a formatted (enhanced or restricted) string for exception + * messages. + * + * The methods above take variable numbers of SensitiveInfo objects + * as parameters which contain the text that may have to be filtered. + * + * The SensitiveInfo objects should be generated with one of the following: + * public static SensitiveInfo filterSocketInfo(String s) + * public static SensitiveInfo filterNonSocketInfo(String s) + * public static SensitiveInfo filterJarName(String name) + * public static SensitiveInfo filterUserName(String name) + */ +public final class Exceptions { + private Exceptions() {} + + private static volatile boolean enhancedSocketExceptionText; + private static volatile boolean enhancedNonSocketExceptionText; + private static volatile boolean enhancedUserExceptionText; + private static volatile boolean enhancedJarExceptionText; + private static volatile boolean initialized = false; + + /** + * Base class for generating exception messages that may + * contain sensitive information which in certain contexts + * needs to be filtered out, in case it gets revealed in + * unexpected places. Exception messages are either enhanced + * or restricted. Enhanced messages include sensitive information. + * Restricted messages don't. + * + * Sub-class for any new category that needs to be independently + * controlled. Consider using a unique value for the + * SecurityProperties.includedInExceptions(String value) mechanism + * Current values defined are "jar", "userInfo" + * "hostInfo", "hostInfoExclSocket". + * + * New code can also piggy back on existing categories + * + * A SensitiveInfo contains the following components + * all of which default to empty strings. + * + * prefix, the sensitive info itself, a suffix + * and a replacement string. + * + * The composeFilteredText(boolean enhance) method generates + * an enhanced string when enhance is true. + * This comprises (enhance == true) + * prefix + info + suffix + * When (enhance == false), then by default the output is: + * "" empty string + * However, if a replacement is set, then when enhance == false + * the output is the replacement string. + */ + public abstract static class SensitiveInfo { + String info, suffix, prefix, replacement; + boolean enhanced; + + SensitiveInfo(String info) { + this.info = info; + prefix = suffix = replacement = ""; + } + public SensitiveInfo prefixWith(String prefix) { + this.prefix = prefix; + return this; + } + public SensitiveInfo suffixWith(String suffix) { + this.suffix = suffix; + return this; + } + public SensitiveInfo replaceWith(String replacement) { + this.replacement = replacement; + return this; + } + + public boolean enhanced() { + return enhanced; + } + + /** + * Implementation should call composeFilteredText(boolean flag) + * where flag contains the boolean value of whether + * the category is enabled or not. + */ + public abstract String output(); + + protected String composeFilteredText(boolean enhance) { + if (enhance) { + this.enhanced = true; + return prefix + info + suffix; + } else { + return replacement; + } + } + } + + static final class SocketInfo extends SensitiveInfo { + public SocketInfo(String host) { + super(host); + } + @Override + public String output() { + setup(); + return super.composeFilteredText(enhancedSocketExceptionText); + } + } + + static final class NonSocketInfo extends SensitiveInfo { + public NonSocketInfo(String host) { + super(host); + } + @Override + public String output() { + setup(); + return super.composeFilteredText(enhancedNonSocketExceptionText); + } + } + + static final class JarInfo extends SensitiveInfo { + public JarInfo(String name) { + super(name); + } + @Override + public String output() { + setup(); + return super.composeFilteredText(enhancedJarExceptionText); + } + } + + static final class UserInfo extends SensitiveInfo { + public UserInfo(String host) { + super(host); + } + @Override + public String output() { + setup(); + return super.composeFilteredText(enhancedUserExceptionText); + } + } + + // remove leading, trailing and duplicated space characters + static String trim(String s) { + int len = s.length(); + if (len == 0) return s; + + StringBuilder sb = new StringBuilder(); + + // initial value deals with leading spaces + boolean inSpace = true; + for (int i=0; i 0 && sb.charAt(sblen - 1) == ' ') + sb.deleteCharAt(sblen - 1); + return sb.toString(); + } + + public static SensitiveInfo filterSocketInfo(String host) { + return new SocketInfo(host); + } + + public static SensitiveInfo filterNonSocketInfo(String host) { + return new NonSocketInfo(host); + } + + public static SensitiveInfo filterJarName(String name) { + return new JarInfo(name); + } + + public static SensitiveInfo filterUserName(String name) { + return new UserInfo(name); + } + + /** + * Transform each SensitiveInfo into a String argument which is passed + * to String.format(). This string is then trimmed. + */ + public static String formatMsg(String format, SensitiveInfo... infos) { + String[] args = new String[infos.length]; + + int i = 0; + + for (SensitiveInfo info : infos) { + args[i++] = info.output(); + } + return trim(String.format(format, (Object[])args)); + } + + /** + * Simplification of above. Equivalent to: + * formatMsg("%s", SensitiveInfo[1]); // ie with one arg + */ + public static String formatMsg(SensitiveInfo info) { + return trim(info.output()); + } + + public static void setup() { + if (initialized || !VM.isBooted()) + return; + enhancedSocketExceptionText = SecurityProperties.includedInExceptions("hostInfo"); + enhancedNonSocketExceptionText = SecurityProperties.includedInExceptions("hostInfoExclSocket") + | enhancedSocketExceptionText; + + enhancedUserExceptionText = SecurityProperties.includedInExceptions("userInfo"); + enhancedJarExceptionText = SecurityProperties.INCLUDE_JAR_NAME_IN_EXCEPTIONS; + initialized = true; + } + + public static boolean enhancedNonSocketExceptions() { + setup(); + return enhancedNonSocketExceptionText; + } + + public static boolean enhancedSocketExceptions() { + setup(); + return enhancedSocketExceptionText; + } + + /** + * The enhanced message text is the socket address appended to + * the original IOException message + */ + public static IOException ioException(IOException e, SocketAddress addr) { + setup(); + if (addr == null) { + return e; + } + if (!enhancedSocketExceptionText) { + return create(e, e.getMessage()); + } + if (addr instanceof UnixDomainSocketAddress) { + return ofUnixDomain(e, (UnixDomainSocketAddress)addr); + } else if (addr instanceof InetSocketAddress) { + return ofInet(e, (InetSocketAddress)addr); + } else { + return e; + } + } + + private static IOException ofInet(IOException e, InetSocketAddress addr) { + return create(e, String.join(": ", e.getMessage(), addr.toString())); + } + + private static IOException ofUnixDomain(IOException e, UnixDomainSocketAddress addr) { + String path = addr.getPath().toString(); + StringBuilder sb = new StringBuilder(); + sb.append(e.getMessage()); + sb.append(": "); + sb.append(path); + String enhancedMsg = sb.toString(); + return create(e, enhancedMsg); + } + + // return a new instance of the same type with the given detail + // msg, or if the type doesn't support detail msgs, return given + // instance. + private static T create(T e, String msg) { + try { + Class clazz = e.getClass(); + @SuppressWarnings("unchecked") + Constructor ctor = (Constructor)clazz.getConstructor(String.class); + T e1 = (ctor.newInstance(msg)); + e1.setStackTrace(e.getStackTrace()); + return e1; + } catch (Exception e0) { + // Some eg AsynchronousCloseException have no detail msg + return e; + } + } +} diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index bbcdfef65ec..07de3f2c57f 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -270,9 +270,13 @@ module java.base { java.prefs, java.security.jgss, java.smartcardio, + java.naming, + java.rmi, + java.net.http, jdk.charsets, jdk.incubator.vector, jdk.internal.vm.ci, + jdk.httpserver, jdk.jlink, jdk.jpackage, jdk.net; diff --git a/src/java.base/share/classes/sun/net/util/IPAddressUtil.java b/src/java.base/share/classes/sun/net/util/IPAddressUtil.java index b3da295c4a7..21bbc5ac455 100644 --- a/src/java.base/share/classes/sun/net/util/IPAddressUtil.java +++ b/src/java.base/share/classes/sun/net/util/IPAddressUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -37,6 +37,9 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import static jdk.internal.util.Exceptions.formatMsg; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; + public class IPAddressUtil { private static final int INADDR4SZ = 4; private static final int INADDR16SZ = 16; @@ -161,7 +164,8 @@ public class IPAddressUtil { * @return an {@code IllegalArgumentException} instance */ public static IllegalArgumentException invalidIpAddressLiteral(String src) { - return new IllegalArgumentException("Invalid IP address literal: " + src); + return new IllegalArgumentException( + formatMsg("Invalid IP address literal%s", filterNonSocketInfo(src).prefixWith(": "))); } /* diff --git a/src/java.base/share/classes/sun/net/util/SocketExceptions.java b/src/java.base/share/classes/sun/net/util/SocketExceptions.java deleted file mode 100644 index 1198898edcb..00000000000 --- a/src/java.base/share/classes/sun/net/util/SocketExceptions.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2018, 2024, 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 sun.net.util; - -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.net.InetSocketAddress; -import java.net.UnixDomainSocketAddress; -import java.net.SocketAddress; - -import sun.security.util.SecurityProperties; - -public final class SocketExceptions { - private SocketExceptions() {} - - private static final boolean enhancedExceptionText = - SecurityProperties.includedInExceptions("hostInfo"); - - /** - * Utility which takes an exception and returns either the same exception - * or a new exception of the same type with the same stack trace - * and detail message enhanced with addressing information from the - * given InetSocketAddress. - * - * If the system/security property "jdk.includeInExceptions" is not - * set or does not contain the category hostInfo, - * then the original exception is returned. - * - * Only specific IOException subtypes are supported. - */ - public static IOException of(IOException e, SocketAddress addr) { - if (!enhancedExceptionText || addr == null) { - return e; - } - if (addr instanceof UnixDomainSocketAddress) { - return ofUnixDomain(e, (UnixDomainSocketAddress)addr); - } else if (addr instanceof InetSocketAddress) { - return ofInet(e, (InetSocketAddress)addr); - } else { - return e; - } - } - - private static IOException ofInet(IOException e, InetSocketAddress addr) { - return create(e, String.join(": ", e.getMessage(), addr.toString())); - } - - private static IOException ofUnixDomain(IOException e, UnixDomainSocketAddress addr) { - String path = addr.getPath().toString(); - StringBuilder sb = new StringBuilder(); - sb.append(e.getMessage()); - sb.append(": "); - sb.append(path); - String enhancedMsg = sb.toString(); - return create(e, enhancedMsg); - } - - // return a new instance of the same type with the given detail - // msg, or if the type doesn't support detail msgs, return given - // instance. - private static IOException create(final IOException e, final String msg) { - try { - Class clazz = e.getClass(); - Constructor ctor = clazz.getConstructor(String.class); - IOException e1 = (IOException)(ctor.newInstance(msg)); - e1.setStackTrace(e.getStackTrace()); - return e1; - } catch (Exception e0) { - // Some eg AsynchronousCloseException have no detail msg - return e; - } - } -} diff --git a/src/java.base/share/classes/sun/net/www/ParseUtil.java b/src/java.base/share/classes/sun/net/www/ParseUtil.java index 51d1b8398b6..cac32e53288 100644 --- a/src/java.base/share/classes/sun/net/www/ParseUtil.java +++ b/src/java.base/share/classes/sun/net/www/ParseUtil.java @@ -40,6 +40,8 @@ import java.nio.charset.CodingErrorAction; import java.util.HexFormat; import sun.nio.cs.UTF_8; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * A class that contains useful routines common to sun.net.www @@ -502,7 +504,7 @@ public final class ParseUtil { { if (scheme != null) { if (path != null && !path.isEmpty() && path.charAt(0) != '/') - throw new URISyntaxException(s, + throw new URISyntaxException(formatMsg("%s", filterNonSocketInfo(s)), "Relative path in absolute URI"); } } diff --git a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java index fb2dfe6fff3..2f011f5805b 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java +++ b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java @@ -53,7 +53,8 @@ import sun.security.ssl.SSLSocketImpl; import sun.util.logging.PlatformLogger; import static sun.net.www.protocol.http.HttpURLConnection.TunnelState.*; - +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * This class provides HTTPS client URL support, building on the standard @@ -559,8 +560,10 @@ final class HttpsClient extends HttpClient serverSocket.close(); session.invalidate(); - throw new IOException("HTTPS hostname wrong: should be <" - + url.getHost() + ">"); + throw new IOException(formatMsg("Wrong HTTPS hostname%s", + filterNonSocketInfo(url.getHost()) + .prefixWith(": should be <") + .suffixWith(">"))); } @Override diff --git a/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java b/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java index 2884f825b84..381d4244238 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -27,6 +27,8 @@ package sun.net.www.protocol.jar; import java.io.IOException; import java.net.*; +import static jdk.internal.util.Exceptions.filterJarName; +import static jdk.internal.util.Exceptions.formatMsg; /* * Jar URL Handler @@ -181,8 +183,11 @@ public class Handler extends java.net.URLStreamHandler { String innerSpec = spec.substring(0, index - 1); newURL(innerSpec); } catch (MalformedURLException e) { - throw new NullPointerException("invalid url: " + - spec + " (" + e + ")"); + throw new NullPointerException( + formatMsg("invalid url: %s %s", filterJarName(spec), + filterJarName(e.getMessage()) + .prefixWith("(") + .suffixWith(")"))); } return spec; } @@ -193,19 +198,18 @@ public class Handler extends java.net.URLStreamHandler { if (spec.startsWith("/")) { int bangSlash = indexOfBangSlash(ctxFile); if (bangSlash == -1) { - throw new NullPointerException("malformed " + - "context url:" + - url + - ": no !/"); + throw new NullPointerException( + formatMsg("malformed context url%s : no !/", + filterJarName(String.valueOf(url)).prefixWith(": "))); } ctxFile = ctxFile.substring(0, bangSlash); } else { // chop up the last component int lastSlash = ctxFile.lastIndexOf('/'); if (lastSlash == -1) { - throw new NullPointerException("malformed " + - "context url:" + - url); + throw new NullPointerException( + formatMsg("malformed context url%s", + filterJarName(String.valueOf(url)).prefixWith(": "))); } else if (lastSlash < ctxFile.length() - 1) { ctxFile = ctxFile.substring(0, lastSlash + 1); } diff --git a/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java b/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java index 4d695c8d4e8..741854349d7 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java @@ -35,6 +35,8 @@ import java.util.jar.JarFile; import jdk.internal.util.OperatingSystem; import sun.net.util.URLUtil; import sun.net.www.ParseUtil; +import static jdk.internal.util.Exceptions.filterJarName; +import static jdk.internal.util.Exceptions.formatMsg; /* A factory for cached JAR file. This class is used to both retrieve * and cache Jar files. @@ -108,7 +110,7 @@ class JarFileFactory implements URLJarFile.URLJarFileCloseController { result = URLJarFile.getJarFile(patched, this); } if (result == null) - throw new FileNotFoundException(url.toString()); + throw new FileNotFoundException(formatMsg("%s", filterJarName(url.toString()))); return result; } @@ -200,7 +202,7 @@ class JarFileFactory implements URLJarFile.URLJarFileCloseController { result = URLJarFile.getJarFile(url, this); } if (result == null) - throw new FileNotFoundException(url.toString()); + throw new FileNotFoundException(formatMsg("%s", filterJarName(url.toString()))); return result; } diff --git a/src/java.base/share/classes/sun/net/www/protocol/jar/JarURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/jar/JarURLConnection.java index 3a346308f71..96c04132551 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/jar/JarURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jar/JarURLConnection.java @@ -37,6 +37,9 @@ import java.util.List; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import static jdk.internal.util.Exceptions.filterJarName; +import static jdk.internal.util.Exceptions.formatMsg; + /** * @author Benjamin Renaud @@ -129,9 +132,10 @@ public class JarURLConnection extends java.net.JarURLConnection { factory.closeIfNotCached(url, jarFile); } catch (Exception e) { } - throw new FileNotFoundException("JAR entry " + entryName + - " not found in " + - jarFile.getName()); + throw new FileNotFoundException( + formatMsg("JAR entry %s not found in jar file %s", + filterJarName(entryName), + filterJarName(jarFile.getName()))); } } @@ -169,9 +173,10 @@ public class JarURLConnection extends java.net.JarURLConnection { throw new IOException("no entry name specified"); } else { if (jarEntry == null) { - throw new FileNotFoundException("JAR entry " + entryName + - " not found in " + - jarFile.getName()); + throw new FileNotFoundException( + formatMsg("JAR entry %s not found in jar file %s", + filterJarName(entryName), + filterJarName(jarFile.getName()))); } result = new JarURLInputStream (jarFile.getInputStream(jarEntry)); } diff --git a/src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java b/src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java index 95bc2179a31..51a88cb229d 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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 diff --git a/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java b/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java index 4930e1447a3..44b05f97472 100644 --- a/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java +++ b/src/java.base/share/classes/sun/nio/ch/DatagramSocketAdaptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -53,6 +53,8 @@ import java.util.Set; import java.util.concurrent.locks.ReentrantLock; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static jdk.internal.util.Exceptions.formatMsg; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; /** * A multicast datagram socket based on a datagram channel. @@ -490,7 +492,8 @@ public class DatagramSocketAdaptor NetworkInterface ni = NetworkInterface.getByInetAddress(inf); if (ni == null) { String address = inf.getHostAddress(); - throw new SocketException("No network interface with address " + address); + throw new SocketException(formatMsg("No network interface found with address %s", + filterNonSocketInfo(address))); } synchronized (outgoingInterfaceLock) { // set interface and update cached values diff --git a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java index b3939f2ca05..6705134648d 100644 --- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java @@ -58,10 +58,12 @@ import sun.net.ConnectionResetException; import sun.net.NetHooks; import sun.net.PlatformSocketImpl; import sun.net.ext.ExtendedSocketOptions; -import sun.net.util.SocketExceptions; +import jdk.internal.util.Exceptions; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.NANOSECONDS; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * NIO based SocketImpl. @@ -554,7 +556,8 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp throw new IOException("Unsupported address type"); InetSocketAddress isa = (InetSocketAddress) remote; if (isa.isUnresolved()) { - throw new UnknownHostException(isa.getHostName()); + throw new UnknownHostException( + formatMsg(filterNonSocketInfo(isa.getHostName()))); } InetAddress address = isa.getAddress(); @@ -604,7 +607,7 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp assert Thread.currentThread().isVirtual(); throw new SocketException("Closed by interrupt"); } else { - throw SocketExceptions.of(ioe, isa); + throw Exceptions.ioException(ioe, isa); } } } diff --git a/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java index d8ed1cfb675..bf777ed23e4 100644 --- a/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java +++ b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java @@ -40,6 +40,9 @@ import java.nio.channels.SocketChannel; import java.util.Set; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; + // Make a socket channel look like a socket. // @@ -92,7 +95,8 @@ class SocketAdaptor if (sc.isConnected()) throw new SocketException("Already connected"); close(); - throw new UnknownHostException(remote.toString()); + throw new UnknownHostException( + formatMsg(filterNonSocketInfo(remote.toString()))); } if (timeout < 0) throw new IllegalArgumentException("connect: timeout can't be negative"); diff --git a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java index 0980592abab..c1241a51f85 100644 --- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -64,7 +64,7 @@ import jdk.internal.event.SocketWriteEvent; import sun.net.ConnectionResetException; import sun.net.NetHooks; import sun.net.ext.ExtendedSocketOptions; -import sun.net.util.SocketExceptions; +import jdk.internal.util.Exceptions; /** * An implementation of SocketChannels @@ -975,7 +975,7 @@ class SocketChannelImpl } catch (IOException ioe) { // connect failed, close the channel close(); - throw SocketExceptions.of(ioe, sa); + throw Exceptions.ioException(ioe, sa); } } @@ -1065,7 +1065,7 @@ class SocketChannelImpl } catch (IOException ioe) { // connect failed, close the channel close(); - throw SocketExceptions.of(ioe, remoteAddress); + throw Exceptions.ioException(ioe, remoteAddress); } } @@ -1313,7 +1313,7 @@ class SocketChannelImpl } catch (IOException ioe) { // connect failed, close the channel close(); - throw SocketExceptions.of(ioe, sa); + throw Exceptions.ioException(ioe, sa); } } diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index b750c1b82b0..61e8aaaf6d1 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1277,8 +1277,13 @@ jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep # # Enhanced exception message information # -# By default, exception messages should not include potentially sensitive -# information such as file names, host names, or port numbers. This property +# Exception messages may include potentially sensitive information such as file +# names, host names, or port numbers. By default, socket related exceptions +# have this information restricted (meaning the sensitive details are removed). +# Exception messages relating to JAR files and exceptions containing user +# identity information are also restricted by default. +# This property can be used to relax this restriction or to place further +# restrictions on other categories, defined below. The property # accepts one or more comma separated values, each of which represents a # category of enhanced exception message information to enable. Values are # case-insensitive. Leading and trailing whitespaces, surrounding each value, @@ -1291,17 +1296,28 @@ jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep # # The categories are: # -# hostInfo - IOExceptions thrown by java.net.Socket and the socket types in the -# java.nio.channels package will contain enhanced exception -# message information +# hostInfo - All networking related exceptions will contain enhanced +# exception message information. +# +# hostInfoExclSocket - The hostInfo category defined above, excluding +# IOExceptions thrown by java.net.Socket and the NetworkChannel +# types in the java.nio.channels package, will contain enhanced +# exception message information # # jar - enables more detailed information in the IOExceptions thrown # by classes in the java.util.jar package # +# userInfo - enables more detailed information in exceptions which may contain +# user identity information +# # The property setting in this file can be overridden by a system property of # the same name, with the same syntax and possible values. # -#jdk.includeInExceptions=hostInfo,jar +# If the property is not set or set to an empty string, then this is the most +# restricted setting with all categories disabled. The following is the default +# (out of the box) setting, meaning these categories are not restricted. +# +jdk.includeInExceptions=hostInfoExclSocket # # Disabled mechanisms for the Simple Authentication and Security Layer (SASL) @@ -1557,4 +1573,4 @@ jdk.tls.alpnCharset=ISO_8859_1 # java.security.PEMEncoder when configured for encryption with the # withEncryption method. # -jdk.epkcs8.defaultAlgorithm=PBEWithHmacSHA256AndAES_128 \ No newline at end of file +jdk.epkcs8.defaultAlgorithm=PBEWithHmacSHA256AndAES_128 diff --git a/src/java.base/share/native/libnet/net_util.c b/src/java.base/share/native/libnet/net_util.c index a198152563a..9c0f14b0d90 100644 --- a/src/java.base/share/native/libnet/net_util.c +++ b/src/java.base/share/native/libnet/net_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -86,9 +86,36 @@ DEF_JNI_OnLoad(JavaVM *vm, void *reserved) /* check if SO_REUSEPORT is supported on this platform */ REUSEPORT_available = reuseport_supported(IPv6_available); + return JNI_VERSION_1_2; } +static int enhancedExceptionsInitialized = 0; +static int enhancedExceptionsAllowed = -1; + +#define CHECK_NULL_THROW_ERROR(X) \ + if (X == NULL) { \ + JNU_ThrowByName(env, "java/lang/InternalError", \ + "can't initialize enhanced exceptions"); \ + return -1; \ + } + +int getEnhancedExceptionsAllowed(JNIEnv *env) { + jclass cls; + jfieldID fid; + + if (enhancedExceptionsInitialized) { + return enhancedExceptionsAllowed; + } + cls = (*env)->FindClass(env, "jdk/internal/util/Exceptions"); + CHECK_NULL_THROW_ERROR(cls); + fid = (*env)->GetStaticFieldID(env, cls, "enhancedNonSocketExceptionText", "Z"); + CHECK_NULL_THROW_ERROR(fid); + enhancedExceptionsAllowed = (*env)->GetStaticBooleanField(env, cls, fid); + enhancedExceptionsInitialized = 1; + return enhancedExceptionsAllowed; +} + static int initialized = 0; JNIEXPORT void JNICALL initInetAddressIDs(JNIEnv *env) { diff --git a/src/java.base/share/native/libnet/net_util.h b/src/java.base/share/native/libnet/net_util.h index a1fa9571821..89537a7f47d 100644 --- a/src/java.base/share/native/libnet/net_util.h +++ b/src/java.base/share/native/libnet/net_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -183,4 +183,6 @@ int lookupCharacteristicsToAddressFamily(int characteristics); int addressesInSystemOrder(int characteristics); +int getEnhancedExceptionsAllowed(JNIEnv *env); + #endif /* NET_UTILS_H */ diff --git a/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java b/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java index b9c099ef92f..5e75e3b2486 100644 --- a/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java +++ b/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -32,9 +32,10 @@ import java.util.concurrent.*; import java.io.IOException; import java.io.FileDescriptor; +import jdk.internal.util.Exceptions; + import sun.net.ConnectionResetException; import sun.net.NetHooks; -import sun.net.util.SocketExceptions; /** * Unix implementation of AsynchronousSocketChannel @@ -264,7 +265,7 @@ class UnixAsynchronousSocketChannelImpl if (e != null) { if (e instanceof IOException) { var isa = (InetSocketAddress)pendingRemote; - e = SocketExceptions.of((IOException)e, isa); + e = Exceptions.ioException((IOException)e, isa); } // close channel if connection cannot be established try { @@ -355,7 +356,7 @@ class UnixAsynchronousSocketChannelImpl // close channel if connect fails if (e != null) { if (e instanceof IOException) { - e = SocketExceptions.of((IOException)e, isa); + e = Exceptions.ioException((IOException)e, isa); } try { close(); diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java b/src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java index f50dea108b0..b1e7b7cbcc4 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -29,6 +29,9 @@ import java.nio.file.attribute.*; import java.io.IOException; import static sun.nio.fs.UnixNativeDispatcher.*; +import static jdk.internal.util.Exceptions.filterUserName; +import static jdk.internal.util.Exceptions.formatMsg; + /** * Unix implementation of java.nio.file.attribute.UserPrincipal */ @@ -132,18 +135,19 @@ public class UnixUserPrincipals { private static int lookupName(String name, boolean isGroup) throws IOException { - int id; + int id = -1; try { id = (isGroup) ? getgrnam(name) : getpwnam(name); } catch (UnixException x) { - throw new IOException(name + ": " + x.errorString()); + throw new IOException(formatMsg("%s " + x.errorString(), + filterUserName(name).suffixWith(": "))); } if (id == -1) { // lookup failed, allow input to be uid or gid try { id = Integer.parseInt(name); } catch (NumberFormatException ignore) { - throw new UserPrincipalNotFoundException(name); + throw new UserPrincipalNotFoundException(formatMsg("%s", filterUserName(name))); } } return id; diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c index 1713d0a8ccd..d50130d188b 100644 --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -184,23 +184,36 @@ void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, { int size; char *buf; - const char *format = "%s: %s"; const char *error_string = gai_strerror(gai_error); if (error_string == NULL) error_string = "unknown error"; + int enhancedExceptions = getEnhancedExceptionsAllowed(env); + + if (enhancedExceptions) { + size = strlen(hostname); + } else { + size = 0; + } + size += strlen(error_string) + 3; - size = strlen(format) + strlen(hostname) + strlen(error_string) + 2; buf = (char *) malloc(size); if (buf) { jstring s; - snprintf(buf, size, format, hostname, error_string); - s = JNU_NewStringPlatform(env, buf); - if (s != NULL) { - jobject x = JNU_NewObjectByName(env, + int n; + if (enhancedExceptions) { + n = snprintf(buf, size, "%s: %s", hostname, error_string); + } else { + n = snprintf(buf, size, " %s", error_string); + } + if (n >= 0) { + s = JNU_NewStringPlatform(env, buf); + if (s != NULL) { + jobject x = JNU_NewObjectByName(env, "java/net/UnknownHostException", "(Ljava/lang/String;)V", s); - if (x != NULL) - (*env)->Throw(env, x); + if (x != NULL) + (*env)->Throw(env, x); + } } free(buf); } diff --git a/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java b/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java index f8b5fab4316..36065f040a0 100644 --- a/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java +++ b/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -33,9 +33,9 @@ import java.nio.BufferOverflowException; import java.net.*; import java.util.concurrent.*; import java.io.IOException; +import jdk.internal.util.Exceptions; import jdk.internal.invoke.MhUtil; import jdk.internal.misc.Unsafe; -import sun.net.util.SocketExceptions; /** * Windows implementation of AsynchronousSocketChannel using overlapped I/O. @@ -253,7 +253,7 @@ class WindowsAsynchronousSocketChannelImpl if (exc != null) { closeChannel(); - exc = SocketExceptions.of(toIOException(exc), remote); + exc = Exceptions.ioException(toIOException(exc), remote); result.setFailure(exc); } Invoker.invoke(result); @@ -280,7 +280,7 @@ class WindowsAsynchronousSocketChannelImpl if (exc != null) { closeChannel(); IOException ee = toIOException(exc); - ee = SocketExceptions.of(ee, remote); + ee = Exceptions.ioException(ee, remote); result.setFailure(ee); } @@ -296,12 +296,12 @@ class WindowsAsynchronousSocketChannelImpl */ @Override public void failed(int error, IOException x) { - x = SocketExceptions.of(x, remote); + x = Exceptions.ioException(x, remote); if (isOpen()) { closeChannel(); result.setFailure(x); } else { - x = SocketExceptions.of(new AsynchronousCloseException(), remote); + x = Exceptions.ioException(new AsynchronousCloseException(), remote); result.setFailure(x); } Invoker.invoke(result); diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java b/src/java.base/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java index da3460592f4..8c3dfa5546e 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -33,6 +33,8 @@ import jdk.internal.misc.Unsafe; import static sun.nio.fs.WindowsNativeDispatcher.*; import static sun.nio.fs.WindowsConstants.*; +import static jdk.internal.util.Exceptions.filterUserName; +import static jdk.internal.util.Exceptions.formatMsg; /** * A SecurityDescriptor for use when setting a file's ACL or creating a file @@ -136,8 +138,8 @@ class WindowsSecurityDescriptor { Math.max(SIZEOF_ACCESS_ALLOWED_ACE, SIZEOF_ACCESS_DENIED_ACE); } catch (WindowsException x) { - throw new IOException("Failed to get SID for " + user.getName() - + ": " + x.errorString()); + throw new IOException(formatMsg("Failed to get SID %s : " + x.errorString(), + filterUserName(user.getName()).prefixWith("for "))); } } diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsUserPrincipals.java b/src/java.base/windows/classes/sun/nio/fs/WindowsUserPrincipals.java index 336bbe22cfb..0a4e2b9c9fa 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsUserPrincipals.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsUserPrincipals.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -29,6 +29,8 @@ import java.io.IOException; import static sun.nio.fs.WindowsConstants.*; import static sun.nio.fs.WindowsNativeDispatcher.*; +import static jdk.internal.util.Exceptions.formatMsg; +import static jdk.internal.util.Exceptions.filterUserName; class WindowsUserPrincipals { private WindowsUserPrincipals() { } @@ -132,13 +134,14 @@ class WindowsUserPrincipals { static UserPrincipal lookup(String name) throws IOException { // invoke LookupAccountName to get buffer size needed for SID - int size; + int size = 0; try { size = LookupAccountName(name, 0L, 0); } catch (WindowsException x) { if (x.lastError() == ERROR_NONE_MAPPED) throw new UserPrincipalNotFoundException(name); - throw new IOException(name + ": " + x.errorString()); + throw new IOException(formatMsg("%s " + x.errorString(), + filterUserName(name).suffixWith(": "))); } assert size > 0; @@ -153,7 +156,8 @@ class WindowsUserPrincipals { // return user principal return fromSid(sidBuffer.address()); } catch (WindowsException x) { - throw new IOException(name + ": " + x.errorString()); + throw new IOException(formatMsg("%s " + x.errorString(), + filterUserName(name).suffixWith(": "))); } } } diff --git a/src/java.base/windows/native/libnet/Inet4AddressImpl.c b/src/java.base/windows/native/libnet/Inet4AddressImpl.c index 0e2d6a3455f..0ef0cae5be7 100644 --- a/src/java.base/windows/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/windows/native/libnet/Inet4AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -88,8 +88,9 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, if (error) { // report error - NET_ThrowByNameWithLastError(env, "java/net/UnknownHostException", - hostname); + NET_ThrowByNameWithLastError( + env, "java/net/UnknownHostException", + getEnhancedExceptionsAllowed(env) ? hostname : ""); goto cleanupAndReturn; } else { int i = 0; diff --git a/src/java.base/windows/native/libnet/Inet6AddressImpl.c b/src/java.base/windows/native/libnet/Inet6AddressImpl.c index 244e2fefa9b..0281e2ddecb 100644 --- a/src/java.base/windows/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/windows/native/libnet/Inet6AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -84,7 +84,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, if (error) { // report error NET_ThrowByNameWithLastError(env, "java/net/UnknownHostException", - hostname); + getEnhancedExceptionsAllowed(env) ? hostname : ""); goto cleanupAndReturn; } else { int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0, diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapURL.java b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapURL.java index 140f025b779..d9319818801 100644 --- a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapURL.java +++ b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapURL.java @@ -33,6 +33,8 @@ import java.util.Locale; import java.util.StringTokenizer; import com.sun.jndi.toolkit.url.Uri; import com.sun.jndi.toolkit.url.UrlUtil; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /* * Extract components of an LDAP URL. @@ -119,7 +121,8 @@ public final class LdapURL extends Uri { @Override protected MalformedURLException newInvalidURISchemeException(String uri) { - return new MalformedURLException("Not an LDAP URL: " + uri); + return new MalformedURLException(formatMsg("Not an LDAP URL%s", + filterNonSocketInfo(uri).prefixWith(": "))); } @Override diff --git a/src/java.naming/share/classes/com/sun/jndi/toolkit/url/Uri.java b/src/java.naming/share/classes/com/sun/jndi/toolkit/url/Uri.java index 10316b1ca69..a4db62868b0 100644 --- a/src/java.naming/share/classes/com/sun/jndi/toolkit/url/Uri.java +++ b/src/java.naming/share/classes/com/sun/jndi/toolkit/url/Uri.java @@ -29,6 +29,8 @@ package com.sun.jndi.toolkit.url; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** @@ -232,6 +234,12 @@ public class Uri { } } + private MalformedURLException newMalformedURLException(String prefix, String msg) { + return new MalformedURLException(prefix + + formatMsg(filterNonSocketInfo(msg) + .prefixWith(prefix.isEmpty()? "" : ": "))); + } + /* * Parses a URI string and sets this object's fields accordingly. * Use java.net.URI to validate the uri string syntax @@ -241,7 +249,7 @@ public class Uri { if (!isSchemeOnly(uri)) { URI u = new URI(uri); scheme = u.getScheme(); - if (scheme == null) throw new MalformedURLException("Invalid URI: " + uri); + if (scheme == null) throw newMalformedURLException("Invalid URI", uri); var auth = u.getRawAuthority(); hasAuthority = auth != null; if (hasAuthority) { @@ -253,7 +261,7 @@ public class Uri { + (port == -1 ? "" : (":" + port)); if (!hostport.equals(auth)) { // throw if we have user info or regname - throw new MalformedURLException("unsupported authority: " + auth); + throw newMalformedURLException("unsupported authority", auth); } } path = u.getRawPath(); @@ -262,7 +270,7 @@ public class Uri { } if (u.getRawFragment() != null) { if (!acceptsFragment()) { - throw new MalformedURLException("URI fragments not supported: " + uri); + throw newMalformedURLException("URI fragments not supported", uri); } fragment = "#" + u.getRawFragment(); } @@ -279,7 +287,7 @@ public class Uri { path = ""; } } catch (URISyntaxException e) { - var mue = new MalformedURLException(e.getMessage()); + var mue = newMalformedURLException("", e.getMessage()); mue.initCause(e); throw mue; } @@ -299,11 +307,11 @@ public class Uri { int qmark = uri.indexOf('?'); int fmark = uri.indexOf('#'); if (i < 0 || slash > 0 && i > slash || qmark > 0 && i > qmark || fmark > 0 && i > fmark) { - throw new MalformedURLException("Invalid URI: " + uri); + throw newMalformedURLException("Invalid URI", uri); } if (fmark > -1) { if (!acceptsFragment()) { - throw new MalformedURLException("URI fragments not supported: " + uri); + throw newMalformedURLException("URI fragments not supported", uri); } } if (i == uri.length() - 1) { @@ -349,26 +357,26 @@ public class Uri { String f = u.getRawFragment(); String ui = u.getRawUserInfo(); if (ui != null) { - throw new MalformedURLException("user info not supported in authority: " + ui); + throw newMalformedURLException("user info not supported in authority", ui); } if (!"/".equals(p)) { - throw new MalformedURLException("invalid authority: " + auth); + throw newMalformedURLException("invalid authority", auth); } if (q != null) { - throw new MalformedURLException("invalid trailing characters in authority: ?" + q); + throw newMalformedURLException("invalid trailing characters in authority '?'", "?" + q); } if (f != null) { - throw new MalformedURLException("invalid trailing characters in authority: #" + f); + throw newMalformedURLException("invalid trailing characters in authority: '#'", "#" + f); } String hostport = (host == null ? "" : host) + (port == -1?"":(":" + port)); if (!auth.equals(hostport)) { // throw if we have user info or regname - throw new MalformedURLException("Authority component is not server-based, " + - "or contains user info. Unsupported authority: " + auth); + throw newMalformedURLException("Authority component is not server-based, " + + "or contains user info. Unsupported authority", auth); } } catch (URISyntaxException e) { - var mue = new MalformedURLException(e.getMessage()); + var mue = newMalformedURLException("", e.getMessage()); mue.initCause(e); throw mue; } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java index e4dee55d8ea..a495fcce1ee 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -39,6 +39,8 @@ import static java.util.Objects.requireNonNull; import static jdk.internal.net.http.common.Utils.isValidName; import static jdk.internal.net.http.common.Utils.isValidValue; import static jdk.internal.net.http.common.Utils.newIAE; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; public class HttpRequestBuilderImpl implements HttpRequest.Builder { @@ -82,7 +84,8 @@ public class HttpRequestBuilderImpl implements HttpRequest.Builder { throw newIAE("invalid URI scheme %s", scheme); } if (uri.getHost() == null) { - throw newIAE("unsupported URI %s", uri); + throw new IllegalArgumentException( + formatMsg("unsupported URI %s", filterNonSocketInfo(uri.toString()))); } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java b/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java index 79b2332ae37..a74c632c218 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -46,6 +46,7 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import jdk.internal.net.http.ResponseSubscribers.PathSubscriber; +import jdk.internal.util.Exceptions; import static java.util.regex.Pattern.CASE_INSENSITIVE; public final class ResponseBodyHandlers { @@ -190,7 +191,12 @@ public final class ResponseBodyHandlers { static final UncheckedIOException unchecked(ResponseInfo rinfo, String msg) { - String s = String.format("%s in response [%d, %s]", msg, rinfo.statusCode(), rinfo.headers()); + String s; + if (Exceptions.enhancedNonSocketExceptions()) { + s = String.format("%s in response [%d, %s]", msg, rinfo.statusCode(), rinfo.headers()); + } else { + s = String.format("%s in response [%d]", msg, rinfo.statusCode()); + } return new UncheckedIOException(new IOException(s)); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/websocket/OpeningHandshake.java b/src/java.net.http/share/classes/jdk/internal/net/http/websocket/OpeningHandshake.java index c1c0853504c..6e76a272cd0 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/websocket/OpeningHandshake.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/websocket/OpeningHandshake.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -61,6 +61,8 @@ import java.util.concurrent.CompletableFuture; import static java.lang.String.format; import static jdk.internal.net.http.common.Utils.isValidName; import static jdk.internal.net.http.common.Utils.stringOf; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; public class OpeningHandshake { @@ -336,9 +338,13 @@ public class OpeningHandshake { if (!("ws".equalsIgnoreCase(scheme) || "wss".equalsIgnoreCase(scheme))) throw illegal("invalid URI scheme: " + scheme); if (uri.getHost() == null) - throw illegal("URI must contain a host: " + uri); + throw new IllegalArgumentException( + formatMsg("URI must contain a host%s", + filterNonSocketInfo(uri.toString()).prefixWith(": "))); if (uri.getFragment() != null) - throw illegal("URI must not contain a fragment: " + uri); + throw new IllegalArgumentException( + formatMsg("URI must not contain a fragment%s", + filterNonSocketInfo(uri.toString()).prefixWith(": "))); return uri; } diff --git a/src/java.rmi/share/classes/java/rmi/Naming.java b/src/java.rmi/share/classes/java/rmi/Naming.java index c4677991770..cb8766564a9 100644 --- a/src/java.rmi/share/classes/java/rmi/Naming.java +++ b/src/java.rmi/share/classes/java/rmi/Naming.java @@ -28,6 +28,8 @@ import java.rmi.registry.*; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * The Naming class provides methods for storing and obtaining @@ -221,6 +223,11 @@ public final class Naming { return LocateRegistry.getRegistry(parsed.host, parsed.port); } + private static MalformedURLException newMalformedURLException(String prefix, String msg) { + return new MalformedURLException( + prefix + formatMsg(filterNonSocketInfo(msg).prefixWith(": "))); + } + /** * Dissect Naming URL strings to obtain referenced host, port and * object name. @@ -240,8 +247,8 @@ public final class Naming { * '//:' forms will result in a URI syntax exception * Convert the authority to a localhost: form */ - MalformedURLException mue = new MalformedURLException( - "invalid URL String: " + str); + MalformedURLException mue = newMalformedURLException( + "invalid URL String", str); mue.initCause(ex); int indexSchemeEnd = str.indexOf(':'); int indexAuthorityBegin = str.indexOf("//:"); @@ -272,22 +279,22 @@ public final class Naming { { URI uri = new URI(str); if (uri.isOpaque()) { - throw new MalformedURLException( - "not a hierarchical URL: " + str); + throw newMalformedURLException( + "not a hierarchical URL", str); } if (uri.getFragment() != null) { - throw new MalformedURLException( - "invalid character, '#', in URL name: " + str); + throw newMalformedURLException( + "invalid character, '#', in URL name", str); } else if (uri.getQuery() != null) { - throw new MalformedURLException( - "invalid character, '?', in URL name: " + str); + throw newMalformedURLException( + "invalid character, '?', in URL name", str); } else if (uri.getUserInfo() != null) { - throw new MalformedURLException( - "invalid character, '@', in URL host: " + str); + throw newMalformedURLException( + "invalid character, '@', in URL host", str); } String scheme = uri.getScheme(); if (scheme != null && !scheme.equals("rmi")) { - throw new MalformedURLException("invalid URL scheme: " + str); + throw newMalformedURLException("invalid URL scheme", str); } String name = uri.getPath(); diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/JWebServer.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/JWebServer.java index c97162ef9bd..d6a42d366c8 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/JWebServer.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/JWebServer.java @@ -35,6 +35,8 @@ public class JWebServer { private static final String SYS_PROP_MAX_CONNECTIONS = "jdk.httpserver.maxConnections"; private static final String DEFAULT_JWEBSERVER_MAX_CONNECTIONS = "200"; + private static final String SYS_PROP_ENHANCED_EXCEP = "jdk.includeInExceptions"; + private static final String DEFAULT_ENHANCED_EXCEP = "net"; /** * This constructor should never be called. */ @@ -61,6 +63,7 @@ public class JWebServer { */ public static void main(String... args) { setMaxReqTime(); + setEnhancedExceptions(); setMaxConnectionsIfNotSet(); int ec = SimpleFileServerImpl.start(new PrintWriter(System.out, true), "jwebserver", args); @@ -80,6 +83,14 @@ public class JWebServer { } } + static void setEnhancedExceptions() { + if (System.getProperty(SYS_PROP_ENHANCED_EXCEP) != null) { + // an explicit value has already been set, so we don't override it + return; + } + System.setProperty(SYS_PROP_ENHANCED_EXCEP, DEFAULT_ENHANCED_EXCEP); + } + static void setMaxConnectionsIfNotSet() { if (System.getProperty(SYS_PROP_MAX_CONNECTIONS) == null) { System.setProperty(SYS_PROP_MAX_CONNECTIONS, DEFAULT_JWEBSERVER_MAX_CONNECTIONS); diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java index 5a16bedc29d..a82b0bf5a6f 100644 --- a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java @@ -226,7 +226,11 @@ public class CommandLineNegativeTest { } static OutputAnalyzer simpleserver(String... args) throws Throwable { - var pb = new ProcessBuilder(args) + String[] nargs = new String[args.length + 1]; + nargs[0] = args[0]; + System.arraycopy(args, 1, nargs, 2, args.length-1); + nargs[1] = "-Djdk.includeInExceptions=hostInfo"; + var pb = new ProcessBuilder(nargs) .directory(TEST_DIR.toFile()); var outputAnalyser = ProcessTools.executeCommand(pb) .outputTo(System.out) diff --git a/test/jdk/java/net/URI/Test.java b/test/jdk/java/net/URI/Test.java index 95dd49ea34f..57da0ac3607 100644 --- a/test/jdk/java/net/URI/Test.java +++ b/test/jdk/java/net/URI/Test.java @@ -26,6 +26,7 @@ * @bug 4464135 4505046 4503239 4438319 4991359 4866303 7023363 7041800 * 7171415 6339649 6933879 8037396 8272072 8051627 8297687 8353013 * @author Mark Reinhold + * @run main/othervm Test */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/jdk/security/JavaDotSecurity/TestJDKIncludeInExceptions.java b/test/jdk/jdk/security/JavaDotSecurity/TestJDKIncludeInExceptions.java index 353309c1654..011fc6bbaf4 100644 --- a/test/jdk/jdk/security/JavaDotSecurity/TestJDKIncludeInExceptions.java +++ b/test/jdk/jdk/security/JavaDotSecurity/TestJDKIncludeInExceptions.java @@ -28,7 +28,7 @@ import java.security.Security; * @bug 8207846 8208691 * @summary Test the default setting of the jdk.net.includeInExceptions * security property - * @comment In OpenJDK, this property is empty by default and on purpose. + * @comment In OpenJDK, this property has value "hostInfoExclSocket" by default * This test assures the default is not changed. * @run main TestJDKIncludeInExceptions */ @@ -36,9 +36,9 @@ public class TestJDKIncludeInExceptions { public static void main(String args[]) throws Exception { String incInExc = Security.getProperty("jdk.includeInExceptions"); - if (incInExc != null) { + if (incInExc == null || !incInExc.equals("hostInfoExclSocket")) { throw new RuntimeException("Test failed: default value of " + - "jdk.includeInExceptions security property is not null: " + + "jdk.includeInExceptions security property does not have expected value: " + incInExc); } } diff --git a/test/jdk/sun/net/util/ExceptionsTest.java b/test/jdk/sun/net/util/ExceptionsTest.java new file mode 100644 index 00000000000..d6717763afb --- /dev/null +++ b/test/jdk/sun/net/util/ExceptionsTest.java @@ -0,0 +1,172 @@ +/* + * 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. + * + * 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.IOException; +import java.net.InetAddress; +import java.util.Arrays; +import jdk.internal.util.Exceptions; +import jdk.internal.util.Exceptions.SensitiveInfo; +import static jdk.internal.util.Exceptions.formatMsg; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.enhancedNonSocketExceptions; + +/* + * @test + * @bug 8348986 + * @summary Improve coverage of enhanced exception messages + * @modules java.base/jdk.internal.util + * @run main/othervm -Djdk.includeInExceptions=hostInfo ExceptionsTest + * @run main/othervm ExceptionsTest + * @run main/othervm -Djdk.includeInExceptions=userInfo ExceptionsTest + * @run main/othervm -Djdk.net.hosts.file=does.not.exist -Djdk.includeInExceptions=userInfo ExceptionsTest + * @run main/othervm -Djdk.net.hosts.file=does.not.exist -Djdk.includeInExceptions=hostInfo ExceptionsTest + */ +public class ExceptionsTest { + + static boolean netEnabled() { + System.out.printf("netEnabled = %b\n", enhancedNonSocketExceptions()); + return enhancedNonSocketExceptions(); + } + + static boolean dnsEnabled() { + System.out.printf("dnsEnabled = %b\n", enhancedNonSocketExceptions()); + return enhancedNonSocketExceptions(); + } + + static boolean hostFileEnabled() { + return System.getProperty("jdk.net.hosts.file", "").length() > 0; + } + + static String[][][] tests = { + // + // If a format argument is of the form ".pre(xxx)" or ".suf(yyy)", then that is + // interpreted as a .prefixWith("xxx") or .suffixWith("yyy") call to the preceding + // argument. .rep() signifies .replaceWith() + // + // Number of elements in array + // --------------------------- + // 1 N 2 + // + // Format string args to format Enhanced o/p non-enhanced o/p + // + /* 1 */ {{"foo: %s bar"}, {"abc"}, {"foo: abc bar", "foo: bar"}}, + /* 2 */ {{"foo: %s bar"}, {"a", "b"}, {"foo: a bar", "foo: bar"}}, + /* 3 */ {{"foo: %s bar"}, {null}, {"foo: null bar", "foo: bar"}}, + /* 4 */ {{"foo: %s bar"}, {""}, {"foo: bar", "foo: bar"}}, + /* 5 */ {{"%s foo: %s bar"}, {"a", "b"}, {"a foo: b bar", "foo: bar"}}, + /* 6 */ {{"foo: %s bar %s"}, {"a", "b"}, {"foo: a bar b", "foo: bar"}}, + /* 7 */ {{"foo: %s bar %s"}, {"abc", "def"}, {"foo: abc bar def", "foo: bar"}}, + /* 8 */ {{"%s bar %s"}, {"abc", ".pre(foo: )", "def"}, {"foo: abc bar def", "bar"}}, + /* 9 */ {{"%s baz"}, {"abc", ".suf(: bar)"}, {"abc: bar baz", "baz"}}, + /* 10 */ {{"%s baz"}, {"abc", ".suf(: bar)" + , ".rep(bob)"}, {"abc: bar baz", "bob baz"}} + }; + + + static void dnsTest() { + String host = "fub.z.a.bar.foo"; + try { + var addr = InetAddress.getByName(host); + } catch (IOException e) { + if (!dnsEnabled() && e.toString().contains(host)) + throw new RuntimeException("Name lookup failed"); + } + } + + static void hostFileTest() { + String result1 = "Unable to resolve host www.rte.ie as hosts file does.not.exist not found"; + String result2 = "Unable to resolve host as hosts file " + + "from ${jdk.net.hosts.file} system property not found"; + + try { + var a = InetAddress.getByName("www.rte.ie"); + } catch (IOException e) { + if (dnsEnabled() && !e.toString().contains(result1)) { + System.out.println("Lookup failed: " + e.toString()); + throw new RuntimeException("Name lookup failed"); + } + if (!dnsEnabled() && !e.toString().contains(result2)) { + System.out.println("Lookup failed: " + e.toString()); + throw new RuntimeException("Name lookup failed"); + } + } + } + + + final static String PRE = ".pre("; + final static String SUF = ".suf("; + final static String REP = ".rep("; + + static SensitiveInfo[] getArgs(String[] args) { + SensitiveInfo[] sa = new SensitiveInfo[args.length]; + + int index = 0; + for (String s : args) { + if (s != null && s.startsWith(PRE)) { + var preArg = s.substring(PRE.length(), s.indexOf(')')); + sa[index-1] = sa[index-1].prefixWith(preArg); + } else if (s != null && s.startsWith(SUF)) { + var sufArg = s.substring(SUF.length(), s.indexOf(')')); + sa[index-1] = sa[index-1].suffixWith(sufArg); + } else if (s != null && s.startsWith(REP)) { + var repArg = s.substring(REP.length(), s.indexOf(')')); + sa[index-1] = sa[index-1].replaceWith(repArg); + } else { + sa[index++] = filterNonSocketInfo(s); + } + } + return Arrays.copyOf(sa, index); + } + + public static void main(String[] a) { + if (!hostFileEnabled()) { + dnsTest(); + } else { + hostFileTest(); + return; + } + + int count = 1; + for (String[][] test : tests) { + String format = test[0][0]; + String expectedEnhanced = test[2][0]; + String expectedNormal = test[2][1]; + SensitiveInfo[] args = getArgs(test[1]); + + String output = formatMsg(format, args); + if (netEnabled()) { + if (!output.equals(expectedEnhanced)) { + var msg = String.format("FAIL %d: got: \"%s\" Expected: \"%s\"", count, + output, expectedEnhanced); + throw new RuntimeException(msg); + } + } else { + if (!output.equals(expectedNormal)) { + var msg = String.format("FAIL %d: got: \"%s\" Expected: \"%s\"", count, + output, expectedNormal); + throw new RuntimeException(msg); + } + } + count++; + } + } +}