Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(743)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaUrlResolver.java

Issue 1044733003: Remove uses of deprecated Header class (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move canPlayMedia to MediaUrlResolver Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/android/java/src/org/chromium/chrome/browser/media/remote/DefaultMediaRouteController.java ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.media.remote; 5 package org.chromium.chrome.browser.media.remote;
6 6
7 import android.content.Context; 7 import android.content.Context;
8 import android.net.Uri; 8 import android.net.Uri;
9 import android.os.AsyncTask; 9 import android.os.AsyncTask;
10 import android.text.TextUtils; 10 import android.text.TextUtils;
11 import android.util.Log; 11 import android.util.Log;
12 12
13 import org.apache.http.Header; 13 import org.chromium.base.CommandLine;
14 import org.apache.http.message.BasicHeader; 14 import org.chromium.chrome.ChromeSwitches;
15 import org.chromium.chrome.browser.ChromiumApplication; 15 import org.chromium.chrome.browser.ChromiumApplication;
16 16
17 import java.io.IOException; 17 import java.io.IOException;
18 import java.net.HttpURLConnection; 18 import java.net.HttpURLConnection;
19 import java.net.MalformedURLException; 19 import java.net.MalformedURLException;
20 import java.net.URI; 20 import java.net.URI;
21 import java.net.URISyntaxException; 21 import java.net.URISyntaxException;
22 import java.net.URL; 22 import java.net.URL;
23 import java.util.Arrays; 23 import java.util.List;
24 import java.util.Map;
24 25
25 /** 26 /**
26 * Resolves the final URL if it's a redirect. Works asynchronously, uses HTTP 27 * Resolves the final URL if it's a redirect. Works asynchronously, uses HTTP
27 * HEAD request to determine if the URL is redirected. 28 * HEAD request to determine if the URL is redirected.
28 */ 29 */
29 public class MediaUrlResolver extends AsyncTask<Void, Void, MediaUrlResolver.Res ult> { 30 public class MediaUrlResolver extends AsyncTask<Void, Void, MediaUrlResolver.Res ult> {
30 31
31 /** 32 /**
32 * The interface to get the initial URI with cookies from and pass the final 33 * The interface to get the initial URI with cookies from and pass the final
33 * URI to. 34 * URI to.
34 */ 35 */
35 public interface Delegate { 36 public interface Delegate {
36 /** 37 /**
37 * @return the original URL to resolve. 38 * @return the original URL to resolve.
38 */ 39 */
39 Uri getUri(); 40 Uri getUri();
40 41
41 /** 42 /**
42 * @return the cookies to fetch the URL with. 43 * @return the cookies to fetch the URL with.
43 */ 44 */
44 String getCookies(); 45 String getCookies();
45 46
46 /** 47 /**
47 * Passes the resolved URL to the delegate. 48 * Passes the resolved URL to the delegate.
48 * 49 *
49 * @param uri the resolved URL. 50 * @param uri the resolved URL.
50 */ 51 */
51 void setUri(Uri uri, Header[] headers); 52 void setUri(Uri uri, boolean palyable);
52 } 53 }
53 54
54 55
55 protected static final class Result { 56 protected static final class Result {
56 private final String mUri; 57 private final String mUri;
57 private final Header[] mRelevantHeaders; 58 private final boolean mPlayable;
58 59
59 public Result(String uri, Header[] relevantHeaders) { 60 public Result(String uri, boolean playable) {
60 mUri = uri; 61 mUri = uri;
61 mRelevantHeaders = 62 mPlayable = playable;
62 relevantHeaders != null
63 ? Arrays.copyOf(relevantHeaders, relevantHeaders.length)
64 : null;
65 } 63 }
66 64
67 public String getUri() { 65 public String getUri() {
68 return mUri; 66 return mUri;
69 } 67 }
70 68
71 public Header[] getRelevantHeaders() { 69 public boolean isPlayable() {
72 return mRelevantHeaders != null 70 return mPlayable;
73 ? Arrays.copyOf(mRelevantHeaders, mRelevantHeaders.length)
74 : null;
75 } 71 }
76 } 72 }
77 73
78 private static final String TAG = "MediaUrlResolver"; 74 private static final String TAG = "MediaUrlResolver";
79 75
80 private static final String CORS_HEADER_NAME = "Access-Control-Allow-Origin" ;
81 private static final String COOKIES_HEADER_NAME = "Cookies"; 76 private static final String COOKIES_HEADER_NAME = "Cookies";
82 private static final String USER_AGENT_HEADER_NAME = "User-Agent"; 77 private static final String USER_AGENT_HEADER_NAME = "User-Agent";
83 private static final String RANGE_HEADER_NAME = "Range"; 78 private static final String RANGE_HEADER_NAME = "Range";
79 private static final String CORS_HEADER_NAME = "Access-Control-Allow-Origin" ;
80
81 // Media types supported for cast, see
82 // media/base/container_names.h for the actual enum where these are defined
83 private static final int UNKNOWN_MEDIA = 0;
84 private static final int SMOOTHSTREAM_MEDIA = 39;
85 private static final int DASH_MEDIA = 38;
86 private static final int HLS_MEDIA = 22;
87 private static final int MPEG4_MEDIA = 29;
84 88
85 // We don't want to necessarily fetch the whole video but we don't want to m iss the CORS header. 89 // We don't want to necessarily fetch the whole video but we don't want to m iss the CORS header.
86 // Assume that 64k should be more than enough to keep all the headers. 90 // Assume that 64k should be more than enough to keep all the headers.
87 private static final String RANGE_HEADER_VALUE = "bytes: 0-65536"; 91 private static final String RANGE_HEADER_VALUE = "bytes: 0-65536";
88 92
89 private final Context mContext;
90 private final Delegate mDelegate; 93 private final Delegate mDelegate;
94 private boolean mDebug;
91 95
92 /** 96 /**
93 * The constructor 97 * The constructor
94 * @param context the context to use to resolve the URL 98 * @param context the context to use to resolve the URL
95 * @param delegate The customer for this URL resolver. 99 * @param delegate The customer for this URL resolver.
96 */ 100 */
97 public MediaUrlResolver(Context context, Delegate delegate) { 101 public MediaUrlResolver(Context context, Delegate delegate) {
98 mContext = context; 102 mDebug = CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_CAST_ DEBUG_LOGS);
99 mDelegate = delegate; 103 mDelegate = delegate;
100 } 104 }
101 105
102 @Override 106 @Override
103 protected MediaUrlResolver.Result doInBackground(Void... params) { 107 protected MediaUrlResolver.Result doInBackground(Void... params) {
104 Uri uri = mDelegate.getUri(); 108 Uri uri = mDelegate.getUri();
105 String url = uri.toString(); 109 String url = uri.toString();
106 Header[] relevantHeaders = null;
107 String cookies = mDelegate.getCookies(); 110 String cookies = mDelegate.getCookies();
108 String userAgent = ChromiumApplication.getBrowserUserAgent(); 111 String userAgent = ChromiumApplication.getBrowserUserAgent();
109 // URL may already be partially percent encoded; double percent encoding will break 112 // URL may already be partially percent encoded; double percent encoding will break
110 // things, so decode it before sanitizing it. 113 // things, so decode it before sanitizing it.
111 String sanitizedUrl = sanitizeUrl(Uri.decode(url)); 114 String sanitizedUrl = sanitizeUrl(Uri.decode(url));
115 Map<String, List<String>> headers = null;
112 116
113 // If we failed to sanitize the URL (e.g. because the host name contains underscores) then 117 // If we failed to sanitize the URL (e.g. because the host name contains underscores) then
114 // HttpURLConnection won't work,so we can't follow redirections. Just tr y to use it as is. 118 // HttpURLConnection won't work,so we can't follow redirections. Just tr y to use it as is.
115 // TODO (aberent): Find out if there is a way of following redirections that is not so 119 // TODO (aberent): Find out if there is a way of following redirections that is not so
116 // strict on the URL format. 120 // strict on the URL format.
117 if (!sanitizedUrl.equals("")) { 121 if (!sanitizedUrl.equals("")) {
118 HttpURLConnection urlConnection = null; 122 HttpURLConnection urlConnection = null;
119 try { 123 try {
120 URL requestUrl = new URL(sanitizedUrl); 124 URL requestUrl = new URL(sanitizedUrl);
121 urlConnection = (HttpURLConnection) requestUrl.openConnection(); 125 urlConnection = (HttpURLConnection) requestUrl.openConnection();
122 if (!TextUtils.isEmpty(cookies)) { 126 if (!TextUtils.isEmpty(cookies)) {
123 urlConnection.setRequestProperty(COOKIES_HEADER_NAME, cookie s); 127 urlConnection.setRequestProperty(COOKIES_HEADER_NAME, cookie s);
124 } 128 }
125 urlConnection.setRequestProperty(USER_AGENT_HEADER_NAME, userAge nt); 129 urlConnection.setRequestProperty(USER_AGENT_HEADER_NAME, userAge nt);
126 urlConnection.setRequestProperty(RANGE_HEADER_NAME, RANGE_HEADER _VALUE); 130 urlConnection.setRequestProperty(RANGE_HEADER_NAME, RANGE_HEADER _VALUE);
127 131
128 // This triggers resolving the URL and receiving the headers. 132 // This triggers resolving the URL and receiving the headers.
129 urlConnection.getHeaderFields(); 133 headers = urlConnection.getHeaderFields();
130 134
131 url = urlConnection.getURL().toString(); 135 url = urlConnection.getURL().toString();
132 String corsHeader = urlConnection.getHeaderField(CORS_HEADER_NAM E);
133 if (corsHeader != null) {
134 relevantHeaders = new Header[1];
135 relevantHeaders[0] = new BasicHeader(CORS_HEADER_NAME, corsH eader);
136 }
137 } catch (IOException e) { 136 } catch (IOException e) {
138 Log.e(TAG, "Failed to fetch the final URI", e); 137 Log.e(TAG, "Failed to fetch the final URI", e);
139 url = ""; 138 url = "";
140 } 139 }
141 if (urlConnection != null) urlConnection.disconnect(); 140 if (urlConnection != null) urlConnection.disconnect();
142 } 141 }
143 return new MediaUrlResolver.Result(url, relevantHeaders); 142 return new MediaUrlResolver.Result(url, canPlayMedia(url, headers));
144 } 143 }
145 144
146 @Override 145 @Override
147 protected void onPostExecute(MediaUrlResolver.Result result) { 146 protected void onPostExecute(MediaUrlResolver.Result result) {
148 String url = result.getUri(); 147 String url = result.getUri();
149 Uri uri = "".equals(url) ? Uri.EMPTY : Uri.parse(url); 148 Uri uri = "".equals(url) ? Uri.EMPTY : Uri.parse(url);
150 mDelegate.setUri(uri, result.getRelevantHeaders()); 149 mDelegate.setUri(uri, result.isPlayable());
151 } 150 }
152 151
153 private String sanitizeUrl(String unsafeUrl) { 152 private String sanitizeUrl(String unsafeUrl) {
154 URL url; 153 URL url;
155 URI uri; 154 URI uri;
156 try { 155 try {
157 url = new URL(unsafeUrl); 156 url = new URL(unsafeUrl);
158 uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), u rl.getPort(), 157 uri = new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), u rl.getPort(),
159 url.getPath(), url.getQuery(), url.getRef()); 158 url.getPath(), url.getQuery(), url.getRef());
160 return uri.toURL().toString(); 159 return uri.toURL().toString();
161 } catch (URISyntaxException syntaxException) { 160 } catch (URISyntaxException syntaxException) {
162 Log.w(TAG, "URISyntaxException " + syntaxException); 161 Log.w(TAG, "URISyntaxException " + syntaxException);
163 } catch (MalformedURLException malformedUrlException) { 162 } catch (MalformedURLException malformedUrlException) {
164 Log.w(TAG, "MalformedURLException " + malformedUrlException); 163 Log.w(TAG, "MalformedURLException " + malformedUrlException);
165 } 164 }
166 return ""; 165 return "";
167 } 166 }
167
168 private boolean canPlayMedia(String url, Map<String, List<String>> headers) {
169 if (url == "") return false;
170
171 // HLS media requires Cors headers.
172 if ((headers == null || isEnhancedMedia(url) && !headers.containsKey(COR S_HEADER_NAME))) {
173 if (mDebug) Log.d(TAG, "HLS stream without CORs header: " + url);
174 return false;
175 }
176 return true;
177 }
178
179 private boolean isEnhancedMedia(String url) {
180 int mediaType = getMediaType(url);
181 return mediaType == HLS_MEDIA || mediaType == DASH_MEDIA || mediaType == SMOOTHSTREAM_MEDIA;
182 }
183
184 static int getMediaType(String url) {
185 if (url.contains(".m3u8")) {
186 return HLS_MEDIA;
whywhat 2015/03/30 17:34:02 nit: these if-s are probably one liners?
aberent 2015/03/31 09:18:08 Done.
187 }
188 if (url.contains(".mp4")) {
189 return MPEG4_MEDIA;
190 }
191 if (url.contains(".mpd")) {
192 return DASH_MEDIA;
193 }
194 if (url.contains(".ism")) {
195 return SMOOTHSTREAM_MEDIA;
196 }
197 return UNKNOWN_MEDIA;
198 }
168 } 199 }
OLDNEW
« no previous file with comments | « chrome/android/java/src/org/chromium/chrome/browser/media/remote/DefaultMediaRouteController.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698