You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by oh...@apache.org on 2013/01/23 21:48:58 UTC

svn commit: r1437723 - in /commons/proper/configuration/trunk: conf/ src/changes/ src/main/java/org/apache/commons/configuration/ src/test/java/org/apache/commons/configuration/

Author: oheger
Date: Wed Jan 23 20:48:57 2013
New Revision: 1437723

URL: http://svn.apache.org/viewvc?rev=1437723&view=rev
Log:
[CONFIGURATION-521] Copied a stripped-down version of FileUtils from Commons IO in order to deal with URL to File conversions correctly. Thanks to Oliver Kopp for the patch."

Added:
    commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/FileUtils.java   (with props)
Modified:
    commons/proper/configuration/trunk/conf/checkstyle-suppressions.xml
    commons/proper/configuration/trunk/src/changes/changes.xml
    commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/ConfigurationUtils.java
    commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestConfigurationUtils.java

Modified: commons/proper/configuration/trunk/conf/checkstyle-suppressions.xml
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/conf/checkstyle-suppressions.xml?rev=1437723&r1=1437722&r2=1437723&view=diff
==============================================================================
--- commons/proper/configuration/trunk/conf/checkstyle-suppressions.xml (original)
+++ commons/proper/configuration/trunk/conf/checkstyle-suppressions.xml Wed Jan 23 20:48:57 2013
@@ -30,4 +30,6 @@
 
     <suppress checks="DoubleCheckedLocking" files="DynamicCombinedConfiguration.java"
       lines="800-900"/>
+
+    <suppress files="FileUtils\.java" checks="[a-zA-Z0-9]*"/>
 </suppressions>

Modified: commons/proper/configuration/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/changes/changes.xml?rev=1437723&r1=1437722&r2=1437723&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/changes/changes.xml (original)
+++ commons/proper/configuration/trunk/src/changes/changes.xml Wed Jan 23 20:48:57 2013
@@ -27,6 +27,10 @@
   <body>
     <release version="2.0" date="in SVN"
       description="TBD">
+      <action dev="oheger" type="update" issue="CONFIGURATION-521" due-to="Oliver Kopp">
+        ConfigurationUtils.fileFromUrl() now correctly handles URL containing
+        encoded percent characters.
+      </action>
       <action dev="oheger" type="add" issue="CONFIGURATION-517">
         Hierarchical configurations now provide methods to obtain sub
         configurations for all child elements of a given key.

Modified: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/ConfigurationUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/ConfigurationUtils.java?rev=1437723&r1=1437722&r2=1437723&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/ConfigurationUtils.java (original)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/ConfigurationUtils.java Wed Jan 23 20:48:57 2013
@@ -60,9 +60,6 @@ public final class ConfigurationUtils
     /** Constant for the name of the clone() method.*/
     private static final String METHOD_CLONE = "clone";
 
-    /** Constant for parsing numbers in hex format. */
-    private static final int HEX = 16;
-
     /**
      * An array with interfaces to be implemented by a proxy for an immutable
      * configuration.
@@ -722,34 +719,14 @@ public final class ConfigurationUtils
 
     /**
      * Tries to convert the specified URL to a file object. If this fails,
-     * <b>null</b> is returned. Note: This code has been copied from the
-     * {@code FileUtils} class from <em>Commons IO</em>.
+     * <b>null</b> is returned.
      *
      * @param url the URL
      * @return the resulting file object
      */
     public static File fileFromURL(URL url)
     {
-        if (url == null || !url.getProtocol().equals(PROTOCOL_FILE))
-        {
-            return null;
-        }
-        else
-        {
-            String filename = url.getFile().replace('/', File.separatorChar);
-            int pos = 0;
-            while ((pos = filename.indexOf('%', pos)) >= 0)
-            {
-                if (pos + 2 < filename.length())
-                {
-                    String hexStr = filename.substring(pos + 1, pos + 3);
-                    char ch = (char) Integer.parseInt(hexStr, HEX);
-                    filename = filename.substring(0, pos) + ch
-                            + filename.substring(pos + 3);
-                }
-            }
-            return new File(filename);
-        }
+        return FileUtils.toFile(url);
     }
 
     /**

Added: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/FileUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/FileUtils.java?rev=1437723&view=auto
==============================================================================
--- commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/FileUtils.java (added)
+++ commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/FileUtils.java Wed Jan 23 20:48:57 2013
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.configuration;
+
+import java.io.File;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * This class is a subset of org.apache.commons.io.FileUtils,
+ * git-svn-id: https://svn.apache.org/repos/asf/commons/proper/io/trunk@1423916 13f79535-47bb-0310-9956-ffa450edef68.
+ * The subset is determined by {@link org.apache.commons.configuration.ConfigurationUtils}.
+ * The copied constants and methods are <em>literally</em> copied.<br />
+ *
+ * See CONFIGURATION-521 for a discussion.
+ * @version $Id$
+ */
+class FileUtils {
+    /**
+     * The UTF-8 character set, used to decode octets in URLs.
+     */
+    private static final Charset UTF8 = Charset.forName("UTF-8");
+
+    //-----------------------------------------------------------------------
+    /**
+     * Convert from a <code>URL</code> to a <code>File</code>.
+     * <p>
+     * From version 1.1 this method will decode the URL.
+     * Syntax such as <code>file:///my%20docs/file.txt</code> will be
+     * correctly decoded to <code>/my docs/file.txt</code>. Starting with version
+     * 1.5, this method uses UTF-8 to decode percent-encoded octets to characters.
+     * Additionally, malformed percent-encoded octets are handled leniently by
+     * passing them through literally.
+     *
+     * @param url  the file URL to convert, {@code null} returns {@code null}
+     * @return the equivalent <code>File</code> object, or {@code null}
+     *  if the URL's protocol is not <code>file</code>
+     */
+    public static File toFile(final URL url) {
+        if (url == null || !"file".equalsIgnoreCase(url.getProtocol())) {
+            return null;
+        } else {
+            String filename = url.getFile().replace('/', File.separatorChar);
+            filename = decodeUrl(filename);
+            return new File(filename);
+        }
+    }
+
+    /**
+     * Decodes the specified URL as per RFC 3986, i.e. transforms
+     * percent-encoded octets to characters by decoding with the UTF-8 character
+     * set. This function is primarily intended for usage with
+     * {@link java.net.URL} which unfortunately does not enforce proper URLs. As
+     * such, this method will leniently accept invalid characters or malformed
+     * percent-encoded octets and simply pass them literally through to the
+     * result string. Except for rare edge cases, this will make unencoded URLs
+     * pass through unaltered.
+     *
+     * @param url  The URL to decode, may be {@code null}.
+     * @return The decoded URL or {@code null} if the input was
+     *         {@code null}.
+     */
+    static String decodeUrl(final String url) {
+        String decoded = url;
+        if (url != null && url.indexOf('%') >= 0) {
+            final int n = url.length();
+            final StringBuffer buffer = new StringBuffer();
+            final ByteBuffer bytes = ByteBuffer.allocate(n);
+            for (int i = 0; i < n;) {
+                if (url.charAt(i) == '%') {
+                    try {
+                        do {
+                            final byte octet = (byte) Integer.parseInt(url.substring(i + 1, i + 3), 16);
+                            bytes.put(octet);
+                            i += 3;
+                        } while (i < n && url.charAt(i) == '%');
+                        continue;
+                    } catch (final RuntimeException e) {
+                        // malformed percent-encoded octet, fall through and
+                        // append characters literally
+                    } finally {
+                        if (bytes.position() > 0) {
+                            bytes.flip();
+                            buffer.append(UTF8.decode(bytes).toString());
+                            bytes.clear();
+                        }
+                    }
+                }
+                buffer.append(url.charAt(i++));
+            }
+            decoded = buffer.toString();
+        }
+        return decoded;
+    }
+
+}

Propchange: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/FileUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/FileUtils.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: commons/proper/configuration/trunk/src/main/java/org/apache/commons/configuration/FileUtils.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestConfigurationUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestConfigurationUtils.java?rev=1437723&r1=1437722&r2=1437723&view=diff
==============================================================================
--- commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestConfigurationUtils.java (original)
+++ commons/proper/configuration/trunk/src/test/java/org/apache/commons/configuration/TestConfigurationUtils.java Wed Jan 23 20:48:57 2013
@@ -232,6 +232,19 @@ public class TestConfigurationUtils
     }
 
     /**
+     * Tests whether an encoded "%" character in the file name is handled correctly by
+     * fileFromURL(). This test is related to CONFIGURATION-521.
+     */
+    @Test
+    public void testFileFromURLWithEncodedPercent() throws MalformedURLException
+    {
+        File file = new File("https%3A%2F%2Fwww.apache.org%2F.url").getAbsoluteFile();
+        URL fileURL = file.toURI().toURL();
+        File file2 = ConfigurationUtils.fileFromURL(fileURL);
+        assertEquals("Wrong file", file, file2);
+    }
+
+    /**
      * Tests whether a "+" character in the file name is handled correctly by
      * fileFromURL(). This test is related to CONFIGURATION-415.
      */