[Jython-checkins] jython: Improve support for Windows UNC paths in getJarFileNameFromURL.

jeff.allen jython-checkins at python.org
Wed Jul 18 04:28:26 EDT 2018


https://hg.python.org/jython/rev/c0b0894950ff
changeset:   8175:c0b0894950ff
user:        Jeff Allen <ja.py at farowl.co.uk>
date:        Wed Jul 18 08:07:34 2018 +0100
summary:
  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.

files:
  NEWS                                              |   1 +
  src/org/python/core/Py.java                       |  37 ++++++-
  tests/java/org/python/core/PySystemStateTest.java |  51 ++++++++-
  3 files changed, 80 insertions(+), 9 deletions(-)


diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@
 
 Development tip
   Bugs fixed
+    - [ 2410 ] Regression in PySystemStateTest (leading slash)
     - [ 2639 ] Incorrect result when using != comparison against Java {List, Set, Map}
     - [ 2672 ] Integer formatting emits two minus signs with -2^31
     - [ 2688 ] ClassCastException when adding list of non-PyObjects
diff --git a/src/org/python/core/Py.java b/src/org/python/core/Py.java
--- a/src/org/python/core/Py.java
+++ b/src/org/python/core/Py.java
@@ -17,11 +17,11 @@
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.JarURLConnection;
+import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLConnection;
-import java.net.URLDecoder;
 import java.sql.Date;
 import java.sql.Time;
 import java.sql.Timestamp;
@@ -2609,6 +2609,11 @@
 
                 case "jar":
                     // url is jar:file:/some/path/some.jar!/package/with/A.class
+                    if (Platform.IS_WINDOWS) {
+                        // ... or jar:file://host/some/path/some.jar!/package/with/A.class
+                        // ... or jar:file:////host/some/path/some.jar!/package/with/A.class
+                        url = tweakWindowsFileURL(url);
+                    }
                     URLConnection c = url.openConnection();
                     fileURI = ((JarURLConnection) c).getJarFileURL().toURI();
                     break;
@@ -2629,7 +2634,7 @@
                     // Unknown protocol or url==null: fileURI = null
                     break;
             }
-        } catch (IOException | URISyntaxException e) {
+        } catch (IOException | URISyntaxException | IllegalArgumentException e) {
             // Handler cannot open connection or URL is malformed some way: fileURI = null
         }
 
@@ -2637,6 +2642,34 @@
         return fileURI == null ? null : new File(fileURI).toString();
     }
 
+    /**
+     * If the argument is a {@code jar:file:} or {@code file:} URL, compensate for a bug in Java's
+     * construction of URLs affecting {@code java.io.File} and {@code java.net.URLConnection} on
+     * Windows. This is a helper for {@link #getJarFileNameFromURL(URL)}.
+     * <p>
+     * This bug bites when a JAR file is at a (Windows) UNC location, and a {@code jar:file:} URL is
+     * derived from {@code Class.getResource()} as it is in {@link #_getJarFileName()}. When URL is
+     * supplied to {@link #getJarFileNameFromURL(URL)}, the bug leads to a URI that falsely treats a
+     * server as an "authority". It subsequently causes an {@code IllegalArgumentException} with the
+     * message "URI has an authority component" when we try to construct a File. See
+     * {@link https://bugs.java.com/view_bug.do?bug_id=6360233} ("won't fix").
+     *
+     * @param url Possibly malformed URL
+     * @return corrected URL
+     */
+    private static URL tweakWindowsFileURL(URL url) throws MalformedURLException {
+        String urlstr = url.toString();
+        int fileIndex = urlstr.indexOf("file://"); // 7 chars
+        if (fileIndex >= 0) {
+            // Intended UNC path. If there is no slash following these two, insert "/" here:
+            int insert = fileIndex + 7;
+            if (urlstr.length() > insert && urlstr.charAt(insert) != '/') {
+                url = new URL(urlstr.substring(0, insert) + "//" + urlstr.substring(insert));
+            }
+        }
+        return url;
+    }
+
 //------------------------contructor-section---------------------------
     static class py2JyClassCacheItem {
         List<Class<?>> interfaces;
diff --git a/tests/java/org/python/core/PySystemStateTest.java b/tests/java/org/python/core/PySystemStateTest.java
--- a/tests/java/org/python/core/PySystemStateTest.java
+++ b/tests/java/org/python/core/PySystemStateTest.java
@@ -5,6 +5,9 @@
 import java.net.URL;
 import java.net.URLConnection;
 import java.net.URLStreamHandler;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 import org.python.util.PythonInterpreter;
 
@@ -23,14 +26,17 @@
         final String urlClassPath;
         final String filePath;
 
+        /** This constructor adapts unixPath to Windows when on Windows. */
         JarExample(String urlJarPath, String urlClassPath, String unixPath) {
+            this(urlJarPath, urlClassPath,
+                    Platform.IS_WINDOWS ? new File(unixPath).toString() : unixPath, true);
+        }
+
+        /** This constructor accepts filePath exactly as given. */
+        JarExample(String urlJarPath, String urlClassPath, String filePath, boolean ignored) {
             this.urlJarPath = urlJarPath;
             this.urlClassPath = urlClassPath;
-            if (Platform.IS_WINDOWS) {
-                this.filePath = new File(unixPath).toString();
-            } else {
-                this.filePath = unixPath;
-            }
+            this.filePath = filePath;
         }
     }
 
@@ -38,7 +44,7 @@
      * Examples of URLs (just the path and class noise) and the reference answer. Provide the
      * reference answer like a Un*x path (forward slash).
      */
-    private static JarExample[] jarExamples = { //
+    private static List<JarExample> jarExamples = Arrays.asList(//
             // simple jar-file url
             new JarExample("/some_dir/some.jar", "a/package/with/A.class", "/some_dir/some.jar"),
             // jar-file url to decode
@@ -48,7 +54,38 @@
             // Some characters should be encoded in the URL, but emerge as themselves in the path.
             new JarExample("/n%c3%a5gon/katalog/r%c3%a4tt.jar", "en/f%c3%b6rpackning/med/En.class",
                     "/någon/katalog/rätt.jar") //
-    };
+    );
+
+    /* Check drive-letter  and UNC path handling if on Windows. */
+    static {
+        if (Platform.IS_WINDOWS) {
+            // Add some examples to the list (must be made mutable for that).
+            jarExamples = new ArrayList<JarExample>(jarExamples);
+
+            // Drive-letter examples
+            jarExamples.add(new JarExample("/C:/some_dir/some.jar", "a/package/with/A.class",
+                    "C:\\some_dir\\some.jar", true));
+            jarExamples.add(new JarExample("/E:/n%c3%a5gon/katalog/r%c3%a4tt.jar", "med/En.class",
+                    "E:\\någon\\katalog\\rätt.jar", true));
+
+            // Simple network file path (UNC path without controversial characters)
+            String p = "/org/python/version.properies";
+            String r = "\\\\localhost\\shared\\jython-dev.jar";
+            // JAR UNC file resource URL as produced by File.getURL or getURI
+            jarExamples.add(new JarExample("////localhost/shared/jython-dev.jar", p, r, true));
+            // JAR UNC file resource URL as produced by URLClassLoader.getResource
+            jarExamples.add(new JarExample("//localhost/shared/jython-dev.jar", p, r, true));
+
+            // Network file path (UNC path with a controversial characters)
+            r = "\\\\localhost\\shared\\jy thon%dev.jar";
+            // JAR UNC file resource URL based on (deprecated) File.getURL is invalid
+            // jarExamples.add(new JarExample("//localhost/shared/jy thon%dev.jar", p, r, true));
+            // JAR UNC file resource URL based on File.getURI
+            jarExamples.add(new JarExample("////localhost/shared/jy%20thon%25dev.jar", p, r, true));
+            // JAR UNC file resource URL as produced by URLClassLoader.getResource
+            jarExamples.add(new JarExample("//localhost/shared/jy%20thon%25dev.jar", p, r, true));
+        }
+    }
 
     /**
      * Test case for finding the path in the local file system of the file located by a JAR-file

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list