Skip to content

Commit 2ea629f

Browse files
author
Eirik Bjørsnøs
committed
8353440: Disable FTP fallback for non-local file URLs by default
Reviewed-by: dfuchs
1 parent 57297e6 commit 2ea629f

File tree

7 files changed

+155
-16
lines changed

7 files changed

+155
-16
lines changed

src/java.base/share/classes/java/net/doc-files/net-properties.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,17 @@ <H2>Proxies</H2>
169169
globally through their user interface). Note that this property is
170170
checked only once at startup.</P>
171171
</UL>
172+
<a id="FileHandler"></a>
173+
<H2>File URL stream protocol handler properties</H2>
174+
<P>The following properties are used to configure the handler for URLs with the {@code file://} scheme:</P>
175+
<UL>
176+
<LI><P><B>{@systemProperty jdk.net.file.ftpfallback}</B> (default: &lt;false&gt;)<BR>
177+
The {@code file://} handler by default rejects any non-local file URL (as defined by RFC 8089)
178+
as invalid. Setting this property to <B>true</B> enables a legacy feature where
179+
the handler instead opens an FTP connection for such non-local URLs.</P>
180+
<P>Any modern code should use explicit {@code ftp://} URLs instead and not rely on
181+
enabling this legacy FTP fallback feature.</P>
182+
</UL>
172183
<a id="MiscHTTP"></a>
173184
<H2>Misc HTTP URL stream protocol handler properties</H2>
174185
<UL>

src/java.base/share/classes/sun/net/www/protocol/file/FileURLConnection.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
package sun.net.www.protocol.file;
2727

28+
import java.net.MalformedURLException;
2829
import java.net.URL;
2930
import java.net.FileNameMap;
3031
import java.io.*;
@@ -46,6 +47,11 @@ public class FileURLConnection extends URLConnection {
4647
private static final String TEXT_PLAIN = "text/plain";
4748
private static final String LAST_MODIFIED = "last-modified";
4849

50+
// The feature of falling back to FTP for non-local file URLs is disabled
51+
// by default and can be re-enabled by setting a system property
52+
private static final boolean FTP_FALLBACK_ENABLED =
53+
Boolean.getBoolean("jdk.net.file.ftpfallback");
54+
4955
private final File file;
5056
private InputStream is;
5157
private List<String> directoryListing;
@@ -222,4 +228,17 @@ public Permission getPermission() throws IOException {
222228
}
223229
return permission;
224230
}
231+
232+
/**
233+
* Throw {@link MalformedURLException} if the FTP fallback feature for non-local
234+
* file URLs is not explicitly enabled via system property.
235+
*
236+
* @see #FTP_FALLBACK_ENABLED
237+
* @throws MalformedURLException if FTP fallback is not enabled
238+
*/
239+
static void requireFtpFallbackEnabled() throws MalformedURLException {
240+
if (!FTP_FALLBACK_ENABLED) {
241+
throw new MalformedURLException("Unsupported non-local file URL");
242+
}
243+
}
225244
}

src/java.base/unix/classes/sun/net/www/protocol/file/Handler.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public URLConnection openConnection(URL u, Proxy p)
7272
/* If you reach here, it implies that you have a hostname
7373
so attempt an ftp connection.
7474
*/
75+
FileURLConnection.requireFtpFallbackEnabled();
7576
URLConnection uc;
7677
URL ru;
7778

src/java.base/windows/classes/sun/net/www/protocol/file/Handler.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public URLConnection openConnection(URL url, Proxy p)
8888
/*
8989
* Now attempt an ftp connection.
9090
*/
91+
FileURLConnection.requireFtpFallbackEnabled();
9192
URLConnection uc;
9293
URL newurl;
9394

test/jdk/java/net/URL/OpenStream.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
* @bug 4064962 8202708
2626
* @summary openStream should work even when not using proxies and
2727
* UnknownHostException is thrown as expected.
28+
* @comment For testing of non-local file URLs with the legacy FTP
29+
* fallback feature enabled, see NonLocalFtpFallback.
2830
*/
2931

3032
import java.io.*;
@@ -34,24 +36,15 @@
3436
public class OpenStream {
3537

3638
private static final String badHttp = "http://foo.bar.baz/";
37-
private static final String badUnc = "file://h7qbp368oix47/not-exist.txt";
3839

3940
public static void main(String[] args) throws IOException {
4041
testHttp();
41-
testUnc();
4242
}
4343

4444
static void testHttp() throws IOException {
4545
checkThrows(badHttp);
4646
}
4747

48-
static void testUnc() throws IOException {
49-
boolean isWindows = System.getProperty("os.name").startsWith("Windows");
50-
if (isWindows) {
51-
checkThrows(badUnc);
52-
}
53-
}
54-
5548
static void checkThrows(String url) throws IOException {
5649
URL u = new URL(url);
5750
try {
@@ -62,7 +55,6 @@ static void checkThrows(String url) throws IOException {
6255
}
6356
throw new RuntimeException("Expected UnknownHostException to be " +
6457
"thrown for " + url);
65-
6658
}
6759
}
6860

test/jdk/sun/net/www/protocol/file/NonLocalFtpFallback.java

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,16 @@
4040
import java.util.concurrent.ExecutorService;
4141
import java.util.concurrent.Executors;
4242

43+
import static org.junit.Assert.assertThrows;
4344
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4445
import static org.junit.jupiter.api.Assertions.assertEquals;
4546

4647
/**
4748
* @test
48-
* @bug 8353662
49-
* @summary Verify long-standing behavior of resolving non-local file URLs using FTP.
50-
* @run junit NonLocalFtpFallback
49+
* @bug 8353662 8202708
50+
* @summary Verify long-standing, disabled by default behavior of resolving non-local
51+
* file URLs using FTP.
52+
* @run junit/othervm -Djdk.net.file.ftpfallback=true NonLocalFtpFallback
5153
*/
5254

5355
public class NonLocalFtpFallback {
@@ -112,9 +114,8 @@ public void destroy() throws IOException {
112114
* Verifies the long-standing and unspecified FTP fallback feature where the file
113115
* URL scheme handler attempts an FTP connection for non-local files.
114116
*
115-
* The non-local file URL used here is of the form file://127.0.0.1/path. Since the
116-
* host component here is not equal to "localhost", this is considered a non-local
117-
* URL.
117+
* The non-local file URL used here is of the form 'file://remotehost/path'. Since the
118+
* host component is not equal to 'localhost', this is considered a non-local URL.
118119
*
119120
* @throws Exception
120121
*/
@@ -142,4 +143,45 @@ public void verifyNonLocalFtpFallback() throws Exception {
142143
URL ftpURL = new URL("ftp", hostname, localURL.getFile());
143144
assertEquals(ftpURL.toURI(), uris.iterator().next());
144145
}
146+
147+
/**
148+
* Sanity check that a local file URL (with a host component equal to 'localhost')
149+
* does not open any FtpURLConnection when the FTP fallback feature is enabled.
150+
*
151+
* @throws Exception
152+
*/
153+
@Test
154+
public void verifyLocalFileURL() throws Exception {
155+
URL localURL = file.toUri().toURL();
156+
URL nonLocalURL = new URL("file", "localhost", localURL.getFile());
157+
158+
// Open the local file: URL connection supplying a proxy
159+
Proxy proxy = new Proxy(Proxy.Type.HTTP,
160+
new InetSocketAddress(proxyServer.getAddress().getAddress(),
161+
proxyServer.getAddress().getPort()));
162+
URLConnection con = nonLocalURL.openConnection(proxy);
163+
164+
// Assert that the expected file content is read
165+
try (InputStream in = con.getInputStream()) {
166+
byte[] retrived = in.readAllBytes();
167+
assertArrayEquals(Files.readAllBytes(file), retrived);
168+
}
169+
170+
// Assert that no FTP URIs were requested in the HTTP proxy
171+
assertEquals(0, uris.size());
172+
}
173+
174+
/**
175+
* Verify that opening a stream on a non-proxy URLConnection for a non-local
176+
* file URL with an unknown host fails with UnknownHostException
177+
* when the fallback FtpURLConnection attempts to connect to the non-existing
178+
* FTP server.
179+
*/
180+
@Test
181+
public void verifyFtpUnknownHost() throws IOException {
182+
URL url = new URL("file://nonexistinghost/not-exist.txt");
183+
assertThrows(UnknownHostException.class, () -> {
184+
InputStream in = url.openConnection(Proxy.NO_PROXY).getInputStream();
185+
});
186+
}
145187
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
import org.junit.jupiter.api.Test;
25+
26+
import java.net.MalformedURLException;
27+
import java.net.URI;
28+
import java.net.URISyntaxException;
29+
import java.net.URL;
30+
import java.nio.file.Path;
31+
32+
import static org.junit.Assert.assertThrows;
33+
34+
/**
35+
* @test
36+
* @bug 8353440
37+
* @summary Verify that non-local file URLs are rejected by default
38+
* @run junit/othervm NonLocalFtpFallbackDisabled
39+
* @run junit/othervm -Djdk.net.file.ftpfallback=false NonLocalFtpFallbackDisabled
40+
* @run junit/othervm -Djdk.net.file.ftpfallback NonLocalFtpFallbackDisabled
41+
*/
42+
public class NonLocalFtpFallbackDisabled {
43+
44+
// The file requested in this test
45+
private Path file = Path.of("ftp-file.txt");
46+
47+
/**
48+
* Verifies that the long-standing and unspecified FTP fallback feature
49+
* where the file URL scheme handler attempts an FTP connection for non-local
50+
* files is disabled by default and that opening connections for such URLs
51+
* is rejected with a MalformedURLException.
52+
*
53+
* @throws MalformedURLException if an unexpected URL exception occurs
54+
* @throws URISyntaxException if an unexpected URI exception occurs
55+
*/
56+
@Test
57+
public void verifyNonLocalFileURLRejected() throws MalformedURLException, URISyntaxException {
58+
// We can use a fake host name here, no actual FTP request will be made
59+
String hostname = "remotehost";
60+
61+
URL local = file.toUri().toURL();
62+
63+
URL nonLocal = new URI("file", hostname, local.getFile(), "").toURL();
64+
assertThrows(MalformedURLException.class, () -> {
65+
nonLocal.openConnection();
66+
});
67+
68+
URL nonLocalEmptyPath = new URI("file", hostname, "", "").toURL();
69+
assertThrows(MalformedURLException.class, () -> {
70+
nonLocalEmptyPath.openConnection();
71+
});
72+
}
73+
}

0 commit comments

Comments
 (0)