MediaHTTPConnection.java revision 5b9305fe9bbe8bb6916bd8daff085c0675b626f3
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 19d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport android.os.IBinder; 20d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport android.os.StrictMode; 21d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport android.util.Log; 22d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 23d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.io.BufferedInputStream; 24d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.io.InputStream; 25d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.io.IOException; 26d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.net.CookieHandler; 27d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.net.CookieManager; 28d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.net.URL; 29d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.net.HttpURLConnection; 30d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.net.MalformedURLException; 31c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnarimport java.net.NoRouteToHostException; 32d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.util.HashMap; 33d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberimport java.util.Map; 34d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 35c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnarimport static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED; 36c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 37d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber/** @hide */ 38d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huberpublic class MediaHTTPConnection extends IMediaHTTPConnection.Stub { 39d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private static final String TAG = "MediaHTTPConnection"; 40d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private static final boolean VERBOSE = false; 41d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 42d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private long mCurrentOffset = -1; 43d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private URL mURL = null; 44d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private Map<String, String> mHeaders = null; 45d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private HttpURLConnection mConnection = null; 46d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private long mTotalSize = -1; 47d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private InputStream mInputStream = null; 48d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 49c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar private boolean mAllowCrossDomainRedirect = true; 505b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu private boolean mAllowCrossProtocolRedirect = true; 51c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 52c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // from com.squareup.okhttp.internal.http 53c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar private final static int HTTP_TEMP_REDIRECT = 307; 54c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar private final static int MAX_REDIRECTS = 20; 55c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 56d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public MediaHTTPConnection() { 57d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (CookieHandler.getDefault() == null) { 58d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber CookieHandler.setDefault(new CookieManager()); 59d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 60d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 61d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber native_setup(); 62d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 63d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 646e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 65d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public IBinder connect(String uri, String headers) { 66d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (VERBOSE) { 67d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers); 68d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 69d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 70d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 71d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber disconnect(); 72c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mAllowCrossDomainRedirect = true; 73d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mURL = new URL(uri); 74d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mHeaders = convertHeaderStringToMap(headers); 75d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (MalformedURLException e) { 76d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return null; 77d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 78d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 79d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return native_getIMemory(); 80d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 81d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 82c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar private boolean parseBoolean(String val) { 83c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar try { 84c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar return Long.parseLong(val) != 0; 85c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } catch (NumberFormatException e) { 86c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar return "true".equalsIgnoreCase(val) || 87c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar "yes".equalsIgnoreCase(val); 88c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 89c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 90c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 91c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar /* returns true iff header is internal */ 92c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar private boolean filterOutInternalHeaders(String key, String val) { 93c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) { 94c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mAllowCrossDomainRedirect = parseBoolean(val); 955b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu // cross-protocol redirects are also controlled by this flag 965b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect; 97c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } else { 98c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar return false; 99c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 100c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar return true; 101c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 102c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 103d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private Map<String, String> convertHeaderStringToMap(String headers) { 104d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber HashMap<String, String> map = new HashMap<String, String>(); 105d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 106d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber String[] pairs = headers.split("\r\n"); 107d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber for (String pair : pairs) { 108d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber int colonPos = pair.indexOf(":"); 109d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (colonPos >= 0) { 110d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber String key = pair.substring(0, colonPos); 111d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber String val = pair.substring(colonPos + 1); 112d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 113c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (!filterOutInternalHeaders(key, val)) { 114c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar map.put(key, val); 115c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 116d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 117d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 118d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 119d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return map; 120d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 121d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 1226e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 123d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public void disconnect() { 124d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber teardownConnection(); 125d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mHeaders = null; 126d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mURL = null; 127d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 128d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 129d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private void teardownConnection() { 130d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (mConnection != null) { 131d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mInputStream = null; 132d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 133d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection.disconnect(); 134d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection = null; 135d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 136d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mCurrentOffset = -1; 137d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 138d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 139d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 140d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private void seekTo(long offset) throws IOException { 141d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber teardownConnection(); 142d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 143d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 144c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar int response; 145c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar int redirectCount = 0; 146c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 147c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar URL url = mURL; 148c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar while (true) { 149c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mConnection = (HttpURLConnection)url.openConnection(); 150c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // handle redirects ourselves if we do not allow cross-domain redirect 151c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect); 152c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 153c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (mHeaders != null) { 154c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar for (Map.Entry<String, String> entry : mHeaders.entrySet()) { 155c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mConnection.setRequestProperty( 156c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar entry.getKey(), entry.getValue()); 157c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 158c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 159d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 160c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (offset > 0) { 161d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection.setRequestProperty( 162c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar "Range", "bytes=" + offset + "-"); 163c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 164c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 165c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response = mConnection.getResponseCode(); 166c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (response != HttpURLConnection.HTTP_MULT_CHOICE && 167c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response != HttpURLConnection.HTTP_MOVED_PERM && 168c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response != HttpURLConnection.HTTP_MOVED_TEMP && 169c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response != HttpURLConnection.HTTP_SEE_OTHER && 170c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar response != HTTP_TEMP_REDIRECT) { 171c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // not a redirect, or redirect handled by HttpURLConnection 172c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar break; 173c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 174c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 175c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (++redirectCount > MAX_REDIRECTS) { 176c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Too many redirects: " + redirectCount); 177c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 178c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar 179c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar String method = mConnection.getRequestMethod(); 180c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (response == HTTP_TEMP_REDIRECT && 181c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar !method.equals("GET") && !method.equals("HEAD")) { 182c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // "If the 307 status code is received in response to a 183c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // request other than GET or HEAD, the user agent MUST NOT 184c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // automatically redirect the request" 185c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Invalid redirect"); 186c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 187c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar String location = mConnection.getHeaderField("Location"); 188c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (location == null) { 189c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Invalid redirect"); 190c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 191c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar url = new URL(mURL /* TRICKY: don't use url! */, location); 192c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (!url.getProtocol().equals("https") && 193c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar !url.getProtocol().equals("http")) { 194c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Unsupported protocol redirect"); 195c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 1965b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol()); 1975b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu if (!mAllowCrossProtocolRedirect && !sameProtocol) { 1985b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu throw new NoRouteToHostException("Cross-protocol redirects are disallowed"); 1995b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu } 200c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar boolean sameHost = mURL.getHost().equals(url.getHost()); 2015b9305fe9bbe8bb6916bd8daff085c0675b626f3Ronghua Wu if (!mAllowCrossDomainRedirect && !sameHost) { 202c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar throw new NoRouteToHostException("Cross-domain redirects are disallowed"); 203d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 204d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 205c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (response != HTTP_TEMP_REDIRECT) { 206c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // update effective URL, unless it is a Temporary Redirect 207c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mURL = url; 208c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 209d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 210d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 211c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar if (mAllowCrossDomainRedirect) { 212c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // remember the current, potentially redirected URL if redirects 213c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar // were handled by HttpURLConnection 214c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar mURL = mConnection.getURL(); 215c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } 2166e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen 2176e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen if (response == HttpURLConnection.HTTP_PARTIAL) { 218d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // Partial content, we cannot just use getContentLength 219d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // because what we want is not just the length of the range 220d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // returned but the size of the full content if available. 221d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 222d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber String contentRange = 223d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection.getHeaderField("Content-Range"); 224d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 225d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mTotalSize = -1; 226d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (contentRange != null) { 227d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // format is "bytes xxx-yyy/zzz 228d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // where "zzz" is the total number of bytes of the 229d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // content or '*' if unknown. 230d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 231d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber int lastSlashPos = contentRange.lastIndexOf('/'); 232d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (lastSlashPos >= 0) { 233d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber String total = 234d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber contentRange.substring(lastSlashPos + 1); 235d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 236d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 237d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mTotalSize = Long.parseLong(total); 238d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (NumberFormatException e) { 239d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 240d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 241d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 2426e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen } else if (response != HttpURLConnection.HTTP_OK) { 243d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber throw new IOException(); 244d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } else { 245d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mTotalSize = mConnection.getContentLength(); 246d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 247d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 2486e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) { 249d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // Some servers simply ignore "Range" requests and serve 250d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // data from the start of the content. 251d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber throw new IOException(); 252d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 253d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 254d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mInputStream = 255d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber new BufferedInputStream(mConnection.getInputStream()); 256d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 257d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mCurrentOffset = offset; 258d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (IOException e) { 259d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mTotalSize = -1; 260d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mInputStream = null; 261d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mConnection = null; 262d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mCurrentOffset = -1; 263d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 264d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber throw e; 265d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 266d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 267d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 2686e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 269d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public int readAt(long offset, int size) { 270d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return native_readAt(offset, size); 271d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 272d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 273d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private int readAt(long offset, byte[] data, int size) { 274d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber StrictMode.ThreadPolicy policy = 275d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber new StrictMode.ThreadPolicy.Builder().permitAll().build(); 276d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 277d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber StrictMode.setThreadPolicy(policy); 278d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 279d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 280d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (offset != mCurrentOffset) { 281d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber seekTo(offset); 282d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 283d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 284d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber int n = mInputStream.read(data, 0, size); 285d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 286d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (n == -1) { 287d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // InputStream signals EOS using a -1 result, our semantics 288d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber // are to return a 0-length read. 289d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber n = 0; 290d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 291d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 292d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber mCurrentOffset += n; 293d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 294d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (VERBOSE) { 295d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "readAt " + offset + " / " + size + " => " + n); 296d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 297d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 298d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return n; 299c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar } catch (NoRouteToHostException e) { 300c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar Log.w(TAG, "readAt " + offset + " / " + size + " => " + e); 301c446dc32742de388b95ff7cf97f4dc1576cb57c5Lajos Molnar return MEDIA_ERROR_UNSUPPORTED; 302d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (IOException e) { 303d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (VERBOSE) { 304d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "readAt " + offset + " / " + size + " => -1"); 305d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 306d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return -1; 307d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (Exception e) { 308d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (VERBOSE) { 309d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "unknown exception " + e); 310d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber Log.d(TAG, "readAt " + offset + " / " + size + " => -1"); 311d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 312d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return -1; 313d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 314d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 315d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 3166e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 317d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public long getSize() { 318d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (mConnection == null) { 319d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 320d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber seekTo(0); 321d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (IOException e) { 322d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return -1; 323d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 324d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 325d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 326d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return mTotalSize; 327d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 328d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 3296e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 330d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber public String getMIMEType() { 331d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber if (mConnection == null) { 332d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber try { 333d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber seekTo(0); 334d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } catch (IOException e) { 335d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return "application/octet-stream"; 336d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 337d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 338d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 339d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber return mConnection.getContentType(); 340d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 341d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 342d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber @Override 3436e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen public String getUri() { 3446e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen return mURL.toString(); 3456e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen } 3466e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen 3476e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen @Override 348d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber protected void finalize() { 349d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber native_finalize(); 350d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 351d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 352d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private static native final void native_init(); 353d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private native final void native_setup(); 354d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private native final void native_finalize(); 355d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 356d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private native final IBinder native_getIMemory(); 357d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber private native final int native_readAt(long offset, int size); 358d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 359d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber static { 360d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber System.loadLibrary("media_jni"); 361d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber native_init(); 362d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber } 363d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber 3645e8ff02ec93aa0f933d0082d9a0e066b552c6a80Colin Cross private long mNativeContext; 3656e89ddc0468495aa15c8408980bb7a86bf2ad604Marco Nelissen 366d2506a506303ed94fd1991cf986b825b870a67c5Andreas Huber} 367