Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/java/src/org/openqa/selenium/devtools/CdpVersionFinder.java
8276 views
1
// Licensed to the Software Freedom Conservancy (SFC) under one
2
// or more contributor license agreements. See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership. The SFC licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License. You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied. See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
package org.openqa.selenium.devtools;
19
20
import java.util.Collection;
21
import java.util.Map;
22
import java.util.Optional;
23
import java.util.ServiceLoader;
24
import java.util.Set;
25
import java.util.logging.Level;
26
import java.util.logging.Logger;
27
import java.util.regex.Matcher;
28
import java.util.regex.Pattern;
29
import java.util.stream.Collectors;
30
import java.util.stream.StreamSupport;
31
import org.openqa.selenium.internal.Require;
32
33
public class CdpVersionFinder {
34
private static final Logger LOG = Logger.getLogger(CdpVersionFinder.class.getName());
35
private final int fudgeFactor;
36
private final Set<CdpInfo> infos;
37
private static final Pattern MAJOR_VERSION_EXTRACTOR = Pattern.compile(".*/(\\d+)\\..*");
38
private static final Pattern BROWSER_NAME_VERSION = Pattern.compile("(\\d+)\\..*");
39
40
public CdpVersionFinder() {
41
this(
42
5,
43
StreamSupport.stream(
44
ServiceLoader.load(CdpInfo.class, CdpVersionFinder.class.getClassLoader())
45
.spliterator(),
46
false)
47
.collect(Collectors.toSet()));
48
}
49
50
public CdpVersionFinder(int versionFudgeFactor, Collection<CdpInfo> infos) {
51
this.fudgeFactor = Require.nonNegative("Version fudge factor", versionFudgeFactor);
52
53
Require.nonNull("CDP versions", infos);
54
55
this.infos = Set.copyOf(infos);
56
}
57
58
/**
59
* Take the output of `/json/version` from a CDP-enabled tool and uses that information to find a
60
* match.
61
*/
62
public Optional<CdpInfo> match(Map<String, Object> versionJson) {
63
/* The json may look like:
64
{
65
"Browser": "Chrome/85.0.4183.69",
66
"Protocol-Version": "1.3",
67
"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",
68
"V8-Version": "8.5.210.19",
69
"WebKit-Version": "537.36 (@4554ea1a1171bd8d06951a4b7d9336afe6c59967)",
70
"webSocketDebuggerUrl": "ws://localhost:9222/devtools/browser/c0ef43a1-7bb0-48e3-9cec-d6bb048cb720"
71
}
72
73
{
74
"Browser": "Edg/84.0.522.59",
75
"Protocol-Version": "1.3",
76
"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",
77
"V8-Version": "8.4.371.23",
78
"WebKit-Version": "537.36 (@52ea6e40afcc988eef78d29d50f9077893fa1a12)",
79
"webSocketDebuggerUrl": "ws://localhost:9222/devtools/browser/c7922624-12e8-4301-8b08-fa446944c5cc"
80
}
81
*/
82
Require.nonNull("JSON", versionJson);
83
84
// We are assured by MS and Google that the `Browser` major version
85
// should match the version of chromium used, so let's grab that.
86
87
Object rawBrowser = versionJson.get("Browser");
88
if (!(rawBrowser instanceof String)) {
89
return Optional.empty();
90
}
91
92
Matcher matcher = MAJOR_VERSION_EXTRACTOR.matcher(rawBrowser.toString());
93
return fromMatcher(matcher);
94
}
95
96
/**
97
* Takes a `browserVersion` from a {@link org.openqa.selenium.Capabilities} instance and returns
98
* the matching CDP version.
99
*/
100
public Optional<CdpInfo> match(String browserVersion) {
101
Require.nonNull("Browser version", browserVersion);
102
103
Matcher matcher = BROWSER_NAME_VERSION.matcher(browserVersion);
104
return fromMatcher(matcher);
105
}
106
107
private Optional<CdpInfo> fromMatcher(Matcher matcher) {
108
if (matcher.matches()) {
109
String major = matcher.group(1);
110
try {
111
int version = Integer.parseInt(major);
112
113
return findNearestMatch(version);
114
} catch (NumberFormatException e) {
115
return Optional.empty();
116
}
117
}
118
119
return Optional.empty();
120
}
121
122
private Optional<CdpInfo> findNearestMatch(int version) {
123
CdpInfo nearestMatch = null;
124
125
for (CdpInfo info : infos) {
126
if (info.getMajorVersion() == version) {
127
LOG.log(Level.FINE, "Found exact CDP implementation for version {0}", version);
128
return Optional.of(info);
129
}
130
131
// Never return a higher version
132
if (info.getMajorVersion() > version) {
133
continue;
134
}
135
136
if (version - info.getMajorVersion() < fudgeFactor) {
137
if (nearestMatch == null || info.getMajorVersion() > nearestMatch.getMajorVersion()) {
138
nearestMatch = info;
139
}
140
}
141
}
142
143
if (nearestMatch == null) {
144
LOG.log(Level.WARNING, "Unable to find CDP implementation matching {0}", version);
145
} else {
146
LOG.log(
147
Level.WARNING,
148
"Unable to find an exact match for CDP version {0}, returning the closest version; "
149
+ "found: {1}; "
150
+ "Please update to a Selenium version that supports CDP version {0}",
151
new Object[] {version, nearestMatch.getMajorVersion()});
152
}
153
154
return Optional.ofNullable(nearestMatch);
155
}
156
}
157
158