8353440: Disable FTP fallback for non-local file URLs by default

Reviewed-by: dfuchs
This commit is contained in:
Eirik Bjørsnøs 2025-05-08 14:52:53 +00:00
parent 57297e60de
commit 2ea629f3f2
7 changed files with 155 additions and 16 deletions

View File

@ -169,6 +169,17 @@ to determine the proxy that should be used for connecting to a given URI.</P>
globally through their user interface). Note that this property is
checked only once at startup.</P>
</UL>
<a id="FileHandler"></a>
<H2>File URL stream protocol handler properties</H2>
<P>The following properties are used to configure the handler for URLs with the {@code file://} scheme:</P>
<UL>
<LI><P><B>{@systemProperty jdk.net.file.ftpfallback}</B> (default: &lt;false&gt;)<BR>
The {@code file://} handler by default rejects any non-local file URL (as defined by RFC 8089)
as invalid. Setting this property to <B>true</B> enables a legacy feature where
the handler instead opens an FTP connection for such non-local URLs.</P>
<P>Any modern code should use explicit {@code ftp://} URLs instead and not rely on
enabling this legacy FTP fallback feature.</P>
</UL>
<a id="MiscHTTP"></a>
<H2>Misc HTTP URL stream protocol handler properties</H2>
<UL>

View File

@ -25,6 +25,7 @@
package sun.net.www.protocol.file;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.FileNameMap;
import java.io.*;
@ -46,6 +47,11 @@ public class FileURLConnection extends URLConnection {
private static final String TEXT_PLAIN = "text/plain";
private static final String LAST_MODIFIED = "last-modified";
// The feature of falling back to FTP for non-local file URLs is disabled
// by default and can be re-enabled by setting a system property
private static final boolean FTP_FALLBACK_ENABLED =
Boolean.getBoolean("jdk.net.file.ftpfallback");
private final File file;
private InputStream is;
private List<String> directoryListing;
@ -222,4 +228,17 @@ public class FileURLConnection extends URLConnection {
}
return permission;
}
/**
* Throw {@link MalformedURLException} if the FTP fallback feature for non-local
* file URLs is not explicitly enabled via system property.
*
* @see #FTP_FALLBACK_ENABLED
* @throws MalformedURLException if FTP fallback is not enabled
*/
static void requireFtpFallbackEnabled() throws MalformedURLException {
if (!FTP_FALLBACK_ENABLED) {
throw new MalformedURLException("Unsupported non-local file URL");
}
}
}

View File

@ -72,6 +72,7 @@ public class Handler extends URLStreamHandler {
/* If you reach here, it implies that you have a hostname
so attempt an ftp connection.
*/
FileURLConnection.requireFtpFallbackEnabled();
URLConnection uc;
URL ru;

View File

@ -88,6 +88,7 @@ public class Handler extends URLStreamHandler {
/*
* Now attempt an ftp connection.
*/
FileURLConnection.requireFtpFallbackEnabled();
URLConnection uc;
URL newurl;

View File

@ -25,6 +25,8 @@
* @bug 4064962 8202708
* @summary openStream should work even when not using proxies and
* UnknownHostException is thrown as expected.
* @comment For testing of non-local file URLs with the legacy FTP
* fallback feature enabled, see NonLocalFtpFallback.
*/
import java.io.*;
@ -34,24 +36,15 @@ import java.net.*;
public class OpenStream {
private static final String badHttp = "http://foo.bar.baz/";
private static final String badUnc = "file://h7qbp368oix47/not-exist.txt";
public static void main(String[] args) throws IOException {
testHttp();
testUnc();
}
static void testHttp() throws IOException {
checkThrows(badHttp);
}
static void testUnc() throws IOException {
boolean isWindows = System.getProperty("os.name").startsWith("Windows");
if (isWindows) {
checkThrows(badUnc);
}
}
static void checkThrows(String url) throws IOException {
URL u = new URL(url);
try {
@ -62,7 +55,6 @@ public class OpenStream {
}
throw new RuntimeException("Expected UnknownHostException to be " +
"thrown for " + url);
}
}

View File

@ -40,14 +40,16 @@ import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.junit.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @test
* @bug 8353662
* @summary Verify long-standing behavior of resolving non-local file URLs using FTP.
* @run junit NonLocalFtpFallback
* @bug 8353662 8202708
* @summary Verify long-standing, disabled by default behavior of resolving non-local
* file URLs using FTP.
* @run junit/othervm -Djdk.net.file.ftpfallback=true NonLocalFtpFallback
*/
public class NonLocalFtpFallback {
@ -112,9 +114,8 @@ public class NonLocalFtpFallback {
* Verifies the long-standing and unspecified FTP fallback feature where the file
* URL scheme handler attempts an FTP connection for non-local files.
*
* The non-local file URL used here is of the form file://127.0.0.1/path. Since the
* host component here is not equal to "localhost", this is considered a non-local
* URL.
* The non-local file URL used here is of the form 'file://remotehost/path'. Since the
* host component is not equal to 'localhost', this is considered a non-local URL.
*
* @throws Exception
*/
@ -142,4 +143,45 @@ public class NonLocalFtpFallback {
URL ftpURL = new URL("ftp", hostname, localURL.getFile());
assertEquals(ftpURL.toURI(), uris.iterator().next());
}
/**
* Sanity check that a local file URL (with a host component equal to 'localhost')
* does not open any FtpURLConnection when the FTP fallback feature is enabled.
*
* @throws Exception
*/
@Test
public void verifyLocalFileURL() throws Exception {
URL localURL = file.toUri().toURL();
URL nonLocalURL = new URL("file", "localhost", localURL.getFile());
// Open the local file: URL connection supplying a proxy
Proxy proxy = new Proxy(Proxy.Type.HTTP,
new InetSocketAddress(proxyServer.getAddress().getAddress(),
proxyServer.getAddress().getPort()));
URLConnection con = nonLocalURL.openConnection(proxy);
// Assert that the expected file content is read
try (InputStream in = con.getInputStream()) {
byte[] retrived = in.readAllBytes();
assertArrayEquals(Files.readAllBytes(file), retrived);
}
// Assert that no FTP URIs were requested in the HTTP proxy
assertEquals(0, uris.size());
}
/**
* Verify that opening a stream on a non-proxy URLConnection for a non-local
* file URL with an unknown host fails with UnknownHostException
* when the fallback FtpURLConnection attempts to connect to the non-existing
* FTP server.
*/
@Test
public void verifyFtpUnknownHost() throws IOException {
URL url = new URL("file://nonexistinghost/not-exist.txt");
assertThrows(UnknownHostException.class, () -> {
InputStream in = url.openConnection(Proxy.NO_PROXY).getInputStream();
});
}
}

View File

@ -0,0 +1,73 @@
/*
* 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 org.junit.jupiter.api.Test;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import static org.junit.Assert.assertThrows;
/**
* @test
* @bug 8353440
* @summary Verify that non-local file URLs are rejected by default
* @run junit/othervm NonLocalFtpFallbackDisabled
* @run junit/othervm -Djdk.net.file.ftpfallback=false NonLocalFtpFallbackDisabled
* @run junit/othervm -Djdk.net.file.ftpfallback NonLocalFtpFallbackDisabled
*/
public class NonLocalFtpFallbackDisabled {
// The file requested in this test
private Path file = Path.of("ftp-file.txt");
/**
* Verifies that the long-standing and unspecified FTP fallback feature
* where the file URL scheme handler attempts an FTP connection for non-local
* files is disabled by default and that opening connections for such URLs
* is rejected with a MalformedURLException.
*
* @throws MalformedURLException if an unexpected URL exception occurs
* @throws URISyntaxException if an unexpected URI exception occurs
*/
@Test
public void verifyNonLocalFileURLRejected() throws MalformedURLException, URISyntaxException {
// We can use a fake host name here, no actual FTP request will be made
String hostname = "remotehost";
URL local = file.toUri().toURL();
URL nonLocal = new URI("file", hostname, local.getFile(), "").toURL();
assertThrows(MalformedURLException.class, () -> {
nonLocal.openConnection();
});
URL nonLocalEmptyPath = new URI("file", hostname, "", "").toURL();
assertThrows(MalformedURLException.class, () -> {
nonLocalEmptyPath.openConnection();
});
}
}