Skip to content

Commit a80f70e

Browse files
committed
Improve support for Windows UNC paths in getJarFileNameFromURL.
This adds to the fix for issue #2410. Tests now include drive-letter and UNC paths when the OS platform is Windows. We work around some strange behaviour wrt UNC paths that may be a Java conformance issue.
1 parent 3562c57 commit a80f70e

3 files changed

Lines changed: 80 additions & 9 deletions

File tree

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ For more details, please see https://hg.python.org/jython
44

55
Development tip
66
Bugs fixed
7+
- [ 2410 ] Regression in PySystemStateTest (leading slash)
78
- [ 2639 ] Incorrect result when using != comparison against Java {List, Set, Map}
89
- [ 2672 ] Integer formatting emits two minus signs with -2^31
910
- [ 2688 ] ClassCastException when adding list of non-PyObjects

src/org/python/core/Py.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
import java.lang.reflect.InvocationTargetException;
1818
import java.lang.reflect.Method;
1919
import java.net.JarURLConnection;
20+
import java.net.MalformedURLException;
2021
import java.net.URI;
2122
import java.net.URISyntaxException;
2223
import java.net.URL;
2324
import java.net.URLConnection;
24-
import java.net.URLDecoder;
2525
import java.sql.Date;
2626
import java.sql.Time;
2727
import java.sql.Timestamp;
@@ -2609,6 +2609,11 @@ public static String getJarFileNameFromURL(URL url) {
26092609

26102610
case "jar":
26112611
// url is jar:file:/some/path/some.jar!/package/with/A.class
2612+
if (Platform.IS_WINDOWS) {
2613+
// ... or jar:file://host/some/path/some.jar!/package/with/A.class
2614+
// ... or jar:file:////host/some/path/some.jar!/package/with/A.class
2615+
url = tweakWindowsFileURL(url);
2616+
}
26122617
URLConnection c = url.openConnection();
26132618
fileURI = ((JarURLConnection) c).getJarFileURL().toURI();
26142619
break;
@@ -2629,14 +2634,42 @@ public static String getJarFileNameFromURL(URL url) {
26292634
// Unknown protocol or url==null: fileURI = null
26302635
break;
26312636
}
2632-
} catch (IOException | URISyntaxException e) {
2637+
} catch (IOException | URISyntaxException | IllegalArgumentException e) {
26332638
// Handler cannot open connection or URL is malformed some way: fileURI = null
26342639
}
26352640

26362641
// The JAR file is now identified in fileURI but needs decoding to a file
26372642
return fileURI == null ? null : new File(fileURI).toString();
26382643
}
26392644

2645+
/**
2646+
* If the argument is a {@code jar:file:} or {@code file:} URL, compensate for a bug in Java's
2647+
* construction of URLs affecting {@code java.io.File} and {@code java.net.URLConnection} on
2648+
* Windows. This is a helper for {@link #getJarFileNameFromURL(URL)}.
2649+
* <p>
2650+
* This bug bites when a JAR file is at a (Windows) UNC location, and a {@code jar:file:} URL is
2651+
* derived from {@code Class.getResource()} as it is in {@link #_getJarFileName()}. When URL is
2652+
* supplied to {@link #getJarFileNameFromURL(URL)}, the bug leads to a URI that falsely treats a
2653+
* server as an "authority". It subsequently causes an {@code IllegalArgumentException} with the
2654+
* message "URI has an authority component" when we try to construct a File. See
2655+
* {@link https://bugs.java.com/view_bug.do?bug_id=6360233} ("won't fix").
2656+
*
2657+
* @param url Possibly malformed URL
2658+
* @return corrected URL
2659+
*/
2660+
private static URL tweakWindowsFileURL(URL url) throws MalformedURLException {
2661+
String urlstr = url.toString();
2662+
int fileIndex = urlstr.indexOf("file://"); // 7 chars
2663+
if (fileIndex >= 0) {
2664+
// Intended UNC path. If there is no slash following these two, insert "/" here:
2665+
int insert = fileIndex + 7;
2666+
if (urlstr.length() > insert && urlstr.charAt(insert) != '/') {
2667+
url = new URL(urlstr.substring(0, insert) + "//" + urlstr.substring(insert));
2668+
}
2669+
}
2670+
return url;
2671+
}
2672+
26402673
//------------------------contructor-section---------------------------
26412674
static class py2JyClassCacheItem {
26422675
List<Class<?>> interfaces;

tests/java/org/python/core/PySystemStateTest.java

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import java.net.URL;
66
import java.net.URLConnection;
77
import java.net.URLStreamHandler;
8+
import java.util.ArrayList;
9+
import java.util.Arrays;
10+
import java.util.List;
811

912
import org.python.util.PythonInterpreter;
1013

@@ -23,22 +26,25 @@ private static class JarExample {
2326
final String urlClassPath;
2427
final String filePath;
2528

29+
/** This constructor adapts unixPath to Windows when on Windows. */
2630
JarExample(String urlJarPath, String urlClassPath, String unixPath) {
31+
this(urlJarPath, urlClassPath,
32+
Platform.IS_WINDOWS ? new File(unixPath).toString() : unixPath, true);
33+
}
34+
35+
/** This constructor accepts filePath exactly as given. */
36+
JarExample(String urlJarPath, String urlClassPath, String filePath, boolean ignored) {
2737
this.urlJarPath = urlJarPath;
2838
this.urlClassPath = urlClassPath;
29-
if (Platform.IS_WINDOWS) {
30-
this.filePath = new File(unixPath).toString();
31-
} else {
32-
this.filePath = unixPath;
33-
}
39+
this.filePath = filePath;
3440
}
3541
}
3642

3743
/**
3844
* Examples of URLs (just the path and class noise) and the reference answer. Provide the
3945
* reference answer like a Un*x path (forward slash).
4046
*/
41-
private static JarExample[] jarExamples = { //
47+
private static List<JarExample> jarExamples = Arrays.asList(//
4248
// simple jar-file url
4349
new JarExample("/some_dir/some.jar", "a/package/with/A.class", "/some_dir/some.jar"),
4450
// jar-file url to decode
@@ -48,7 +54,38 @@ private static class JarExample {
4854
// Some characters should be encoded in the URL, but emerge as themselves in the path.
4955
new JarExample("/n%c3%a5gon/katalog/r%c3%a4tt.jar", "en/f%c3%b6rpackning/med/En.class",
5056
"/någon/katalog/rätt.jar") //
51-
};
57+
);
58+
59+
/* Check drive-letter and UNC path handling if on Windows. */
60+
static {
61+
if (Platform.IS_WINDOWS) {
62+
// Add some examples to the list (must be made mutable for that).
63+
jarExamples = new ArrayList<JarExample>(jarExamples);
64+
65+
// Drive-letter examples
66+
jarExamples.add(new JarExample("/C:/some_dir/some.jar", "a/package/with/A.class",
67+
"C:\\some_dir\\some.jar", true));
68+
jarExamples.add(new JarExample("/E:/n%c3%a5gon/katalog/r%c3%a4tt.jar", "med/En.class",
69+
"E:\\någon\\katalog\\rätt.jar", true));
70+
71+
// Simple network file path (UNC path without controversial characters)
72+
String p = "/org/python/version.properies";
73+
String r = "\\\\localhost\\shared\\jython-dev.jar";
74+
// JAR UNC file resource URL as produced by File.getURL or getURI
75+
jarExamples.add(new JarExample("////localhost/shared/jython-dev.jar", p, r, true));
76+
// JAR UNC file resource URL as produced by URLClassLoader.getResource
77+
jarExamples.add(new JarExample("//localhost/shared/jython-dev.jar", p, r, true));
78+
79+
// Network file path (UNC path with a controversial characters)
80+
r = "\\\\localhost\\shared\\jy thon%dev.jar";
81+
// JAR UNC file resource URL based on (deprecated) File.getURL is invalid
82+
// jarExamples.add(new JarExample("//localhost/shared/jy thon%dev.jar", p, r, true));
83+
// JAR UNC file resource URL based on File.getURI
84+
jarExamples.add(new JarExample("////localhost/shared/jy%20thon%25dev.jar", p, r, true));
85+
// JAR UNC file resource URL as produced by URLClassLoader.getResource
86+
jarExamples.add(new JarExample("//localhost/shared/jy%20thon%25dev.jar", p, r, true));
87+
}
88+
}
5289

5390
/**
5491
* Test case for finding the path in the local file system of the file located by a JAR-file

0 commit comments

Comments
 (0)