aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sdkmanager/app/tests/com/android/sdkmanager/MainTest.java73
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DownloadCache.java45
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/UrlOpener.java25
3 files changed, 136 insertions, 7 deletions
diff --git a/sdkmanager/app/tests/com/android/sdkmanager/MainTest.java b/sdkmanager/app/tests/com/android/sdkmanager/MainTest.java
index 96cb003..057ad3d 100644
--- a/sdkmanager/app/tests/com/android/sdkmanager/MainTest.java
+++ b/sdkmanager/app/tests/com/android/sdkmanager/MainTest.java
@@ -22,13 +22,25 @@ import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkManager;
import com.android.sdklib.SdkManagerTestCase;
import com.android.sdklib.internal.avd.AvdInfo;
+import com.android.sdklib.internal.repository.CanceledByUserException;
+import com.android.sdklib.internal.repository.DownloadCache;
+import com.android.sdklib.internal.repository.DownloadCache.Strategy;
+import com.android.sdklib.internal.repository.NullTaskMonitor;
import com.android.sdklib.repository.SdkAddonConstants;
import com.android.sdklib.repository.SdkRepoConstants;
import com.android.utils.Pair;
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Set;
@@ -286,4 +298,65 @@ public class MainTest extends SdkManagerTestCase {
}
}
}
+
+ public void testLocalFileDownload() throws IOException, CanceledByUserException {
+ Main main = new Main();
+ main.setLogger(getLog());
+ SdkManager sdkman = getSdkManager();
+ main.setSdkManager(sdkman);
+ getLog().clear();
+
+ IAndroidTarget target = sdkman.getTargets()[0];
+ File sourceProps = new File(target.getLocation(), SdkConstants.FN_SOURCE_PROP);
+ assertTrue(sourceProps.isFile());
+
+ String urlStr = getFileUrl(sourceProps);
+ assertTrue(urlStr.startsWith("file:///"));
+
+ DownloadCache cache = new DownloadCache(Strategy.DIRECT);
+ NullTaskMonitor monitor = new NullTaskMonitor(getLog());
+ Pair<InputStream, Integer> result = cache.openDirectUrl(urlStr, monitor);
+ assertNotNull(result);
+ assertEquals(200, result.getSecond().intValue());
+
+ int len = (int) sourceProps.length();
+ byte[] buf = new byte[len];
+ FileInputStream is = new FileInputStream(sourceProps);
+ is.read(buf);
+ is.close();
+ String expected = new String(buf, "UTF-8");
+
+ buf = new byte[len];
+ result.getFirst().read(buf);
+ result.getFirst().close();
+ String actual = new String(buf, "UTF-8");
+ assertEquals(expected, actual);
+ }
+
+ private String getFileUrl(File file) throws IOException {
+ // Note: to create a file:// URL, one would typically use something like
+ // f.toURI().toURL().toString(). However this generates a broken path on
+ // Windows, namely "C:\\foo" is converted to "file:/C:/foo" instead of
+ // "file:///C:/foo" (i.e. there should be 3 / after "file:"). So we'll
+ // do the correct thing manually.
+
+ String path = file.getCanonicalPath();
+ if (File.separatorChar != '/') {
+ path = path.replace(File.separatorChar, '/');
+ }
+ // A file:// should start with 3 // (2 for file:// and 1 to make it an absolute
+ // path. On Windows that should look like file:///C:/. Linux/Mac will already
+ // have that leading / in their path so we need to compensate for windows.
+ if (!path.startsWith("/")) {
+ path = "/" + path;
+ }
+
+ // For some reason the URL class doesn't add the mandatory "//" after
+ // the "file:" protocol name, so it has to be hacked into the path.
+ URL url = new URL("file", null, "//" + path); //$NON-NLS-1$ //$NON-NLS-2$
+ String result = url.toString();
+ return result;
+
+ }
+
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DownloadCache.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DownloadCache.java
index 0667b74..e02023d 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DownloadCache.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/DownloadCache.java
@@ -283,6 +283,8 @@ public class DownloadCache {
* For details on realm authentication and user/password handling,
* check the underlying {@link UrlOpener#openUrl(String, boolean, ITaskMonitor, Header[])}
* documentation.
+ * <p/>
+ * The resulting input stream may not support mark/reset.
*
* @param urlString the URL string to be opened.
* @param headers An optional set of headers to pass when requesting the resource. Can be null.
@@ -315,6 +317,49 @@ public class DownloadCache {
}
/**
+ * This is a simplified convenience method that calls
+ * {@link #openDirectUrl(String, Header[], ITaskMonitor)}
+ * without passing any specific HTTP headers and returns the resulting input stream
+ * and the HTTP status code.
+ * See the original method's description for details on its behavior.
+ * <p/>
+ * {@link #openDirectUrl(String, Header[], ITaskMonitor)} can accept customized
+ * HTTP headers to send with the requests and also returns the full HTTP
+ * response -- status line with code and protocol and all headers.
+ * <p/>
+ * The resulting input stream may not support mark/reset.
+ *
+ * @param urlString the URL string to be opened.
+ * @param monitor {@link ITaskMonitor} which is related to this URL
+ * fetching.
+ * @return Returns a pair with a {@link InputStream} and an HTTP status code.
+ * The pair is never null.
+ * The input stream can be null in case of error, although in general the
+ * method will probably throw an exception instead.
+ * The caller should look at the response code's status and only accept the
+ * input stream if it's the desired code (e.g. 200 or 206).
+ * @throws IOException Exception thrown when there are problems retrieving
+ * the URL or its content.
+ * @throws CanceledByUserException Exception thrown if the user cancels the
+ * authentication dialog.
+ * @see #openDirectUrl(String, Header[], ITaskMonitor)
+ */
+ public Pair<InputStream, Integer> openDirectUrl(
+ @NonNull String urlString,
+ @NonNull ITaskMonitor monitor)
+ throws IOException, CanceledByUserException {
+ if (DEBUG) {
+ System.out.println(String.format("%s : Direct download", urlString)); //$NON-NLS-1$
+ }
+ Pair<InputStream, HttpResponse> result = UrlOpener.openUrl(
+ urlString,
+ false /*needsMarkResetSupport*/,
+ monitor,
+ null /*headers*/);
+ return Pair.of(result.getFirst(), result.getSecond().getStatusLine().getStatusCode());
+ }
+
+ /**
* Downloads a small file, typically XML manifests.
* The current {@link Strategy} governs whether the file is served as-is
* from the cache, potentially updated first or directly downloaded.
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/UrlOpener.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/UrlOpener.java
index baccc27..52724c7 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/UrlOpener.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/UrlOpener.java
@@ -175,6 +175,7 @@ class UrlOpener {
@Nullable Header[] headers)
throws IOException, CanceledByUserException {
+ Exception fallbackOnJavaUrlConnect = null;
Pair<InputStream, HttpResponse> result = null;
try {
@@ -186,6 +187,11 @@ class UrlOpener {
// it could use a better message.
throw new IOException("Unknown Host " + e.getMessage(), e);
+ } catch (ClientProtocolException e) {
+ // We get this when HttpClient fails to accept the current protocol,
+ // e.g. when processing file:// URLs.
+ fallbackOnJavaUrlConnect = e;
+
} catch (IOException e) {
throw e;
@@ -194,19 +200,24 @@ class UrlOpener {
throw e;
} catch (Exception e) {
- // If the protocol is not supported by HttpClient (e.g. file:///),
- // revert to the standard java.net.Url.open.
if (DEBUG) {
System.out.printf("[HttpClient Error] %s : %s\n", url, e.toString());
}
+ fallbackOnJavaUrlConnect = e;
+ }
+
+ if (fallbackOnJavaUrlConnect != null) {
+ // If the protocol is not supported by HttpClient (e.g. file:///),
+ // revert to the standard java.net.Url.open.
+
try {
result = openWithUrl(url, headers);
- } catch (IOException e2) {
- throw e2;
- } catch (Exception e2) {
- if (DEBUG && !e.equals(e2)) {
- System.out.printf("[Url Error] %s : %s\n", url, e2.toString());
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ if (DEBUG && !fallbackOnJavaUrlConnect.equals(e)) {
+ System.out.printf("[Url Error] %s : %s\n", url, e.toString());
}
}
}