All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.applitools.eyes.UserAgent Maven / Gradle / Ivy

package com.applitools.eyes;

import com.applitools.eyes.exceptions.NotSupportedException;
import com.applitools.utils.ArgumentGuard;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Handles parsing of a user agent string
 */
public class UserAgent {
    private static final String MAJOR_MINOR = "(?[^ .;_)]+)[_.](?[^ .;_)]+)";
    private static final String PRODUCT = "(?:(?%s)/" + MAJOR_MINOR + ")";

    // Browser Regexes
    private static final String[] VALUES_FOR_BROWSER_REGEX_EXCEPT_IE =
            new String[]{"Opera", "Chrome", "Safari", "Firefox", "Edge"};

    private static final Pattern IE_BROWSER_REGEX = Pattern.compile("(?:MS(?IE) " + MAJOR_MINOR + ")");

    private String originalUserAgentString;
    private String OS;
    private String OSMajorVersion;
    private String OSMinorVersion;
    private String Browser;
    private String BrowserMajorVersion;
    private String BrowserMinorVersion;

    private static Pattern[] getBrowserRegexes() {
        Pattern[] browserRegexes = new Pattern[VALUES_FOR_BROWSER_REGEX_EXCEPT_IE.length + 1];

        Pattern currentRegex;
        for (int i = 0; i < VALUES_FOR_BROWSER_REGEX_EXCEPT_IE.length; ++i) {
            String browser = VALUES_FOR_BROWSER_REGEX_EXCEPT_IE[i];
            browserRegexes[i] = Pattern.compile(String.format(PRODUCT, browser));
        }

        // Last pattern is IE
        browserRegexes[browserRegexes.length - 1] = IE_BROWSER_REGEX;

        return browserRegexes;
    }

    private static List> noHeaders = new LinkedList<>();

    private static final Pattern VERSION_REGEX = Pattern.compile(String.format(PRODUCT, "Version"));


    private static Pattern[] OS_REGEXES = new Pattern[]{
            Pattern.compile("(?:(?Windows) NT " + MAJOR_MINOR + ")"),
            Pattern.compile("(?:(?Windows XP))"),
            Pattern.compile("(?:(?Windows 2000))"),
            Pattern.compile("(?:(?Windows NT))"),
            Pattern.compile("(?:(?Windows))"),
            Pattern.compile("(?:(?Mac OS X) " + MAJOR_MINOR + ")"),
            Pattern.compile("(?:(?Android) " + MAJOR_MINOR + ")"),
            Pattern.compile("(?:(?CPU(?: i[a-zA-Z]+)? OS) " + MAJOR_MINOR + ")"),
            Pattern.compile("(?:(?Mac OS X))"),
            Pattern.compile("(?:(?Mac_PowerPC))"),
            Pattern.compile("(?:(?Linux))"),
            Pattern.compile("(?:(?CrOS))"),
            Pattern.compile("(?:(?SymbOS))")
    };

    private static final Pattern HIDDEN_IE_REGEX = Pattern.compile("(?:(?:rv:" + MAJOR_MINOR + "\\) like Gecko))");

    private static final Pattern EDGE_REGEX = Pattern.compile(String.format(PRODUCT, "Edge"));

    /**
     * @param userAgent User agent string to parse
     * @param unknowns  Whether to treat unknown products as {@code UNKNOWN} or throw an exception.
     * @return A representation of the user agent string.
     */
    public static UserAgent ParseUserAgentString(String userAgent, boolean unknowns) {

        if (userAgent == null) return null;

        userAgent = userAgent.trim();
        UserAgent result = new UserAgent();
        result.originalUserAgentString = userAgent;

        // OS
        Map oss = new HashMap<>();
        List matchers = new ArrayList<>();

        for (Pattern osRegex : OS_REGEXES) {
            Matcher matcher = osRegex.matcher(userAgent);
            if (matcher.find()) {
                matchers.add(matcher);
                break;
            }
        }

        for (Matcher m : matchers) {
            String os = m.group("os");
            if (os != null) {
                oss.put(os.toLowerCase(), m);
            }
        }

        Matcher osmatch;
        if (matchers.size() == 0) {
            if (unknowns) {
                result.OS = OSNames.Unknown;
            } else {
                throw new NotSupportedException("Unknown OS: " + userAgent);
            }
        } else {
            if (oss.size() > 1 && oss.containsKey("android")) {
                osmatch = oss.get("android");
            } else {
                osmatch = oss.values().toArray(new Matcher[0])[0];
            }

            result.OS = osmatch.group("os");
            if (osmatch.groupCount() > 1) {
                result.OSMajorVersion = osmatch.group("major");
                result.OSMinorVersion = osmatch.group("minor");
            }
        }

        // OS Normalization
        if (result.OS.startsWith("CPU")) {
            result.OS = OSNames.IOS;
        } else if (result.OS.equals("Windows XP")) {
            result.OS = OSNames.Windows;
            result.OSMajorVersion = "5";
            result.OSMinorVersion = "1";
        } else if (result.OS.equals("Windows 2000")) {
            result.OS = OSNames.Windows;
            result.OSMajorVersion = "5";
            result.OSMinorVersion = "0";
        } else if (result.OS.equals("Windows NT")) {
            result.OS = OSNames.Windows;
            result.OSMajorVersion = "4";
            result.OSMinorVersion = "0";
        } else if (result.OS.equals("Mac_PowerPC") || result.OS.equals("Mac OS X")) {
            result.OS = OSNames.Macintosh;
        } else if (result.OS.equals("CrOS")) {
            result.OS = OSNames.ChromeOS;
        }

        // Browser
        boolean browserOK = false;

        for (Pattern browserRegex : getBrowserRegexes()) {
            Matcher matcher = browserRegex.matcher(userAgent);
            if (matcher.find()) {
                result.Browser = matcher.group("product");
                result.BrowserMajorVersion = matcher.group("major");
                result.BrowserMinorVersion = matcher.group("minor");
                browserOK = true;
                break;
            }
        }

        if (result.OS.equals(OSNames.Windows)) {
            Matcher edgeMatch = EDGE_REGEX.matcher(userAgent);
            if (edgeMatch.find()) {
                result.Browser = BrowserNames.Edge;
                result.BrowserMajorVersion = edgeMatch.group("major");
                result.BrowserMinorVersion = edgeMatch.group("minor");
            }

            // IE11 and later is "hidden" on purpose.
            // http://blogs.msdn.com/b/ieinternals/archive/2013/09/21/
            //   internet-explorer-11-user-agent-string-ua-string-sniffing-
            //   compatibility-with-gecko-webkit.aspx
            Matcher iematch = HIDDEN_IE_REGEX.matcher(userAgent);
            if (iematch.find()) {
                result.Browser = BrowserNames.IE;
                result.BrowserMajorVersion = iematch.group("major");
                result.BrowserMinorVersion = iematch.group("minor");

                browserOK = true;
            }
        }

        if (!browserOK) {
            if (unknowns) {
                result.Browser = "Unknown";
            } else {
                throw new NotSupportedException("Unknown browser: " + userAgent);
            }
        }

        // Explicit browser version (if available)
        Matcher versionMatch = VERSION_REGEX.matcher(userAgent);
        if (versionMatch.find()) {
            result.BrowserMajorVersion = versionMatch.group("major");
            result.BrowserMinorVersion = versionMatch.group("minor");
        }

        return result;
    }

    public String getBrowser() {
        return Browser;
    }

    public String getBrowserMajorVersion() {
        return BrowserMajorVersion;
    }

    public String getBrowserMinorVersion() {
        return BrowserMinorVersion;
    }

    public String getOS() {
        return OS;
    }

    public String getOSMajorVersion() {
        return OSMajorVersion;
    }

    public String getOSMinorVersion() {
        return OSMinorVersion;
    }

    public String getOriginalUserAgentString() {
        return originalUserAgentString;
    }

    @Override
    public String toString() {
        return String.format("%s %s.%s / %s %s.%s", OS, OSMajorVersion, OSMinorVersion, Browser, BrowserMajorVersion, BrowserMinorVersion);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy