Skip to content

Commit f948e6d

Browse files
committed
The W3C spec is pretty clear about what's allowed in new session
To be exact, only things that look like they're peotocol extensions and the handful of allowed tags are to be allowed into the firstMatch and anyMatch parameters.
1 parent 8fde866 commit f948e6d

File tree

2 files changed

+69
-8
lines changed

2 files changed

+69
-8
lines changed

java/client/src/org/openqa/selenium/remote/ProtocolHandshake.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@
5656
import java.util.Map;
5757
import java.util.Optional;
5858
import java.util.Set;
59+
import java.util.function.Predicate;
5960
import java.util.logging.Level;
6061
import java.util.logging.Logger;
62+
import java.util.regex.Pattern;
6163
import java.util.stream.Collector;
6264
import java.util.stream.Collectors;
6365
import java.util.stream.Stream;
@@ -67,13 +69,22 @@ public class ProtocolHandshake {
6769
private final static Logger LOG = Logger.getLogger(ProtocolHandshake.class.getName());
6870

6971
/**
70-
* Capability names that should never be sent across the wire to a w3c compliant remote end.
72+
* Patterns that are acceptable to send to a w3c remote end.
7173
*/
72-
private final Set<String> UNUSED_W3C_NAMES = ImmutableSet.<String>builder()
73-
.add("firefox_binary")
74-
.add("firefox_profile")
75-
.add("marionette")
76-
.build();
74+
private final Predicate<String> ACCEPTED_W3C_PATTERNS = Stream.of(
75+
"^[\\w-]+:.*$",
76+
"^acceptInsecureCerts$",
77+
"^browserName$",
78+
"^browserVersion$",
79+
"^platformName$",
80+
"^pageLoadStrategy$",
81+
"^proxy$",
82+
"^setWindowRect$",
83+
"^timeouts$",
84+
"^unhandledPromptBehavior$")
85+
.map(Pattern::compile)
86+
.map(Pattern::asPredicate)
87+
.reduce(identity -> false, Predicate::or);
7788

7889
public Result createSession(HttpClient client, Command command)
7990
throws IOException {
@@ -246,7 +257,7 @@ private void streamW3CProtocolParameters(
246257
.flatMap(Collection::stream)
247258
.filter(entry -> !excludedKeys.contains(entry.getKey()))
248259
.filter(entry -> entry.getValue() != null)
249-
.filter(entry -> !UNUSED_W3C_NAMES.contains(entry.getKey())) // We never want to send this
260+
.filter(entry -> ACCEPTED_W3C_PATTERNS.test(entry.getKey()))
250261
.distinct()
251262
.collect(Collector.of(
252263
JsonObject::new,
@@ -264,7 +275,7 @@ private void streamW3CProtocolParameters(
264275
.map(map -> {
265276
JsonObject json = new JsonObject();
266277
for (Map.Entry<String, ?> entry : map.entrySet()) {
267-
if (!UNUSED_W3C_NAMES.contains(entry.getKey())) {
278+
if (ACCEPTED_W3C_PATTERNS.test(entry.getKey())) {
268279
json.add(entry.getKey(), gson.toJsonTree(entry.getValue()));
269280
}
270281
}

java/client/test/org/openqa/selenium/remote/ProtocolHandshakeTest.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static java.net.HttpURLConnection.HTTP_OK;
2121
import static java.nio.charset.StandardCharsets.UTF_8;
2222
import static org.junit.Assert.assertEquals;
23+
import static org.junit.Assert.assertFalse;
2324
import static org.junit.Assert.assertTrue;
2425

2526
import com.google.common.collect.ImmutableList;
@@ -33,9 +34,15 @@
3334
import org.openqa.selenium.remote.http.HttpClient;
3435
import org.openqa.selenium.remote.http.HttpRequest;
3536
import org.openqa.selenium.remote.http.HttpResponse;
37+
import org.openqa.selenium.remote.http.W3CHttpCommandCodec;
3638

3739
import java.io.IOException;
40+
import java.util.Collection;
41+
import java.util.HashSet;
42+
import java.util.List;
3843
import java.util.Map;
44+
import java.util.Set;
45+
import java.util.stream.Collectors;
3946

4047
@SuppressWarnings("unchecked")
4148
@RunWith(JUnit4.class)
@@ -187,6 +194,49 @@ public void shouldAddBothGeckoDriverAndW3CCapabilitiesToRootCapabilitiesProperty
187194
assertTrue(capabilities.containsKey("firstMatch"));
188195
}
189196

197+
@Test
198+
public void shouldNotIncludeNonProtocolExtensionKeys() throws IOException {
199+
DesiredCapabilities caps = new DesiredCapabilities();
200+
caps.setCapability("se:option", "cheese");
201+
caps.setCapability("option", "I like sausages");
202+
caps.setCapability("browserName", "amazing cake browser");
203+
204+
Map<String, Object> params = ImmutableMap.of("desiredCapabilities", caps);
205+
Command command = new Command(null, DriverCommand.NEW_SESSION, params);
206+
207+
HttpResponse response = new HttpResponse();
208+
response.setStatus(HTTP_OK);
209+
response.setContent(
210+
"{\"sessionId\": \"23456789\", \"status\": 0, \"value\": {}}".getBytes(UTF_8));
211+
RecordingHttpClient client = new RecordingHttpClient(response);
212+
213+
new ProtocolHandshake().createSession(client, command);
214+
215+
HttpRequest request = client.getRequest();
216+
Map<String, Object> handshakeRequest = new Gson().fromJson(
217+
request.getContentString(),
218+
new TypeToken<Map<String, Object>>() {}.getType());
219+
220+
Object rawCaps = handshakeRequest.get("capabilities");
221+
assertTrue(rawCaps instanceof Map);
222+
223+
Map<?, ?> capabilities = (Map<?, ?>) rawCaps;
224+
225+
Map<?, ?> always = (Map<?, ?>) capabilities.get("alwaysMatch");
226+
List<Map<?, ?>> first = (List<Map<?, ?>>) capabilities.get("firstMatch");
227+
228+
// We don't care where they are, but we want to see "se:option" and not "option"
229+
Set<String> keys = new HashSet(always.keySet());
230+
keys.addAll(first.stream()
231+
.map(Map::keySet)
232+
.flatMap(Collection::stream)
233+
.map(String::valueOf)
234+
.collect(Collectors.toSet()));
235+
assertTrue(keys.contains("browserName"));
236+
assertTrue(keys.contains("se:option"));
237+
assertFalse(keys.contains("options"));
238+
}
239+
190240
class RecordingHttpClient implements HttpClient {
191241

192242
private final HttpResponse response;

0 commit comments

Comments
 (0)