Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 74b3cda9 authored by Lajos Molnar's avatar Lajos Molnar Committed by Android (Google) Code Review
Browse files

Merge "MediaHTTPConnection: support header android-allow-cross-domain-redirect"

parents f4600922 c446dc32
Loading
Loading
Loading
Loading
+97 −12
Original line number Diff line number Diff line
@@ -28,9 +28,12 @@ import java.net.CookieManager;
import java.net.URL;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.NoRouteToHostException;
import java.util.HashMap;
import java.util.Map;

import static android.media.MediaPlayer.MEDIA_ERROR_UNSUPPORTED;

/** @hide */
public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
    private static final String TAG = "MediaHTTPConnection";
@@ -43,6 +46,12 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
    private long mTotalSize = -1;
    private InputStream mInputStream = null;

    private boolean mAllowCrossDomainRedirect = true;

    // from com.squareup.okhttp.internal.http
    private final static int HTTP_TEMP_REDIRECT = 307;
    private final static int MAX_REDIRECTS = 20;

    public MediaHTTPConnection() {
        if (CookieHandler.getDefault() == null) {
            CookieHandler.setDefault(new CookieManager());
@@ -59,6 +68,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {

        try {
            disconnect();
            mAllowCrossDomainRedirect = true;
            mURL = new URL(uri);
            mHeaders = convertHeaderStringToMap(headers);
        } catch (MalformedURLException e) {
@@ -68,6 +78,25 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
        return native_getIMemory();
    }

    private boolean parseBoolean(String val) {
        try {
            return Long.parseLong(val) != 0;
        } catch (NumberFormatException e) {
            return "true".equalsIgnoreCase(val) ||
                "yes".equalsIgnoreCase(val);
        }
    }

    /* returns true iff header is internal */
    private boolean filterOutInternalHeaders(String key, String val) {
        if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
            mAllowCrossDomainRedirect = parseBoolean(val);
        } else {
            return false;
        }
        return true;
    }

    private Map<String, String> convertHeaderStringToMap(String headers) {
        HashMap<String, String> map = new HashMap<String, String>();

@@ -78,9 +107,11 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
                String key = pair.substring(0, colonPos);
                String val = pair.substring(colonPos + 1);

                if (!filterOutInternalHeaders(key, val)) {
                    map.put(key, val);
                }
            }
        }

        return map;
    }
@@ -107,7 +138,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
        teardownConnection();

        try {
            mConnection = (HttpURLConnection)mURL.openConnection();
            int response;
            int redirectCount = 0;

            URL url = mURL;
            while (true) {
                mConnection = (HttpURLConnection)url.openConnection();
                // handle redirects ourselves if we do not allow cross-domain redirect
                mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect);

                if (mHeaders != null) {
                    for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
@@ -121,9 +159,53 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
                            "Range", "bytes=" + offset + "-");
                }

            int response = mConnection.getResponseCode();
            // remember the current, possibly redirected URL
                response = mConnection.getResponseCode();
                if (response != HttpURLConnection.HTTP_MULT_CHOICE &&
                        response != HttpURLConnection.HTTP_MOVED_PERM &&
                        response != HttpURLConnection.HTTP_MOVED_TEMP &&
                        response != HttpURLConnection.HTTP_SEE_OTHER &&
                        response != HTTP_TEMP_REDIRECT) {
                    // not a redirect, or redirect handled by HttpURLConnection
                    break;
                }

                if (++redirectCount > MAX_REDIRECTS) {
                    throw new NoRouteToHostException("Too many redirects: " + redirectCount);
                }

                String method = mConnection.getRequestMethod();
                if (response == HTTP_TEMP_REDIRECT &&
                        !method.equals("GET") && !method.equals("HEAD")) {
                    // "If the 307 status code is received in response to a
                    // request other than GET or HEAD, the user agent MUST NOT
                    // automatically redirect the request"
                    throw new NoRouteToHostException("Invalid redirect");
                }
                String location = mConnection.getHeaderField("Location");
                if (location == null) {
                    throw new NoRouteToHostException("Invalid redirect");
                }
                url = new URL(mURL /* TRICKY: don't use url! */, location);
                if (!url.getProtocol().equals("https") &&
                        !url.getProtocol().equals("http")) {
                    throw new NoRouteToHostException("Unsupported protocol redirect");
                }
                boolean sameHost = mURL.getHost().equals(url.getHost());
                if (!sameHost) {
                    throw new NoRouteToHostException("Cross-domain redirects are disallowed");
                }

                if (response != HTTP_TEMP_REDIRECT) {
                    // update effective URL, unless it is a Temporary Redirect
                    mURL = url;
                }
            }

            if (mAllowCrossDomainRedirect) {
                // remember the current, potentially redirected URL if redirects
                // were handled by HttpURLConnection
                mURL = mConnection.getURL();
            }

            if (response == HttpURLConnection.HTTP_PARTIAL) {
                // Partial content, we cannot just use getContentLength
@@ -207,6 +289,9 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
            }

            return n;
        } catch (NoRouteToHostException e) {
            Log.w(TAG, "readAt " + offset + " / " + size + " => " + e);
            return MEDIA_ERROR_UNSUPPORTED;
        } catch (IOException e) {
            if (VERBOSE) {
                Log.d(TAG, "readAt " + offset + " / " + size + " => -1");