Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What to do with an IOException in WebViewClient.shouldInterceptRequest()

I am trying to intercept requests from a WebView so that I can inject extra headers. I am applying a WebViewClient to the WebView and overriding shouldInterceptRequest().

In shouldInterceptRequest() I open the connection, add the headers, and then return the opened stream in a WebResourceResponse.

It is not clear to me how an IOException should be handled if the initial opening of the connection fails.

final Map<String, String> extraHeaders = getExtraHeaders(intent);
webview.setWebViewClient(new WebViewClient() {
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        final Uri uri = request.getUrl();

        try {
            URL           url = new URL(uri.toString());
            URLConnection con = url.openConnection();
            for (Map.Entry<String, String> h : extraHeaders.entrySet()) {
                con.addRequestProperty(h.getKey(), h.getValue());
            }
            final String contentType = con.getContentType().split(";")[0];
            final String encoding    = con.getContentEncoding();
            return new WebResourceResponse(contentType, encoding, con.getInputStream());
        } catch (IOException e) {
            // what should we do now?
            e.printStackTrace();
        }

        return super.shouldInterceptRequest(view, request);
    }
});

I can't leave it uncaught, as it's a checked exception and is not part of the shouldInterceptRequest() signature.

I can't wrap it in an unchecked exception, as that then goes uncaught by the WebView and kills the app.

If I catch and ignore the exception, and default to the super method (which just returns null), then the WebView will continue with its default behaviour and attempt to send the request (without my extra headers). This is not desirable, as the WebView's own connection attempt may actually succeed, and the missing headers will cause more problems further down the line.

There seems to be no way to indicate that the intercept has failed and the request should be aborted.

What's the best thing to do here?


I have tried to return a mock failure response, but this is not treated as an error. The WebView shows a page with the content of the response (the error message from the exception) and the WebViewClient's onReceivedError() or onReceivedHttpError() callbacks are not called.

} catch (IOException e) {
    InputStream is = new ByteArrayInputStream(e.getMessage().getBytes());
    return new WebResourceResponse("text/plain", "UTF-8", 500, "Intercept failed",
                                   Collections.<String, String>emptyMap(),
                                   is);
}
like image 934
Graham Borland Avatar asked Nov 21 '22 17:11

Graham Borland


1 Answers

You could try to instantiate a new WebResourceError and then call WebViewClient.onReceivedError. Never tried such a thing, but this is how it would look like:

} catch (final IOException e) {
    WebResourceError wre = new WebResourceError(){
        @Override
        public CharSequence getDescription (){
            return e.toString(); 
        }

        @Override
        public int getErrorCode (){
            return WebViewClient.ERROR_CONNECT;
        }
    };

    onReceivedError(view, request, wre);

    return true;
}

There's also a deprecated version of onReceivedError you could use if you don't want or can't instantiate a WebResourceError.

like image 54
Mister Smith Avatar answered Dec 11 '22 06:12

Mister Smith