Skip to content

Commit 062ef44

Browse files
committed
Refactoring detection of spec compliant remote end in .NET
Since the W3C WebDriver working group has decided to remove the mandatory specificationLevel capability being returned when creating a new session, we now require a new way to detect whether a remote end uses the open-source project dialect or the W3C dialect of the wire protocol. We now do this by sniffing for the 'status' property in responses from the remote end. OSS dialect responses should have it; W3C dialect responses should not. Note that this is a potentially flawed algorithm, because there is no requirement that a remote end cannot add additional fields to a response body, but it's the best approach at present. If the working group makes a change that makes it easier to identify when a W3C compliant version of the protocol is being used, we can switch to that.
1 parent ef46bca commit 062ef44

File tree

2 files changed

+33
-43
lines changed

2 files changed

+33
-43
lines changed

dotnet/src/webdriver/Remote/HttpCommandExecutor.cs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -121,28 +121,17 @@ public virtual Response Execute(Command commandToExecute)
121121
}
122122

123123
Response toReturn = this.CreateResponse(request);
124-
if (commandToExecute.Name == DriverCommand.NewSession)
124+
if (commandToExecute.Name == DriverCommand.NewSession && toReturn.IsSpecificationCompliant)
125125
{
126126
// If we are creating a new session, sniff the response to determine
127127
// what protocol level we are using. If the response contains a
128-
// capability called "specificationLevel" that's an integer value
129-
// and that's greater than 0, that means we're using the W3C protocol
130-
// dialect.
128+
// field called "status", it's not a spec-compliant response.
129+
// Each response is polled for this, and sets a property describing
130+
// whether it's using the W3C protocol dialect.
131131
// TODO(jimevans): Reverse this test to make it the default path when
132132
// most remote ends speak W3C, then remove it entirely when legacy
133133
// protocol is phased out.
134-
Dictionary<string, object> capabilities = toReturn.Value as Dictionary<string, object>;
135-
if (capabilities != null)
136-
{
137-
if (capabilities.ContainsKey("specificationLevel"))
138-
{
139-
int returnedSpecLevel = Convert.ToInt32(capabilities["specificationLevel"]);
140-
if (returnedSpecLevel > 0)
141-
{
142-
this.commandInfoRepository = new W3CWireProtocolCommandInfoRepository();
143-
}
144-
}
145-
}
134+
this.commandInfoRepository = new W3CWireProtocolCommandInfoRepository();
146135
}
147136

148137
return toReturn;
@@ -198,7 +187,7 @@ private Response CreateResponse(WebRequest request)
198187
string responseString = GetTextOfWebResponse(webResponse);
199188
if (webResponse.ContentType != null && webResponse.ContentType.StartsWith(JsonMimeType, StringComparison.OrdinalIgnoreCase))
200189
{
201-
commandResponse = Response.FromJson(responseString, this.commandInfoRepository.SpecificationLevel);
190+
commandResponse = Response.FromJson(responseString);
202191
}
203192
else
204193
{

dotnet/src/webdriver/Remote/Response.cs

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class Response
3131
private object responseValue;
3232
private string responseSessionId;
3333
private WebDriverResult responseStatus;
34+
private bool isSpecificationCompliant;
3435

3536
/// <summary>
3637
/// Initializes a new instance of the Response class
@@ -51,7 +52,7 @@ public Response(SessionId sessionId)
5152
}
5253
}
5354

54-
private Response(Dictionary<string, object> rawResponse, int protocolSpecLevel)
55+
private Response(Dictionary<string, object> rawResponse)
5556
{
5657
if (rawResponse.ContainsKey("sessionId"))
5758
{
@@ -66,13 +67,31 @@ private Response(Dictionary<string, object> rawResponse, int protocolSpecLevel)
6667
this.responseValue = rawResponse["value"];
6768
}
6869

69-
if (protocolSpecLevel > 0)
70+
if (rawResponse.ContainsKey("status"))
7071
{
72+
this.responseStatus = (WebDriverResult)Convert.ToInt32(rawResponse["status"], CultureInfo.InvariantCulture);
73+
}
74+
else
75+
{
76+
// If the response does *not* have a "status" property, it
77+
// is compliant with the specification, which does not put
78+
// status in its responses.
79+
this.isSpecificationCompliant = true;
80+
7181
// If the returned object does *not* have a "value" property
7282
// the response value should be the entirety of the response.
7383
if (!rawResponse.ContainsKey("value") && this.responseValue == null)
7484
{
75-
this.responseValue = rawResponse;
85+
// Special-case for the new session command, where the "capabilities"
86+
// property of the response is the actual value we're interested in.
87+
if (rawResponse.ContainsKey("capabilities"))
88+
{
89+
this.responseValue = rawResponse["capabilities"];
90+
}
91+
else
92+
{
93+
this.responseValue = rawResponse;
94+
}
7695
}
7796

7897
// Check for an error response by looking for an "error" property,
@@ -82,20 +101,6 @@ private Response(Dictionary<string, object> rawResponse, int protocolSpecLevel)
82101
this.responseStatus = WebDriverError.ResultFromError(rawResponse["error"].ToString());
83102
}
84103
}
85-
else
86-
{
87-
if (rawResponse.ContainsKey("status"))
88-
{
89-
this.responseStatus = (WebDriverResult)Convert.ToInt32(rawResponse["status"], CultureInfo.InvariantCulture);
90-
}
91-
92-
// Special-case for the new session command, in the case where
93-
// the remote end is using the W3C dialect of the protocol.
94-
if (rawResponse.ContainsKey("capabilities"))
95-
{
96-
this.responseValue = rawResponse["capabilities"];
97-
}
98-
}
99104
}
100105

101106
/// <summary>
@@ -126,26 +131,22 @@ public WebDriverResult Status
126131
}
127132

128133
/// <summary>
129-
/// Returns a new <see cref="Response"/> from a JSON-encoded string.
134+
/// Gets a value indicating whether this response is compliant with the WebDriver specification.
130135
/// </summary>
131-
/// <param name="value">The JSON string to deserialize into a <see cref="Response"/>.</param>
132-
/// <returns>A <see cref="Response"/> object described by the JSON string.</returns>
133-
public static Response FromJson(string value)
136+
public bool IsSpecificationCompliant
134137
{
135-
return Response.FromJson(value, 0);
138+
get { return this.isSpecificationCompliant; }
136139
}
137140

138141
/// <summary>
139142
/// Returns a new <see cref="Response"/> from a JSON-encoded string.
140143
/// </summary>
141144
/// <param name="value">The JSON string to deserialize into a <see cref="Response"/>.</param>
142-
/// <param name="protocolSpecLevel">The specification level of the protocol from which to
143-
/// create the response.</param>
144145
/// <returns>A <see cref="Response"/> object described by the JSON string.</returns>
145-
public static Response FromJson(string value, int protocolSpecLevel)
146+
public static Response FromJson(string value)
146147
{
147148
Dictionary<string, object> deserializedResponse = JsonConvert.DeserializeObject<Dictionary<string, object>>(value, new ResponseValueJsonConverter());
148-
Response response = new Response(deserializedResponse, protocolSpecLevel);
149+
Response response = new Response(deserializedResponse);
149150
return response;
150151
}
151152

0 commit comments

Comments
 (0)