25

Does Android allow native apps to disable CORS security policies for http:// (not local/file) requests?

In my native app, a webview shows a remote html via http://, not on the local/file system. This seems to be CORS-restricted in the same way as within webbrowsers.

Worakround: A native-js bridge for ajax requests to cross-domains which do not have Access-Control-Allow-Origin: * is my quick'n'dirt solution. (jsonp or server-side proxy is not an option because cookie+ip of client are checked by the webservice.)

Can this policy be disabled for inapp webviews?

Please let me know, if there is a simple flag for allowing js to bypass this restriction which limits the "native" app's webview.

ledy
  • 1,527
  • 6
  • 22
  • 33

3 Answers3

17

This is now possible as of Android API level 21. You can create an OPTIONS response like so:

public class OptionsAllowResponse {
    static final SimpleDateFormat formatter = new SimpleDateFormat("E, dd MMM yyyy kk:mm:ss", Locale.US);

    @TargetApi(21)
    static WebResourceResponse build() {
        Date date = new Date();
        final String dateString = formatter.format(date);

        Map<String, String> headers = new HashMap<String, String>() {{
            put("Connection", "close");
            put("Content-Type", "text/plain");
            put("Date", dateString + " GMT");
            put("Access-Control-Allow-Origin", /* your domain here */);
            put("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS");
            put("Access-Control-Max-Age", "600");
            put("Access-Control-Allow-Credentials", "true");
            put("Access-Control-Allow-Headers", "accept, authorization, Content-Type");
            put("Via", "1.1 vegur");
        }};

        return new WebResourceResponse("text/plain", "UTF-8", 200, "OK", headers, null);
    }
}

and then call it from your WebViewClient implementation as follows:

    @Override
    @TargetApi(21)
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        if (request.getMethod().equalsIgnoreCase("OPTIONS")) {
            return OptionsAllowResponse.build();
        }

        return null;
    }

This only works from API level 21, since the OPTIONS response requires inspecting the requested HTTP method from the WebResourceRequest, which is only available since API 21.

davidgoli
  • 2,436
  • 1
  • 16
  • 13
  • 3
    I don't see how this disables CORS, it just intercepts the request and return what you want, but not the actual request data. – jcesarmobile Apr 30 '18 at 15:28
  • 4
    You're correct that it doesn't directly handle the request data for the GET/PUT/POST request, but CORS involves *two* requests: the first one is an HTTP OPTIONS request with no request data that checks to see if the GET/PUT/POST can go through, and if so, the WebView will proceed to make the actual request with the data. This code overrides the response for that first OPTIONS request so that the second request will go through. – davidgoli May 01 '18 at 16:45
  • how do you make the requests from javascript? In my tests I never got the OPTIONS request, just the actual request that failed, so I ended using a `HttpURLConnection` to get the file data and return it in the `WebResourceResponse` – jcesarmobile May 01 '18 at 17:03
  • In Javascript you just make requests as normal eg. through XMLHttpRequest or fetch or whatever. The Java here is implemented in the `WebViewClient` class that is assigned to the `WebView` in which your Javascript is running. I'm not sure what your setup is or that you are experiencing CORS issues, but you should read https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS to understand the CORS protocol. – davidgoli May 01 '18 at 22:31
  • @davidgoli Any idea how to overcome this frm REACT-NATIVE, when I am using a POST request? Please see https://stackoverflow.com/questions/52178543/invalid-cors-request-error-in-webview-used-in-react-native – Yossi Sep 06 '18 at 05:51
  • Sorry to revive an old thread, I've just tried this, however fetch requests in JS are still returning failed CORS. I have set breakpoints and ensured `build()` is being called and is returning correctly. – Bea Boxler Aug 01 '19 at 15:31
  • @BenBoxler , I guess that you may send the OPTIONS request to the incorrect domain, you can refer for the example raised in [CORS wiki](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) . – wkm Aug 09 '19 at 08:49
  • @davidgoli you should know that CORS requires you to add headers on the actual response as well not only on the OPTIONS request so your method is not working because you only handle the OPTIONS request. On the actual response you only need to add the `Access-Control-Allow-Origin` but without that the request fails. Check [0] and read the http response below this line `Once the preflight request is complete, the real request is sent:` [0]https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS – Mihai Dec 01 '20 at 04:17
  • never see an OPTIONS request when using – Yeung Dec 16 '21 at 09:23
  • This is not working because subsequent requests after OPTIONS will fail since they will not have proper headers. To solve this you need to make your own request and override the response headers but from `shouldInterceptRequest` you can't get POST payload, so it will not work in all situations. – Alex Titarenko Jan 26 '23 at 06:12
12

AFAIK this is not possible, and believe me, I've tried many ways.

The best you can do is override resource loading. See Intercept and override HTTP-requests from WebView

Community
  • 1
  • 1
Marco Martinelli
  • 892
  • 2
  • 14
  • 27
  • Sorry for asking again. This can't be "fixed" by shouldInterceptRequest since api 11 by manipulating the header response to be CORS-accepted always? – ledy Jun 24 '13 at 11:38
  • It *is* possible, see my answer below. – davidgoli May 01 '18 at 22:31
  • @MarcoMartinelli Any idea how to overcome this frm REACT-NATIVE, when I am using a POST request? Please see https://stackoverflow.com/questions/52178543/invalid-cors-request-error-in-webview-used-in-react-native – Yossi Sep 06 '18 at 05:54
0

A shorter version that helped me using c# with Xamarin is the following:

    public override WebResourceResponse ShouldInterceptRequest(WebView view, IWebResourceRequest request)
    {
        if (request.Url.SchemeSpecificPart.StartsWith("//<domain>/"))
        {
            request.RequestHeaders.Add("Access-Control-Allow-Origin", "*");
        }

        return base.ShouldInterceptRequest(view, request);
    }

This override is done for Android.Webkit.WebViewClient, where <domain> is the one that is blocked by CORS policy.

Ollie
  • 23
  • 1