1d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber/* 2d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * Copyright (C) 2013 The Android Open Source Project 3d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * 4d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 5d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * you may not use this file except in compliance with the License. 6d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * You may obtain a copy of the License at 7d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * 8d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 9d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * 10d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * Unless required by applicable law or agreed to in writing, software 11d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 12d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * See the License for the specific language governing permissions and 14d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber * limitations under the License. 15d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber */ 16d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 17d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberpackage android.media; 18d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 19a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhangimport android.net.NetworkUtils; 20d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport android.os.IBinder; 21d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport android.os.StrictMode; 22d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport android.util.Log; 23d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 24d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.io.BufferedInputStream; 25d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.io.InputStream; 26d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.io.IOException; 27d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.net.CookieHandler; 28d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.net.CookieManager; 29a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhangimport java.net.Proxy; 30d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.net.URL; 31d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.net.HttpURLConnection; 32d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.net.MalformedURLException; 33c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnarimport java.net.NoRouteToHostException; 348976a0954cce9cfc8bd8776893fc9067e240a91cChong Zhangimport java.net.ProtocolException; 356db04b369ec4a4d59315ba0207ecc53d8e8852ccAlex Klyubinimport java.net.UnknownServiceException; 36d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.util.HashMap; 37d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.util.Map; 38d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 39c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnarimport static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED; 40c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 41d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber/** @hide */ 42d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberpublic class MediaHTTPConnection extends IMediaHTTPConnection.Stub { 43d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private static final String TAG = "MediaHTTPConnection"; 44d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private static final boolean VERBOSE = false; 45d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 4690b59750436bc23ff040d9287651e51bfd7fb470Chong Zhang // connection timeout - 30 sec 4790b59750436bc23ff040d9287651e51bfd7fb470Chong Zhang private static final int CONNECT_TIMEOUT_MS = 30 * 1000; 4890b59750436bc23ff040d9287651e51bfd7fb470Chong Zhang 49d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private long mCurrentOffset = -1; 50d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private URL mURL = null; 51d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private Map<String, String> mHeaders = null; 52d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private HttpURLConnection mConnection = null; 53d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private long mTotalSize = -1; 54d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private InputStream mInputStream = null; 55d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 56c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar private boolean mAllowCrossDomainRedirect = true; 575b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu private boolean mAllowCrossProtocolRedirect = true; 58c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 59c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // from com.squareup.okhttp.internal.http 60c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar private final static int HTTP_TEMP_REDIRECT = 307; 61c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar private final static int MAX_REDIRECTS = 20; 62c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 63d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public MediaHTTPConnection() { 64d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (CookieHandler.getDefault() == null) { 65d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber CookieHandler.setDefault(new CookieManager()); 66d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 67d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 68d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber native_setup(); 69d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 70d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 716e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 72d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public IBinder connect(String uri, String headers) { 73d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (VERBOSE) { 74d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers); 75d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 76d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 77d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 78d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber disconnect(); 79c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mAllowCrossDomainRedirect = true; 80d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mURL = new URL(uri); 81d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mHeaders = convertHeaderStringToMap(headers); 82d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (MalformedURLException e) { 83d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return null; 84d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 85d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 86d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return native_getIMemory(); 87d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 88d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 89c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar private boolean parseBoolean(String val) { 90c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar try { 91c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar return Long.parseLong(val) != 0; 92c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } catch (NumberFormatException e) { 93c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar return "true".equalsIgnoreCase(val) || 94c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar "yes".equalsIgnoreCase(val); 95c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 96c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 97c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 98c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar /* returns true iff header is internal */ 99c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar private boolean filterOutInternalHeaders(String key, String val) { 100c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) { 101c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mAllowCrossDomainRedirect = parseBoolean(val); 1025b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu // cross-protocol redirects are also controlled by this flag 1035b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect; 104c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } else { 105c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar return false; 106c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 107c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar return true; 108c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 109c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 110d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private Map<String, String> convertHeaderStringToMap(String headers) { 111d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber HashMap<String, String> map = new HashMap<String, String>(); 112d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 113d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber String[] pairs = headers.split("\r\n"); 114d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber for (String pair : pairs) { 115d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber int colonPos = pair.indexOf(":"); 116d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (colonPos >= 0) { 117d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber String key = pair.substring(0, colonPos); 118d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber String val = pair.substring(colonPos + 1); 119d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 120c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (!filterOutInternalHeaders(key, val)) { 121c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar map.put(key, val); 122c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 123d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 124d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 125d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 126d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return map; 127d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 128d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 1296e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 130d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public void disconnect() { 131d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber teardownConnection(); 132d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mHeaders = null; 133d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mURL = null; 134d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 135d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 136d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private void teardownConnection() { 137d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (mConnection != null) { 1386f357fd589e115a74aae25b1ac325af6121cdadfMarco Nelissen if (mInputStream != null) { 1396f357fd589e115a74aae25b1ac325af6121cdadfMarco Nelissen try { 1406f357fd589e115a74aae25b1ac325af6121cdadfMarco Nelissen mInputStream.close(); 1416f357fd589e115a74aae25b1ac325af6121cdadfMarco Nelissen } catch (IOException e) { 1426f357fd589e115a74aae25b1ac325af6121cdadfMarco Nelissen } 1436f357fd589e115a74aae25b1ac325af6121cdadfMarco Nelissen mInputStream = null; 1446f357fd589e115a74aae25b1ac325af6121cdadfMarco Nelissen } 145d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 146d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection.disconnect(); 147d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection = null; 148d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 149d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mCurrentOffset = -1; 150d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 151d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 152d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 153a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang private static final boolean isLocalHost(URL url) { 154a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang if (url == null) { 155a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang return false; 156a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 157a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 158a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang String host = url.getHost(); 159a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 160a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang if (host == null) { 161a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang return false; 162a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 163a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 164a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang try { 165a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang if (host.equalsIgnoreCase("localhost")) { 166a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang return true; 167a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 168a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang if (NetworkUtils.numericToInetAddress(host).isLoopbackAddress()) { 169a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang return true; 170a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 171a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } catch (IllegalArgumentException iex) { 172a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 173a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang return false; 174a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 175a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 176d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private void seekTo(long offset) throws IOException { 177d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber teardownConnection(); 178d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 179d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 180c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar int response; 181c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar int redirectCount = 0; 182c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 183c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar URL url = mURL; 184a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 185a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang // do not use any proxy for localhost (127.0.0.1) 186a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang boolean noProxy = isLocalHost(url); 187a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 188c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar while (true) { 189a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang if (noProxy) { 190a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); 191a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } else { 192a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang mConnection = (HttpURLConnection)url.openConnection(); 193a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 19490b59750436bc23ff040d9287651e51bfd7fb470Chong Zhang mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS); 195a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 196c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // handle redirects ourselves if we do not allow cross-domain redirect 197c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect); 198c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 199c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (mHeaders != null) { 200c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar for (Map.Entry<String, String> entry : mHeaders.entrySet()) { 201c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mConnection.setRequestProperty( 202c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar entry.getKey(), entry.getValue()); 203c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 204c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 205d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 206c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (offset > 0) { 207d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection.setRequestProperty( 208c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar "Range", "bytes=" + offset + "-"); 209c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 210c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 211c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response = mConnection.getResponseCode(); 212c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (response != HttpURLConnection.HTTP_MULT_CHOICE && 213c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response != HttpURLConnection.HTTP_MOVED_PERM && 214c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response != HttpURLConnection.HTTP_MOVED_TEMP && 215c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response != HttpURLConnection.HTTP_SEE_OTHER && 216c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response != HTTP_TEMP_REDIRECT) { 217c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // not a redirect, or redirect handled by HttpURLConnection 218c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar break; 219c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 220c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 221c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (++redirectCount > MAX_REDIRECTS) { 222c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Too many redirects: " + redirectCount); 223c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 224c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 225c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar String method = mConnection.getRequestMethod(); 226c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (response == HTTP_TEMP_REDIRECT && 227c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar !method.equals("GET") && !method.equals("HEAD")) { 228c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // "If the 307 status code is received in response to a 229c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // request other than GET or HEAD, the user agent MUST NOT 230c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // automatically redirect the request" 231c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Invalid redirect"); 232c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 233c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar String location = mConnection.getHeaderField("Location"); 234c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (location == null) { 235c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Invalid redirect"); 236c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 237c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar url = new URL(mURL /* TRICKY: don't use url! */, location); 238c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (!url.getProtocol().equals("https") && 239c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar !url.getProtocol().equals("http")) { 240c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Unsupported protocol redirect"); 241c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 2425b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol()); 2435b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu if (!mAllowCrossProtocolRedirect && !sameProtocol) { 2445b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu throw new NoRouteToHostException("Cross-protocol redirects are disallowed"); 2455b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu } 246c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar boolean sameHost = mURL.getHost().equals(url.getHost()); 2475b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu if (!mAllowCrossDomainRedirect && !sameHost) { 248c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Cross-domain redirects are disallowed"); 249d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 250d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 251c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (response != HTTP_TEMP_REDIRECT) { 252c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // update effective URL, unless it is a Temporary Redirect 253c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mURL = url; 254c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 255d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 256d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 257c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (mAllowCrossDomainRedirect) { 258c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // remember the current, potentially redirected URL if redirects 259c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // were handled by HttpURLConnection 260c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mURL = mConnection.getURL(); 261c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 2626e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen 2636e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen if (response == HttpURLConnection.HTTP_PARTIAL) { 264d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // Partial content, we cannot just use getContentLength 265d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // because what we want is not just the length of the range 266d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // returned but the size of the full content if available. 267d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 268d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber String contentRange = 269d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection.getHeaderField("Content-Range"); 270d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 271d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mTotalSize = -1; 272d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (contentRange != null) { 273d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // format is "bytes xxx-yyy/zzz 274d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // where "zzz" is the total number of bytes of the 275d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // content or '*' if unknown. 276d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 277d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber int lastSlashPos = contentRange.lastIndexOf('/'); 278d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (lastSlashPos >= 0) { 279d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber String total = 280d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber contentRange.substring(lastSlashPos + 1); 281d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 282d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 283d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mTotalSize = Long.parseLong(total); 284d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (NumberFormatException e) { 285d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 286d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 287d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 2886e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen } else if (response != HttpURLConnection.HTTP_OK) { 289d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber throw new IOException(); 290d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } else { 291d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mTotalSize = mConnection.getContentLength(); 292d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 293d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 2946e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) { 295d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // Some servers simply ignore "Range" requests and serve 296d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // data from the start of the content. 2978976a0954cce9cfc8bd8776893fc9067e240a91cChong Zhang throw new ProtocolException(); 298d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 299d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 300d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mInputStream = 301d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber new BufferedInputStream(mConnection.getInputStream()); 302d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 303d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mCurrentOffset = offset; 304d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (IOException e) { 305d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mTotalSize = -1; 3066f357fd589e115a74aae25b1ac325af6121cdadfMarco Nelissen teardownConnection(); 307d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mCurrentOffset = -1; 308d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 309d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber throw e; 310d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 311d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 312d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 3136e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 314d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public int readAt(long offset, int size) { 315d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return native_readAt(offset, size); 316d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 317d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 318d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private int readAt(long offset, byte[] data, int size) { 319d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber StrictMode.ThreadPolicy policy = 320d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber new StrictMode.ThreadPolicy.Builder().permitAll().build(); 321d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 322d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber StrictMode.setThreadPolicy(policy); 323d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 324d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 325d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (offset != mCurrentOffset) { 326d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber seekTo(offset); 327d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 328d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 329d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber int n = mInputStream.read(data, 0, size); 330d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 331d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (n == -1) { 332d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // InputStream signals EOS using a -1 result, our semantics 333d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // are to return a 0-length read. 334d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber n = 0; 335d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 336d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 337d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mCurrentOffset += n; 338d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 339d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (VERBOSE) { 340d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "readAt " + offset + " / " + size + " => " + n); 341d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 342d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 343d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return n; 3448976a0954cce9cfc8bd8776893fc9067e240a91cChong Zhang } catch (ProtocolException e) { 3458976a0954cce9cfc8bd8776893fc9067e240a91cChong Zhang Log.w(TAG, "readAt " + offset + " / " + size + " => " + e); 3468976a0954cce9cfc8bd8776893fc9067e240a91cChong Zhang return MEDIA_ERROR_UNSUPPORTED; 347c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } catch (NoRouteToHostException e) { 348c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar Log.w(TAG, "readAt " + offset + " / " + size + " => " + e); 349c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar return MEDIA_ERROR_UNSUPPORTED; 3506db04b369ec4a4d59315ba0207ecc53d8e8852ccAlex Klyubin } catch (UnknownServiceException e) { 3516db04b369ec4a4d59315ba0207ecc53d8e8852ccAlex Klyubin Log.w(TAG, "readAt " + offset + " / " + size + " => " + e); 3526db04b369ec4a4d59315ba0207ecc53d8e8852ccAlex Klyubin return MEDIA_ERROR_UNSUPPORTED; 35390b59750436bc23ff040d9287651e51bfd7fb470Chong Zhang } catch (IOException e) { 354d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (VERBOSE) { 355d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "readAt " + offset + " / " + size + " => -1"); 356d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 357d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return -1; 358d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (Exception e) { 359d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (VERBOSE) { 360d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "unknown exception " + e); 361d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "readAt " + offset + " / " + size + " => -1"); 362d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 363d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return -1; 364d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 365d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 366d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 3676e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 368d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public long getSize() { 369d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (mConnection == null) { 370d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 371d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber seekTo(0); 372d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (IOException e) { 373d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return -1; 374d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 375d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 376d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 377d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return mTotalSize; 378d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 379d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 3806e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 381d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public String getMIMEType() { 382d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (mConnection == null) { 383d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 384d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber seekTo(0); 385d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (IOException e) { 386d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return "application/octet-stream"; 387d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 388d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 389d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 390d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return mConnection.getContentType(); 391d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 392d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 393d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber @Override 3946e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen public String getUri() { 3956e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen return mURL.toString(); 3966e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen } 3976e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen 3986e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 399d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber protected void finalize() { 400d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber native_finalize(); 401d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 402d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 403d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private static native final void native_init(); 404d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private native final void native_setup(); 405d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private native final void native_finalize(); 406d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 407d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private native final IBinder native_getIMemory(); 408d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private native final int native_readAt(long offset, int size); 409d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 410d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber static { 411d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber System.loadLibrary("media_jni"); 412d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber native_init(); 413d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 414d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 4155e8ff02ec93aa0f933d0082d9a0e066b552c6a80Colin Cross private long mNativeContext; 4166e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen 417d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber} 418