Android - Webview only applying headers to initial request - android

I'm writing an android app that uses webview to request content from a web server, but using mWebView.loadUrl(url1, headers); will only apply the headers to the initial request and not the resources in the request.
Any idea as so how to apply the headers to the resource requests as well?

Not absolutely sure but you can try to override shouldOverrideUrlLoading(WebView view, String url) method and handle all redirects by starting mWebView.loadUrl(url, yourHeaders);
Dont forget to return true in that overriden method.

First of all, let me say that i can't believe that webview sucks so much.
This is what i did to pass custom headers
public class CustomWebview extends WebView {
public void loadWithHeaders(String url) {
setWebViewClient(new WebViewClient() {
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
//makes a custom http request, which allows you to add your own headers
return customRequest(url);
}
});
loadUrl(url);
}
/**
* Custom http request with headers
* #param url
* #return
*/
private WebResourceResponse customRequest(String url) {
try {
OkHttpClient httpClient = new OkHttpClient();
Request request = new Request.Builder()
.url(url.trim())
.addHeader("Header-Name", "Android Sucks")
.build();
Response response = httpClient.newCall(request).execute();
return new WebResourceResponse(
"text/html", // You can set something other as default content-type
"utf-8", // Again, you can set another encoding as default
response.body().byteStream()
);
} catch (IOException e) {
//return null to tell WebView we failed to fetch it WebView should try again.
return null;
}
}
}

Related

How to play a video in webview from a link which needs authentication?

We have some videos hosted in our platform. Let's say mydomain.com/no_auth_video_1 and mydomain.com/no_auth_video_2, for instance. Now we added a third video mydomain.com/auth_video_3, but this one can only be seen if you add some authentication headers to the request.
In our android app, we use a WebView to play these videos. We have this html template:
<!-- html stuf -->
<video>
<source src="%videoUrl%"/>
</video>
<!-- html stuf -->
and once replaced the url, we load the html on the webview with:
webView.loadData(html, "text/html", "utf-8")
This works great for the no_auth videos, but not for the video which needs the authentication. Looking for some answers, I found that we should override the shouldInterceptRequest method on the WebViewClient:
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
String url = request.getUrl().toString();
if (urlShouldBeHandledByWebView(url)) {
return super.shouldInterceptRequest(view, url);
}
return getNewResponse(view, url);
}
private WebResourceResponse getNewResponse(WebView view, String url) {
try {
OkHttpClient okHttpClient = getMyAuthenticatedHTTPClient()
Request request = new Request.Builder()
.url(url)
.build();
final Response response = okHttpClient.newCall(request).execute();
return new WebResourceResponse(
response.header("content-type", null),
response.header("content-encoding", "utf-8"),
response.body().byteStream()
);
} catch (Exception e) {
return null;
}
}
This works intended since the query for mydomain.com/auth_video_3 is executed, and I can see that the info is retrieved properly with the debugger. Problem is that in the WebView the video isn't loading anyway.

Android WebView sometimes doesn't send request headers on initial page load

I have a webview activity that loads a URL with a few custom request headers in its onCreate() method. The requirement is to pass the custom headers with the initial URL request. On a few devices, the webview stops sending the headers after the webview activity has been launched a few times.
For example, I have a HomeActivity which launches a WebViewActivity. After launching the WebViewActivity and navigating back to HomeActivity a few times, the WebViewActivity stops sending the custom request headers and this behaviour doesn't change unless I clear the application's data.
I have confirmed this behaviour using a MITM tool. The implementation is as follows:
#Override
protected void onCreate(Bundle savedInstanceState) {
Map<String, String> map = new HashMap<>();
map.put("header1", "header1_value");
map.put("header2", "header2_value");
map.put("header3", "header3_value");
map.put("header4", "header4_value");
webView.loadUrl("https://www.example.com/mypath", map);
}
The above snippet executes unconditionally on every activity launch. However, the headers are not present in the actual request made by the webview. Also, the page being requested is a 303 redirect.
If your minimum API target is level 21, you can use the shouldInterceptRequest else you can use this
With each interception, you will need to take the url, make this request yourself, and return the content stream:
Then:
WebViewClient wvc = new WebViewClient() {
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
try {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("header1", "header1_value");
httpGet.setHeader("header2", "header2_value");
httpGet.setHeader("header3", "header3_value");
httpGet.setHeader("header4", "header4_value");
HttpResponse httpReponse = client.execute(httpGet);
Header contentType = httpReponse.getEntity().getContentType();
Header encoding = httpReponse.getEntity().getContentEncoding();
InputStream responseInputStream = httpReponse.getEntity().getContent();
String contentTypeValue = null;
String encodingValue = null;
if (contentType != null) {
contentTypeValue = contentType.getValue();
}
if (encoding != null) {
encodingValue = encoding.getValue();
}
return new WebResourceResponse(contentTypeValue, encodingValue, responseInputStream);
} catch (ClientProtocolException e) {
//return null to tell WebView we failed to fetch it WebView should try again.
return null;
} catch (IOException e) {
//return null to tell WebView we failed to fetch it WebView should try again.
return null;
}
}
}
//Where wv is your webview
wv.setWebViewClient(wvc);
Based on this question

Getting around X-Frame-Options DENY in an Android WebView

I am attempting to implement a technique similar to the one describe in this question.
I have an android application (Ionic built on top of Cordova) that runs in a webview. Basically what I want to do is load a page into an iframe and perform some work on this page. Many website uses the X-Frame-Options: DENY header to disallow their content from being loaded in an iFrame. In a chrome extension you can get around this by intercepting the webrequest and removing that header.
I've overridden the shouldInterceptRequest function here: https://developer.android.com/reference/android/webkit/WebViewClient.html
// Handle API until level 21
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
try {
WebResourceResponse cordovaResponse = super.shouldInterceptRequest(view, request);
if(cordovaResponse != null) {
return cordovaResponse;
}
String url = request.getUrl().toString();
HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.connect();
//view.loadUrl(url, getCustomHeaders());
WebResourceResponse response = new WebResourceResponse(urlConnection.getContentType(),
urlConnection.getContentEncoding(),
urlConnection.getInputStream());
Map<String, String> headers = response.getResponseHeaders();
if(headers != null){
response.setResponseHeaders(removeXOriginHeaders(headers));
}
return response;
} catch(MalformedURLException e) {
e.printStackTrace();
return null;
}
catch (IOException e) {
e.printStackTrace();
return null;
}
}`
but when the headers for all requests are received using the above method they are null and when the content is put into the iframe, it doesn't result in a fully formed Document.
The chrome debugger provides this message: Resource interpreted as Document but transferred with MIME type text/html;charset=UTF-8:
It's like the page content is fetched using xhr and then stuck inside a single element of the Document as opposed to loading as it normally would when using an iframe (all scripts run to execution, subsequent ajax requests fired etc).
Is there anyway to get the page content to load in the iframe after having removed that single header?
I was able to solve my problem by using the OkHttpClient found here: http://square.github.io/okhttp/ instead of the java URLConnection
// Handle API until level 21
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
try {
WebResourceResponse cordovaResponse = super.shouldInterceptRequest(view, request);
if(cordovaResponse != null) {
return cordovaResponse;
}
String url = request.getUrl().toString();
OkHttpClient httpClient = new OkHttpClient();
Request okRequest = new Request.Builder()
.url(url)
.build();
Response response = httpClient.newCall(okRequest).execute();
Response modifiedResponse = response.newBuilder()
.removeHeader("x-frame-options")
.removeHeader("frame-options")
.build();
return new WebResourceResponse("text/html",
modifiedResponse.header("content-encoding", "utf-8"),
modifiedResponse.body().byteStream()
);
} catch(MalformedURLException e) {
e.printStackTrace();
return null;
}
catch (IOException e) {
e.printStackTrace();
return null;
}
}

Get the link redirected from webview android

I am trying to implement a payment gateway in android, and the payment processor requires sending some parameters when the "Pay" button is clicked. The sample link is:
https://vpay.com/?p=linkToken&v_merchant_id=qa331322179752&merchant_ref=234-567-890&memo=Bulk+order+from+McAckney+Web+Shop&total=13000&
notify_url=http%3A%2F%2Fwww.example.com%2Fnotification.php&
success_url=http%3A%2F%2Fwww.example.com%2Fthank_you.html&fail_url=http%3A%2F%2Fwww.example.com%2Ffailed.html
Now if the parameters are inputted correctly, the link returns another link in the format: https://vpay.com/pay/bnlink/xxxxxxxx-x0 which when visited brings up VPay payment page that can be used for payment based on the parameters supplied.
The payment processor should have employed an automatic redirection when the new link is generated, instead, it just displays the new link and stays there. Is there a way to get this new "RETURNED" link and then visit it so users can input the payment info.
Thank you!
Following method of Webview will work if you are using your own webview in activity or fragment for the payment stuff. below is the piece of code which will help:
webview.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Log.i(TAG, "Processing webview url click...");
view.loadUrl(url);
Log.v(TAG,"html content of url:"+ getHtml(String url) );
return true;
}
public void onPageFinished(WebView view, String url) {
Log.i(TAG, "Finished loading URL: " +url);
}
});
in shouldOverrideUrlLoading method you will add your condition according to the url whether to load this url in webview or not.
And to get html content of the url use below Method:
public String getHtml(String url) {
HttpClient vClient = new DefaultHttpClient();
HttpGet vGet = new HttpGet(url);
String response = "";
try {
ResponseHandler<String> vHandler = new BasicResponseHandler();
response = vClient.execute(vGet, vHandler);
} catch (Exception e) {
e.printStackTrace();
}
return response;
}

CORS with Crosswalk and OKHttp

I'm trying to use a crosswalk embedded webview to display a web page, with some javascript. Because I need to add some headers to each request, I am intercepting the request with shouldInterceptLoadRequest, and making the request with OkHttp.
#Override
public WebResourceResponse shouldInterceptLoadRequest(XWalkView view, String url) {
try {
Log.i(App.TAG, url);
return new WebResourceResponse("", "UTF-8", getUrl(url));
} catch (Exception e) {
e.printStackTrace();
return super.shouldInterceptLoadRequest(view, url);
}
}
InputStream getUrl(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.addHeader("MyHeader","MyHeaderValue")
.build();
Response response = client.newCall(request).execute();
return response.body().byteStream();
}
This code works as intended at first, but upon making an Ajax request, I get this error : [INFO:CONSOLE(0)] "XMLHttpRequest cannot load https://api.example1.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://example2.com' is therefore not allowed access."
I do not get this error if I don't intercept the request, but then I loose the ability to add headers to the request.

Categories

Resources