MediaHTTPConnection.java revision 90b59750436bc23ff040d9287651e51bfd7fb470
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) { 138d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mInputStream = null; 139d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 140d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection.disconnect(); 141d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection = null; 142d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 143d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mCurrentOffset = -1; 144d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 145d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 146d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 147a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang private static final boolean isLocalHost(URL url) { 148a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang if (url == null) { 149a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang return false; 150a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 151a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 152a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang String host = url.getHost(); 153a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 154a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang if (host == null) { 155a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang return false; 156a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 157a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 158a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang try { 159a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang if (host.equalsIgnoreCase("localhost")) { 160a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang return true; 161a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 162a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang if (NetworkUtils.numericToInetAddress(host).isLoopbackAddress()) { 163a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang return true; 164a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 165a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } catch (IllegalArgumentException iex) { 166a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 167a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang return false; 168a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 169a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 170d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private void seekTo(long offset) throws IOException { 171d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber teardownConnection(); 172d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 173d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 174c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar int response; 175c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar int redirectCount = 0; 176c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 177c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar URL url = mURL; 178a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 179a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang // do not use any proxy for localhost (127.0.0.1) 180a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang boolean noProxy = isLocalHost(url); 181a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 182c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar while (true) { 183a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang if (noProxy) { 184a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); 185a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } else { 186a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang mConnection = (HttpURLConnection)url.openConnection(); 187a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang } 18890b59750436bc23ff040d9287651e51bfd7fb470Chong Zhang mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS); 189a6ae8ba4a59f3f893fe8893335e7517388123c10Chong Zhang 190c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // handle redirects ourselves if we do not allow cross-domain redirect 191c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect); 192c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 193c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (mHeaders != null) { 194c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar for (Map.Entry<String, String> entry : mHeaders.entrySet()) { 195c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mConnection.setRequestProperty( 196c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar entry.getKey(), entry.getValue()); 197c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 198c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 199d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 200c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (offset > 0) { 201d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection.setRequestProperty( 202c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar "Range", "bytes=" + offset + "-"); 203c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 204c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 205c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response = mConnection.getResponseCode(); 206c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (response != HttpURLConnection.HTTP_MULT_CHOICE && 207c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response != HttpURLConnection.HTTP_MOVED_PERM && 208c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response != HttpURLConnection.HTTP_MOVED_TEMP && 209c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response != HttpURLConnection.HTTP_SEE_OTHER && 210c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response != HTTP_TEMP_REDIRECT) { 211c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // not a redirect, or redirect handled by HttpURLConnection 212c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar break; 213c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 214c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 215c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (++redirectCount > MAX_REDIRECTS) { 216c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Too many redirects: " + redirectCount); 217c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 218c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 219c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar String method = mConnection.getRequestMethod(); 220c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (response == HTTP_TEMP_REDIRECT && 221c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar !method.equals("GET") && !method.equals("HEAD")) { 222c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // "If the 307 status code is received in response to a 223c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // request other than GET or HEAD, the user agent MUST NOT 224c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // automatically redirect the request" 225c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Invalid redirect"); 226c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 227c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar String location = mConnection.getHeaderField("Location"); 228c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (location == null) { 229c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Invalid redirect"); 230c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 231c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar url = new URL(mURL /* TRICKY: don't use url! */, location); 232c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (!url.getProtocol().equals("https") && 233c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar !url.getProtocol().equals("http")) { 234c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Unsupported protocol redirect"); 235c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 2365b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol()); 2375b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu if (!mAllowCrossProtocolRedirect && !sameProtocol) { 2385b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu throw new NoRouteToHostException("Cross-protocol redirects are disallowed"); 2395b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu } 240c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar boolean sameHost = mURL.getHost().equals(url.getHost()); 2415b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu if (!mAllowCrossDomainRedirect && !sameHost) { 242c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Cross-domain redirects are disallowed"); 243d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 244d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 245c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (response != HTTP_TEMP_REDIRECT) { 246c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // update effective URL, unless it is a Temporary Redirect 247c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mURL = url; 248c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 249d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 250d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 251c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (mAllowCrossDomainRedirect) { 252c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // remember the current, potentially redirected URL if redirects 253c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // were handled by HttpURLConnection 254c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mURL = mConnection.getURL(); 255c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 2566e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen 2576e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen if (response == HttpURLConnection.HTTP_PARTIAL) { 258d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // Partial content, we cannot just use getContentLength 259d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // because what we want is not just the length of the range 260d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // returned but the size of the full content if available. 261d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 262d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber String contentRange = 263d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection.getHeaderField("Content-Range"); 264d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 265d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mTotalSize = -1; 266d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (contentRange != null) { 267d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // format is "bytes xxx-yyy/zzz 268d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // where "zzz" is the total number of bytes of the 269d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // content or '*' if unknown. 270d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 271d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber int lastSlashPos = contentRange.lastIndexOf('/'); 272d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (lastSlashPos >= 0) { 273d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber String total = 274d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber contentRange.substring(lastSlashPos + 1); 275d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 276d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 277d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mTotalSize = Long.parseLong(total); 278d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (NumberFormatException e) { 279d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 280d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 281d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 2826e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen } else if (response != HttpURLConnection.HTTP_OK) { 283d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber throw new IOException(); 284d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } else { 285d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mTotalSize = mConnection.getContentLength(); 286d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 287d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 2886e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) { 289d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // Some servers simply ignore "Range" requests and serve 290d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // data from the start of the content. 2918976a0954cce9cfc8bd8776893fc9067e240a91cChong Zhang throw new ProtocolException(); 292d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 293d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 294d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mInputStream = 295d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber new BufferedInputStream(mConnection.getInputStream()); 296d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 297d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mCurrentOffset = offset; 298d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (IOException e) { 299d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mTotalSize = -1; 300d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mInputStream = null; 301d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection = null; 302d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mCurrentOffset = -1; 303d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 304d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber throw e; 305d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 306d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 307d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 3086e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 309d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public int readAt(long offset, int size) { 310d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return native_readAt(offset, size); 311d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 312d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 313d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private int readAt(long offset, byte[] data, int size) { 314d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber StrictMode.ThreadPolicy policy = 315d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber new StrictMode.ThreadPolicy.Builder().permitAll().build(); 316d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 317d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber StrictMode.setThreadPolicy(policy); 318d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 319d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 320d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (offset != mCurrentOffset) { 321d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber seekTo(offset); 322d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 323d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 324d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber int n = mInputStream.read(data, 0, size); 325d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 326d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (n == -1) { 327d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // InputStream signals EOS using a -1 result, our semantics 328d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // are to return a 0-length read. 329d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber n = 0; 330d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 331d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 332d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mCurrentOffset += n; 333d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 334d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (VERBOSE) { 335d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "readAt " + offset + " / " + size + " => " + n); 336d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 337d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 338d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return n; 3398976a0954cce9cfc8bd8776893fc9067e240a91cChong Zhang } catch (ProtocolException e) { 3408976a0954cce9cfc8bd8776893fc9067e240a91cChong Zhang Log.w(TAG, "readAt " + offset + " / " + size + " => " + e); 3418976a0954cce9cfc8bd8776893fc9067e240a91cChong Zhang return MEDIA_ERROR_UNSUPPORTED; 342c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } catch (NoRouteToHostException e) { 343c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar Log.w(TAG, "readAt " + offset + " / " + size + " => " + e); 344c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar return MEDIA_ERROR_UNSUPPORTED; 3456db04b369ec4a4d59315ba0207ecc53d8e8852ccAlex Klyubin } catch (UnknownServiceException e) { 3466db04b369ec4a4d59315ba0207ecc53d8e8852ccAlex Klyubin Log.w(TAG, "readAt " + offset + " / " + size + " => " + e); 3476db04b369ec4a4d59315ba0207ecc53d8e8852ccAlex Klyubin return MEDIA_ERROR_UNSUPPORTED; 34890b59750436bc23ff040d9287651e51bfd7fb470Chong Zhang } catch (IOException e) { 349d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (VERBOSE) { 350d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "readAt " + offset + " / " + size + " => -1"); 351d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 352d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return -1; 353d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (Exception e) { 354d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (VERBOSE) { 355d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "unknown exception " + e); 356d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "readAt " + offset + " / " + size + " => -1"); 357d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 358d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return -1; 359d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 360d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 361d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 3626e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 363d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public long getSize() { 364d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (mConnection == null) { 365d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 366d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber seekTo(0); 367d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (IOException e) { 368d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return -1; 369d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 370d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 371d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 372d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return mTotalSize; 373d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 374d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 3756e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 376d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public String getMIMEType() { 377d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (mConnection == null) { 378d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 379d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber seekTo(0); 380d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (IOException e) { 381d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return "application/octet-stream"; 382d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 383d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 384d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 385d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return mConnection.getContentType(); 386d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 387d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 388d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber @Override 3896e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen public String getUri() { 3906e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen return mURL.toString(); 3916e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen } 3926e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen 3936e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 394d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber protected void finalize() { 395d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber native_finalize(); 396d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 397d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 398d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private static native final void native_init(); 399d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private native final void native_setup(); 400d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private native final void native_finalize(); 401d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 402d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private native final IBinder native_getIMemory(); 403d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private native final int native_readAt(long offset, int size); 404d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 405d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber static { 406d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber System.loadLibrary("media_jni"); 407d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber native_init(); 408d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 409d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 4105e8ff02ec93aa0f933d0082d9a0e066b552c6a80Colin Cross private long mNativeContext; 4116e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen 412d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber} 413