summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNarayan Kamath <narayan@google.com>2014-05-08 15:56:31 +0100
committerNarayan Kamath <narayan@google.com>2014-05-09 10:53:56 +0100
commitd94e746976d2906b89197448db15e4a0e355d98a (patch)
treef4daebb530f894c48c4e70ea3aaa8732a900d5de
parentf560c538e8cb2750502c7337cae86c536e44ca8d (diff)
downloadlibcore-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
-rw-r--r--expectations/knownfailures.txt9
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/internal/net/www/protocol/file/FileURLConnectionTest.java71
-rw-r--r--luni/src/main/java/libcore/net/url/FileURLConnection.java146
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;