Path: blob/trunk/java/src/org/openqa/selenium/devtools/CdpVersionFinder.java
8276 views
// Licensed to the Software Freedom Conservancy (SFC) under one1// or more contributor license agreements. See the NOTICE file2// distributed with this work for additional information3// regarding copyright ownership. The SFC licenses this file4// to you under the Apache License, Version 2.0 (the5// "License"); you may not use this file except in compliance6// with the License. You may obtain a copy of the License at7//8// http://www.apache.org/licenses/LICENSE-2.09//10// Unless required by applicable law or agreed to in writing,11// software distributed under the License is distributed on an12// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13// KIND, either express or implied. See the License for the14// specific language governing permissions and limitations15// under the License.1617package org.openqa.selenium.devtools;1819import java.util.Collection;20import java.util.Map;21import java.util.Optional;22import java.util.ServiceLoader;23import java.util.Set;24import java.util.logging.Level;25import java.util.logging.Logger;26import java.util.regex.Matcher;27import java.util.regex.Pattern;28import java.util.stream.Collectors;29import java.util.stream.StreamSupport;30import org.openqa.selenium.internal.Require;3132public class CdpVersionFinder {33private static final Logger LOG = Logger.getLogger(CdpVersionFinder.class.getName());34private final int fudgeFactor;35private final Set<CdpInfo> infos;36private static final Pattern MAJOR_VERSION_EXTRACTOR = Pattern.compile(".*/(\\d+)\\..*");37private static final Pattern BROWSER_NAME_VERSION = Pattern.compile("(\\d+)\\..*");3839public CdpVersionFinder() {40this(415,42StreamSupport.stream(43ServiceLoader.load(CdpInfo.class, CdpVersionFinder.class.getClassLoader())44.spliterator(),45false)46.collect(Collectors.toSet()));47}4849public CdpVersionFinder(int versionFudgeFactor, Collection<CdpInfo> infos) {50this.fudgeFactor = Require.nonNegative("Version fudge factor", versionFudgeFactor);5152Require.nonNull("CDP versions", infos);5354this.infos = Set.copyOf(infos);55}5657/**58* Take the output of `/json/version` from a CDP-enabled tool and uses that information to find a59* match.60*/61public Optional<CdpInfo> match(Map<String, Object> versionJson) {62/* The json may look like:63{64"Browser": "Chrome/85.0.4183.69",65"Protocol-Version": "1.3",66"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.69 Safari/537.36",67"V8-Version": "8.5.210.19",68"WebKit-Version": "537.36 (@4554ea1a1171bd8d06951a4b7d9336afe6c59967)",69"webSocketDebuggerUrl": "ws://localhost:9222/devtools/browser/c0ef43a1-7bb0-48e3-9cec-d6bb048cb720"70}7172{73"Browser": "Edg/84.0.522.59",74"Protocol-Version": "1.3",75"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36 Edg/84.0.522.59",76"V8-Version": "8.4.371.23",77"WebKit-Version": "537.36 (@52ea6e40afcc988eef78d29d50f9077893fa1a12)",78"webSocketDebuggerUrl": "ws://localhost:9222/devtools/browser/c7922624-12e8-4301-8b08-fa446944c5cc"79}80*/81Require.nonNull("JSON", versionJson);8283// We are assured by MS and Google that the `Browser` major version84// should match the version of chromium used, so let's grab that.8586Object rawBrowser = versionJson.get("Browser");87if (!(rawBrowser instanceof String)) {88return Optional.empty();89}9091Matcher matcher = MAJOR_VERSION_EXTRACTOR.matcher(rawBrowser.toString());92return fromMatcher(matcher);93}9495/**96* Takes a `browserVersion` from a {@link org.openqa.selenium.Capabilities} instance and returns97* the matching CDP version.98*/99public Optional<CdpInfo> match(String browserVersion) {100Require.nonNull("Browser version", browserVersion);101102Matcher matcher = BROWSER_NAME_VERSION.matcher(browserVersion);103return fromMatcher(matcher);104}105106private Optional<CdpInfo> fromMatcher(Matcher matcher) {107if (matcher.matches()) {108String major = matcher.group(1);109try {110int version = Integer.parseInt(major);111112return findNearestMatch(version);113} catch (NumberFormatException e) {114return Optional.empty();115}116}117118return Optional.empty();119}120121private Optional<CdpInfo> findNearestMatch(int version) {122CdpInfo nearestMatch = null;123124for (CdpInfo info : infos) {125if (info.getMajorVersion() == version) {126LOG.log(Level.FINE, "Found exact CDP implementation for version {0}", version);127return Optional.of(info);128}129130// Never return a higher version131if (info.getMajorVersion() > version) {132continue;133}134135if (version - info.getMajorVersion() < fudgeFactor) {136if (nearestMatch == null || info.getMajorVersion() > nearestMatch.getMajorVersion()) {137nearestMatch = info;138}139}140}141142if (nearestMatch == null) {143LOG.log(Level.WARNING, "Unable to find CDP implementation matching {0}", version);144} else {145LOG.log(146Level.WARNING,147"Unable to find an exact match for CDP version {0}, returning the closest version; "148+ "found: {1}; "149+ "Please update to a Selenium version that supports CDP version {0}",150new Object[] {version, nearestMatch.getMajorVersion()});151}152153return Optional.ofNullable(nearestMatch);154}155}156157158