Question

I'm trying to get the favicon of the url the user enters, for example

_url = "google.com";

I use HttpUrlConnection to get the Bitmap of the favicon from the /favicon.ico extension from the host url.

        String faviconString = Uri.parse(_url).getHost() + "/favicon.ico";
        URL faviconUrl = null;
        Bitmap favicon = null;
        try
        {
            faviconString = "http://" + faviconString;
            faviconUrl = new URL(faviconString);
            HttpURLConnection connection = (HttpURLConnection) faviconUrl.openConnection();
            connection.setDoInput(true);
            connection.connect();
            favicon = BitmapFactory.decodeStream(connection.getInputStream());
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        return favicon;

However, since the user probably won't specify http:// or https://, I would have to add it myself. The problem I'm having is that, if I add http:// in front of the url, everything would work fine, but for https://, some sites would return the favicon, others would just give me null. How do I find out which page uses https? Should I just add http:// for every case? Are there any websites that restricts to strictly https and would return null for using http?

Was it helpful?

Solution

Unless you use user2558882's idea or there is some other tool out in the wild that will just get a websites favicon for you, you're going to have to check both the http and https urls. There is no other way to do this. It is part of the difficulty of using the web.

Perhaps looking at your code differently and breaking down what you're trying to do into smaller more manageable parts would be a bit better?

public void getFavicon(String host) {

    URL httpUrl = this.getHttpUrl(host + "/favicon.ico");

    Bitmap favicon = this.getBitmap(httpUrl);

    if (favicon == null) {

        URL httpsUrl = this.getHttpsUrl(host + "/favicon.ico");

        favicon = this.getBitmap(httpsUrl);
    }

    if (favicon == null) {

        throw new FaviconMissingException("Unable to find favicon for host: " + host);
    }

    return favicon;
}

public URL getHttpUrl(String uri) throws MalformedURLException {

    // There are better ways of building a url then string concationation.
    return new URL("http://" + uri);
}

public URL getHttpsUrl(String uri) throws MalformedURLException {

    // There are better ways of building a url then string concationation.
    return new URL("https://" + uri);
}

public Bitmap getBitmap(URL url) {

    InputStream inputStream = getInputStream(url);

    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);

    return bitmap
}

public InputStream getInputStream(URL url) {

    // Please use a real connection library like HTTPClient here!
    // HttpClient will handle timeouts, redirects, and things like that for you.
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setDoInput(true);
    connection.connect();

    return connection.getInputStream();
}

BTW, being concerned about one or two connections takes more time then writing the code to make two requests. I almost guarantee that google is making two requests as needed. And if it is good enough for google it is good enough for me.

Finally, if you start to see that making two requests is really taking too much time, then do something about improving the performance.

OTHER TIPS

Note: I am not sure how helpful my answer would be.

You can grab the favicon using google:

http://www.google.com/s2/favicons?domain=stackoverflow.com

returns:

enter image description here

You don't have to specify http or https.

 http://www.google.com/s2/favicons?domain=my.yorku.ca ===>> (https://my.yorku.ca)

returns:

enter image description here

But this is not the actual favicon that https://my.yorku.ca uses. So, I guess google returns a default one for sites that do not provide access their favicons.

InputStream is = null;

String urlPrefix = "http://www.google.com/s2/favicons?domain=";

String _url = "google.com";

Bitmap favicon = null;

try {

    is = (InputStream) new URL(urlPrefix + _url).getContent();

} catch (MalformedURLException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

favicon = BitmapFactory.decodeStream(is);

You can actually keep a copy of the default favicon and check if:

if (defaultBitmap.sameAs(favicon)) {
    // favicon wasn't available
}
            URL url = new URL(downloadURL);
            HttpURLConnection urlCon = null;

            URL testUrlHttps = new URL(downloadURL);
            if (testUrlHttps.getProtocol().toLowerCase().equals("https"))
            {
                trustAllHosts();
                HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
                https.setHostnameVerifier(DO_NOT_VERYFY);
                urlCon = https;
            } else
            {
                urlCon = (HttpURLConnection) url.openConnection();
            }




add this method. May be it will help



   private static void trustAllHosts()
    {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()
        {
            public java.security.cert.X509Certificate[] getAcceptedIssuers()
            {
                return new java.security.cert.X509Certificate[] {};
            }

            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
            {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
            {
            }
        } };

        // Install the all-trusting trust manager
        try
        {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

How about checking if the website returns null or a favicon?

I hope this helps you

Another answer that is even 'easier'.

Just make the user enter the url (including protocol) for their favicon and validate that url returns a favicon. If not then display a validation error back to the end user.

Following agile principals, do the least amount of work and see what works. If the one plan doesn't work, then try something different.

Try this when URL start with "https":

              TrustManager[] trustAllCerts = new TrustManager[]
               {
                 new X509TrustManager()
                  {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers()  { return null; }
                    public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType)  {}
                    public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType)  {}
                  }
                 };
              try
                {
                  SSLContext sc = SSLContext.getInstance( "SSL"); // "TLS" "SSL"
                  sc.init( null, trustAllCerts, null);
                  HttpsURLConnection.setDefaultSSLSocketFactory( sc.getSocketFactory());
                  HttpsURLConnection.setDefaultHostnameVerifier( 
                   new HostnameVerifier() 
                    {
                      public boolean verify( String hostname, SSLSession session) { return true; }
                    } );
                }
               catch( Exception e)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top