BrowserDetect.java Source code

Java tutorial

Introduction

Here is the source code for BrowserDetect.java

Source

/*
 * Copyright 2005 Joe Walker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import javax.servlet.http.HttpServletRequest;

/**
 * Various functions to do with working out what is at the other end of the
 * wire, and what it can do.
 * 
 * <h2>Version number documentation</h2>
 * 
 * <h3>Safari</h3>
 * <p>Quick summary:
 * <ul>
 * <li>Jaguar  = 10.2.x  = Safari 1.0.x = WebKit/85
 * <li>Panther = 10.3.0+ = Safari 1.1.x = WebKit/100
 * <li>Panther = 10.3.4+ = Safari 1.2.x = WebKit/125
 * <li>Panther = 10.3.9+ = Safari 1.3.x = WebKit/312
 * <li>Tiger   = 10.4.x  = Safari 2.0.x = WebKit/412-419
 * <li>Tiger   = 10.4.11 = Safari 3.0.x = WebKit/523
 * <li>Leopard = 10.5.x  = Safari 3.0.x = WebKit/523
 * <li>Windows           = Safari 3.0.x = WebKit/523
 * <li>Leopard = 10.5.x  = Safari 3.1.x = WebKit/525-526
 * </ul>
 * 
 * <p>For full information see the Safari and WebKit Version Information:
 * <a href="http://developer.apple.com/internet/safari/uamatrix.html">at Apple
 * Developer Connection</a> and for browsers in general, see this fairly complete
 * <a href="http://www.useragentstring.com/pages/useragentstring.php">list of
 * user agent strings</a>.</p>
 * @author Joe Walker [joe at getahead dot ltd dot uk]
 */
public class BrowserDetect {
    /**
     * How many connections can this browser open simultaneously?
     * @param request The request so we can get at the user-agent header
     * @return The number of connections that we think this browser can take
     */
    public static int getConnectionLimit(HttpServletRequest request) {
        if (atLeast(request, UserAgent.IE, 8)) {
            return 6;
        } else if (atLeast(request, UserAgent.AppleWebKit, 8)) {
            return 4;
        } else if (atLeast(request, UserAgent.Opera, 9)) {
            return 4;
        } else {
            return 2;
        }
    }

    /**
     * Does this web browser support comet?
     * @param request The request so we can get at the user-agent header
     * @return True if long lived HTTP connections are supported
     */
    public static boolean supportsComet(HttpServletRequest request) {
        String userAgent = request.getHeader("user-agent");

        // None of the non-iPhone mobile browsers that I've tested support comet
        if (userAgent.contains("Symbian")) {
            return false;
        }

        // We need to test for other failing browsers here

        return true;
    }

    /**
     * Check that the user-agent string indicates some minimum browser level
     * @param request The browsers request
     * @param requiredUserAgent The UA required
     * @return true iff the browser matches the spec.
     */
    public static boolean atLeast(HttpServletRequest request, UserAgent requiredUserAgent) {
        return atLeast(request, requiredUserAgent, -1);
    }

    /**
     * Check that the user-agent string indicates some minimum browser level
     * @param request The browsers request
     * @param requiredUserAgent The UA required. Currently this is major version only
     * @param requiredVersion The version required, or -1 if versions are not important
     * @return true iff the browser matches the spec.
     */
    public static boolean atLeast(HttpServletRequest request, UserAgent requiredUserAgent, int requiredVersion) {
        String userAgent = request.getHeader("user-agent");
        int realVersion;

        switch (requiredUserAgent) {
        case IE:
            realVersion = getMajorVersionAssumingIE(userAgent);
            break;

        case Gecko:
            realVersion = getMajorVersionAssumingGecko(userAgent);
            break;

        case Opera:
            realVersion = getMajorVersionAssumingOpera(userAgent);
            break;

        case AppleWebKit:
            realVersion = getMajorVersionAssumingAppleWebKit(userAgent);
            break;

        default:
            throw new UnsupportedOperationException("Detection of " + requiredUserAgent + " is not supported yet.");
        }

        return realVersion >= requiredVersion;
    }

    /**
     * Check {@link #atLeast(HttpServletRequest, UserAgent)} for
     * {@link UserAgent#AppleWebKit}
     */
    private static int getMajorVersionAssumingAppleWebKit(String userAgent) {
        int webKitPos = userAgent.indexOf("AppleWebKit");
        if (webKitPos == -1) {
            return -1;
        }

        return parseNumberAtStart(userAgent.substring(webKitPos + 12));
    }

    /**
     * Check {@link #atLeast(HttpServletRequest, UserAgent)} for
     * {@link UserAgent#Opera}
     */
    private static int getMajorVersionAssumingOpera(String userAgent) {
        int operaPos = userAgent.indexOf("Opera");
        if (operaPos == -1) {
            return -1;
        }

        return parseNumberAtStart(userAgent.substring(operaPos + 6));
    }

    /**
     * Check {@link #atLeast(HttpServletRequest, UserAgent)} for
     * {@link UserAgent#Gecko}
     */
    private static int getMajorVersionAssumingGecko(String userAgent) {
        int geckoPos = userAgent.indexOf(" Gecko/20");
        if (geckoPos == -1 || userAgent.contains("WebKit/")) {
            return -1;
        }

        return parseNumberAtStart(userAgent.substring(geckoPos + 7));
    }

    /**
     * Check {@link #atLeast(HttpServletRequest, UserAgent)} for
     * {@link UserAgent#IE}
     */
    private static int getMajorVersionAssumingIE(String userAgent) {
        int msiePos = userAgent.indexOf("MSIE ");
        if (msiePos == -1 || userAgent.contains("Opera")) {
            return -1;
        }

        return parseNumberAtStart(userAgent.substring(msiePos + 5));
    }

    /**
     * We've found the start of a sequence of numbers, what is it as an int?
     */
    private static int parseNumberAtStart(String numberString) {
        if (numberString == null || numberString.length() == 0) {
            return -1;
        }

        int endOfNumbers = 0;
        while (Character.isDigit(numberString.charAt(endOfNumbers))) {
            endOfNumbers++;
        }

        try {
            return Integer.parseInt(numberString.substring(0, endOfNumbers));
        } catch (NumberFormatException ex) {
            return -1;
        }
    }

    /**
     * This method is for debugging only
     */
    public static String getUserAgentDebugString(HttpServletRequest request) {
        String userAgent = request.getHeader("user-agent");

        int version = getMajorVersionAssumingIE(userAgent);
        if (version != -1) {
            return "IE/" + version;
        }

        version = getMajorVersionAssumingGecko(userAgent);
        if (version != -1) {
            return "Gecko/" + version;
        }

        version = getMajorVersionAssumingAppleWebKit(userAgent);
        if (version != -1) {
            return "WebKit/" + version;
        }

        version = getMajorVersionAssumingOpera(userAgent);
        if (version != -1) {
            return "Opera/" + version;
        }

        return "Unknown: (" + userAgent + ")";
    }

}

/*
 * Copyright 2005 Joe Walker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Joe Walker [joe at getahead dot ltd dot uk]
 */
enum UserAgent {
    IE, Opera, Gecko, AppleWebKit,
}