diff options
author | Narayan Kamath <narayan@google.com> | 2014-05-08 15:56:31 +0100 |
---|---|---|
committer | Narayan Kamath <narayan@google.com> | 2014-05-09 10:53:56 +0100 |
commit | d94e746976d2906b89197448db15e4a0e355d98a (patch) | |
tree | f4daebb530f894c48c4e70ea3aaa8732a900d5de | |
parent | f560c538e8cb2750502c7337cae86c536e44ca8d (diff) | |
download | libcore-d94e746976d2906b89197448db15e4a0e355d98a.zip libcore-d94e746976d2906b89197448db15e4a0e355d98a.tar.gz libcore-d94e746976d2906b89197448db15e4a0e355d98a.tar.bz2 |
Fix various errors in FileURLConnectionTest.
- First, the test was broken pretty badly. It would pass a
Jar style URL to a FileURLConnection and expect it to
work, this is out of spec and seems wrong in general
(file:///foo.apk!resources/foo.txt).
- The RI supports various "headers" on file URL connections
(sigh). As if the getHeaderField(int) and getHeaderFieldKey(int)
APIs weren't bad enough. This has now been implemented with
a naive implementation.
- Fixes FileURLConnection to populate a header map for
information it provides (content length, content type
etc.)
bug: 11664881
Change-Id: I7a3e9aaa79bf125abbcfe8367574115ce54718e3
3 files changed, 186 insertions, 40 deletions
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt index b976c67..01f6d91 100644 --- a/expectations/knownfailures.txt +++ b/expectations/knownfailures.txt @@ -1623,15 +1623,6 @@ ] }, { - description: "Known failures in dealing with # in file / jar URLs", - bug: 11664881, - names: [ - "org.apache.harmony.tests.internal.net.www.protocol.file.FileURLConnectionTest#testGetContentType", - "org.apache.harmony.tests.internal.net.www.protocol.file.FileURLConnectionTest#testGetInputStream", - "org.apache.harmony.tests.internal.net.www.protocol.file.FileURLConnectionTest#testHeaderFunctions" - ] -}, -{ description: "Known failures in SerializationStressTest", bug: 11668227, names: [ diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/internal/net/www/protocol/file/FileURLConnectionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/internal/net/www/protocol/file/FileURLConnectionTest.java index 317ba5c..1f4ad1f 100644 --- a/harmony-tests/src/test/java/org/apache/harmony/tests/internal/net/www/protocol/file/FileURLConnectionTest.java +++ b/harmony-tests/src/test/java/org/apache/harmony/tests/internal/net/www/protocol/file/FileURLConnectionTest.java @@ -14,12 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package tests.api.internal.net.www.protocol.file; +package org.apache.harmony.tests.internal.net.www.protocol.file; -import junit.framework.TestCase; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; +import junit.framework.TestCase; +import libcore.io.Streams; import libcore.net.url.FileURLConnection; /** @@ -27,53 +33,81 @@ import libcore.net.url.FileURLConnection; */ public class FileURLConnectionTest extends TestCase { - static String getContentType(String fileName) throws IOException { + private static final String RESOURCE_NAME = "resources/test.rtf"; + + private final ClassLoader loader = FileURLConnectionTest.class.getClassLoader(); + + private URL createTempFileWithContent(String resourceName) throws IOException { + InputStream is = null; + OutputStream os = null; + try { + final URL url = loader.getResource(resourceName); + assertNotNull("Cannot find test resource " + resourceName, url); + is = url.openStream(); + File file = File.createTempFile("FileURLConnectionTest", + resourceName.substring(resourceName.indexOf("."))); + os = new BufferedOutputStream(new FileOutputStream(file)); + Streams.copy(is, os); + + return new URL("file://" + file.getAbsolutePath()); + } finally { + if (is != null) { + is.close(); + } + + if (os != null) { + os.close(); + } + } + } + + private String getContentType(String fileName) throws IOException { String resourceName = "resources/" + fileName; - URL url = ClassLoader.getSystemClassLoader().getResource(resourceName); - assertNotNull("Cannot find test resource " + resourceName, url); + URL url = createTempFileWithContent(resourceName); return new FileURLConnection(url).getContentType(); } public void testGetContentType() throws IOException { // Regression for HARMONY-4699 - assertEquals("application/rtf", getContentType("test.rtf")); - assertEquals("text/plain", getContentType("test.java")); + assertEquals("text/rtf", getContentType("test.rtf")); // RI would return "content/unknown" assertEquals("application/msword", getContentType("test.doc")); assertEquals("text/html", getContentType("test.htx")); - assertEquals("application/xml", getContentType("test.xml")); - assertEquals("text/plain", getContentType(".")); + assertEquals("text/xml", getContentType("test.xml")); + assertEquals("text/html", + new FileURLConnection(new URL("file:///")).getContentType()); } public void testGetInputStream() throws IOException { // Regression for Harmony-5737 - String resourceName = "resources/" + "test.rtf"; - URL url = ClassLoader.getSystemClassLoader().getResource(resourceName); + URL url = createTempFileWithContent(RESOURCE_NAME); assertNotNull(url); URL anchorUrl = new URL(url, "#anchor"); - assertNotNull("Cannot find test resource " + resourceName, anchorUrl); + assertNotNull("Cannot find test resource " + RESOURCE_NAME, anchorUrl); FileURLConnection conn = new FileURLConnection(anchorUrl); assertNotNull(conn.getInputStream()); + } + public void testGetInputStream_localHost() throws IOException { // Regression for Harmony-5779 + URL url = createTempFileWithContent(RESOURCE_NAME); String localURLString = "file://localhost/" + url.getFile(); URL localURL = new URL(localURLString); - conn = new FileURLConnection(localURL); + FileURLConnection conn = new FileURLConnection(localURL); assertNotNull(conn.getInputStream()); assertEquals("file", conn.getURL().getProtocol()); } public void testHeaderFunctions() throws IOException { - String resourceName = "resources/test.rtf"; //folder name - URL url = ClassLoader.getSystemClassLoader().getResource(resourceName); + URL url = createTempFileWithContent(RESOURCE_NAME); FileURLConnection conn = new FileURLConnection(url); assertNotNull(conn.getInputStream()); assertEquals(conn.getContentType(), conn.getHeaderField("content-type")); - resourceName = "resources/" + "test.rtf"; - url = ClassLoader.getSystemClassLoader().getResource(resourceName); + url = createTempFileWithContent(RESOURCE_NAME); conn = new FileURLConnection(url); + assertNotNull(conn.getInputStream()); assertEquals(conn.getContentType(), conn.getHeaderField("content-type")); assertEquals(Integer.toString(conn.getContentLength()), @@ -89,8 +123,7 @@ public class FileURLConnectionTest extends TestCase { } public void testHeader_BoundaryCheck() throws IOException { - String resourceName = "resources/test.rtf"; - URL url = ClassLoader.getSystemClassLoader().getResource(resourceName); + URL url = createTempFileWithContent(RESOURCE_NAME); URLConnection urlConnection = url.openConnection(); assertNull(urlConnection.getHeaderField(Integer.MIN_VALUE)); assertNull(urlConnection.getHeaderField(Integer.MAX_VALUE)); diff --git a/luni/src/main/java/libcore/net/url/FileURLConnection.java b/luni/src/main/java/libcore/net/url/FileURLConnection.java index f8d7926..94fe1d6 100644 --- a/luni/src/main/java/libcore/net/url/FileURLConnection.java +++ b/luni/src/main/java/libcore/net/url/FileURLConnection.java @@ -28,6 +28,11 @@ import java.io.InputStream; import java.io.PrintStream; import java.net.URL; import java.net.URLConnection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; import libcore.net.UriCodec; /** @@ -38,17 +43,45 @@ import libcore.net.UriCodec; */ public class FileURLConnection extends URLConnection { + private static final Comparator<String> HEADER_COMPARATOR = new Comparator<String>() { + @Override + public int compare(String a, String b) { + if (a == b) { + return 0; + } else if (a == null) { + return -1; + } else if (b == null) { + return 1; + } else { + return String.CASE_INSENSITIVE_ORDER.compare(a, b); + } + } + }; + private String filename; private InputStream is; private long length = -1; + private long lastModified = -1; + private boolean isDir; private FilePermission permission; /** + * A set of three key value pairs representing the headers we support. + */ + private final String[] headerKeysAndValues; + + private static final int CONTENT_TYPE_VALUE_IDX = 1; + private static final int CONTENT_LENGTH_VALUE_IDX = 3; + private static final int LAST_MODIFIED_VALUE_IDX = 5; + + private Map<String, List<String>> headerFields; + + /** * Creates an instance of <code>FileURLConnection</code> for establishing * a connection to the file pointed by this <code>URL<code> * @@ -61,6 +94,10 @@ public class FileURLConnection extends URLConnection { filename = ""; } filename = UriCodec.decode(filename); + headerKeysAndValues = new String[] { + "content-type", null, + "content-length", null, + "last-modified", null }; } /** @@ -74,15 +111,105 @@ public class FileURLConnection extends URLConnection { @Override public void connect() throws IOException { File f = new File(filename); + IOException error = null; if (f.isDirectory()) { isDir = true; is = getDirectoryListing(f); // use -1 for the contentLength + lastModified = f.lastModified(); + headerKeysAndValues[CONTENT_TYPE_VALUE_IDX] = "text/html"; } else { - is = new BufferedInputStream(new FileInputStream(f)); - length = f.length(); + try { + is = new BufferedInputStream(new FileInputStream(f)); + } catch (IOException ioe) { + error = ioe; + } + + if (error == null) { + length = f.length(); + lastModified = f.lastModified(); + headerKeysAndValues[CONTENT_TYPE_VALUE_IDX] = getContentTypeForPlainFiles(); + } else { + headerKeysAndValues[CONTENT_TYPE_VALUE_IDX] = "content/unknown"; + } } + + headerKeysAndValues[CONTENT_LENGTH_VALUE_IDX] = String.valueOf(length); + headerKeysAndValues[LAST_MODIFIED_VALUE_IDX] = String.valueOf(lastModified); + connected = true; + if (error != null) { + throw error; + } + } + + @Override + public String getHeaderField(String key) { + if (!connected) { + try { + connect(); + } catch (IOException ioe) { + return null; + } + } + + for (int i = 0; i < headerKeysAndValues.length; i += 2) { + if (headerKeysAndValues[i].equalsIgnoreCase(key)) { + return headerKeysAndValues[i + 1]; + } + } + + return null; + } + + @Override + public String getHeaderFieldKey(int position) { + if (!connected) { + try { + connect(); + } catch (IOException ioe) { + return null; + } + } + + if (position < 0 || position > headerKeysAndValues.length / 2) { + return null; + } + + return headerKeysAndValues[position * 2]; + } + + @Override + public String getHeaderField(int position) { + if (!connected) { + try { + connect(); + } catch (IOException ioe) { + return null; + } + } + + if (position < 0 || position > headerKeysAndValues.length / 2) { + return null; + } + + return headerKeysAndValues[(position * 2) + 1]; + } + + @Override + public Map<String, List<String>> getHeaderFields() { + if (headerFields == null) { + final TreeMap<String, List<String>> headerFieldsMap = new TreeMap<>(HEADER_COMPARATOR); + + for (int i = 0; i < headerKeysAndValues.length; i+=2) { + headerFieldsMap.put(headerKeysAndValues[i], + Collections.singletonList(headerKeysAndValues[i + 1])); + } + + headerFields = Collections.unmodifiableMap(headerFieldsMap); + } + + return headerFields; } /** @@ -123,16 +250,11 @@ public class FileURLConnection extends URLConnection { */ @Override public String getContentType() { - try { - if (!connected) { - connect(); - } - } catch (IOException e) { - return "content/unknown"; - } - if (isDir) { - return "text/plain"; - } + // The content-type header field is always at position 0. + return getHeaderField(0); + } + + private String getContentTypeForPlainFiles() { String result = guessContentTypeFromName(url.getFile()); if (result != null) { return result; |