Reputation: 11095
Is there a way for me to capture all HTTP requests that are being sent from my app, and modify their headers before they are sent? I want to modify their referer
header so that the server that the requests are sent to thinks as if they are coming from a web browser instead of a mobile application. Thank you!
Update: To give you more context, I am planning to port a chrome extension Instant Music into an Android app by using Phonegap. Some YouTube videos that are allowed on PC are not allowed on mobile and I suspect that's because youtube player embedded inside an android app doesn't have a referrer header. I am trying to find a solution to this problem so that I can play such videos on mobile too.
Upvotes: 14
Views: 15000
Reputation: 44118
Youtube detects user browser's Agent String
which contains information about the browser. If you were to use a WebView
to show the youtube video instead, then it would be possible to set that WebView
's Agent String
.
You can find agent strings of different browsers on the internet. I found some here: Agent Strings.
Here's how i play Bob Marley's song that is not allowed on mobile phones by impersonating a Firefox browser:
package com.my.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
public class MyActivity extends Activity {
private WebView mWebView ;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mWebView = new WebView(this);
// Enable javascript
mWebView.getSettings().setJavaScriptEnabled(true);
// Impersonate Mozzila browser
mWebView.getSettings().setUserAgentString("Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:21.0.0) Gecko/20121011 Firefox/21.0.0");
final Activity activity = this;
mWebView.setWebViewClient(new WebViewClient() {
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(activity, description, Toast.LENGTH_SHORT).show();
}
});
mWebView .loadUrl("http://youtube.com/watch?v=x59kS2AOrGM");
setContentView(mWebView);
}
}
EDIT:
You also need to give permission for your Activity to use the internet, by adding this line to your AndroidManifest.xml
:
<uses-permission android:name="android.permission.INTERNET" />
Upvotes: 8
Reputation: 5320
DISCLAIMER: Dirty hack, only tested on Android 4.4 but should work for Android 4.0 and above.
The setupURLStreamHandlerFactory() methods needs to be called as early as possible and sets our own URL stream handler factory with URL.setURLStreamHandlerFactory()
. The factory is used for all connections opened via URL.openConnection()
. We set up a special handler for all http://... URLs which sets the 'Referer' header on the created HttpUrlConnection.
private static String REFERER_URL = "http://www.example.com/referer";
private void setupURLStreamHandlerFactory() {
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("http".equals(protocol)) {
try {
String className = Build.VERSION.SDK_INT < 19 ? "libcore.net.http.HttpHandler" : "com.android.okhttp.HttpHandler";
URLStreamHandler streamHandler = (URLStreamHandler) Class
.forName(className).newInstance();
return wrap(streamHandler);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return null;
}
});
}
private static URLStreamHandler wrap(final URLStreamHandler streamHandler) {
return new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL u) throws IOException {
URLConnection conn;
try {
Method openConnectionMethod = URLStreamHandler.class
.getDeclaredMethod("openConnection", URL.class);
openConnectionMethod.setAccessible(true);
conn = (URLConnection) openConnectionMethod.invoke(
streamHandler, u);
conn.setRequestProperty("Referer", REFERER_URL);
return conn;
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof IOException) {
throw (IOException) e.getTargetException();
} else {
throw new RuntimeException(e);
}
}
}
};
}
EDIT: Modified to work for versions prior to Android 4.4 Kitkat as well
Upvotes: 5
Reputation: 6705
You can set a header easily enough like this:
final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36";
final String URL = "http://www.cnn.com";
final String REFERER_URL = "http://www.w3.org/hypertext/DataSources/Overview.html";
HttpClient httpclient = new DefaultHttpClient();
HttpGet request = new HttpGet(URL);
// add request header
request.addHeader("User-Agent", USER_AGENT);
request.addHeader("Referer", REFERER_URL);
try {
HttpResponse response = httpclient.execute(request);
} catch (Exception e) {
// ...
}
I added "User-Agent" as well, since most sites use that rather than "Referer" to determine if a client is a mobile browser or not.
Note that "Referer" is misspelled; this is intentional in my code. See this link. Guessing it was a typo many years ago and just stuck.
Upvotes: 5