Commit 211677df authored by Bill Orr's avatar Bill Orr Committed by Commit Bot

Reject WebXR session requests with consistent errors

The service_ pointer was getting nulled-out asynchronously, so we'd
sometimes reject early based on the service_ being null and sometimes
pass that check and reject with no user gesture.

The fix makes things consistent but not yet spec compliant - issue
962991 will make things spec compliant.

Bug: 962685
Change-Id: I69bae46f02e0027ef69365c1c8c47d72af0dee3b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1630719Reviewed-by: default avatarDavid Dorwin <ddorwin@chromium.org>
Commit-Queue: Bill Orr <billorr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#664383}
parent ec8eedf8
...@@ -284,15 +284,6 @@ ScriptPromise XR::requestSession(ScriptState* script_state, ...@@ -284,15 +284,6 @@ ScriptPromise XR::requestSession(ScriptState* script_state,
kFeaturePolicyBlocked)); kFeaturePolicyBlocked));
} }
// If we no longer have a valid service connection reject the request, unless
// it was for an inline mode. In which case, we'll end up creating the
// session in OnRequestSessionReturned.
if (!service_ && session_mode != XRSession::kModeInline) {
return ScriptPromise::RejectWithDOMException(
script_state, MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotFoundError, kNoDevicesMessage));
}
// Only one immersive session can be active at a time. // Only one immersive session can be active at a time.
if (is_immersive && frameProvider()->immersive_session()) { if (is_immersive && frameProvider()->immersive_session()) {
return ScriptPromise::RejectWithDOMException( return ScriptPromise::RejectWithDOMException(
...@@ -310,6 +301,19 @@ ScriptPromise XR::requestSession(ScriptState* script_state, ...@@ -310,6 +301,19 @@ ScriptPromise XR::requestSession(ScriptState* script_state,
kRequestRequiresUserActivation)); kRequestRequiresUserActivation));
} }
// TODO(https://crbug.com/962991): The error handling here is not spec
// compliant. The spec says to reject based on no device before rejecting
// based on user gesture.
// If we no longer have a valid service connection reject the request, unless
// it was for an inline mode. In which case, we'll end up creating the
// session in OnRequestSessionReturned.
if (!service_ && session_mode != XRSession::kModeInline) {
return ScriptPromise::RejectWithDOMException(
script_state,
MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotSupportedError,
kNoDevicesMessage));
}
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise(); ScriptPromise promise = resolver->Promise();
...@@ -340,6 +344,9 @@ void XR::DispatchRequestSession(PendingSessionQuery* query) { ...@@ -340,6 +344,9 @@ void XR::DispatchRequestSession(PendingSessionQuery* query) {
return; return;
} }
// TODO(https://crbug.com/962991): The spec says to reject with null.
// Clarify/fix the spec. In other places where we have no device or no
// service we return kNotSupportedError.
query->resolver->Reject(MakeGarbageCollected<DOMException>( query->resolver->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotSupportedError, kSessionNotSupported)); DOMExceptionCode::kNotSupportedError, kSessionNotSupported));
return; return;
...@@ -613,6 +620,9 @@ void XR::OnDeviceDisconnect() { ...@@ -613,6 +620,9 @@ void XR::OnDeviceDisconnect() {
HeapHashSet<Member<PendingSessionQuery>> request_queries = HeapHashSet<Member<PendingSessionQuery>> request_queries =
outstanding_request_queries_; outstanding_request_queries_;
for (const auto& query : request_queries) { for (const auto& query : request_queries) {
// We had a device, so rejecting the session request as though the mode
// isn't supported. TODO(https://crbug.com/962991): The spec should specify
// what is returned here.
OnRequestSessionReturned(query, nullptr); OnRequestSessionReturned(query, nullptr);
} }
DCHECK(outstanding_support_queries_.IsEmpty()); DCHECK(outstanding_support_queries_.IsEmpty());
......
...@@ -92,24 +92,22 @@ test(t => { ...@@ -92,24 +92,22 @@ test(t => {
// Ensure that AR sessions are not exposed as part of the WebXR origin trial. // Ensure that AR sessions are not exposed as part of the WebXR origin trial.
// The webXREnabled check is effectively checking whether experimental features // The webXREnabled check is effectively checking whether experimental features
// are enabled. This works as long as at least one AR feature is experimental. // are enabled. This works as long as at least one AR feature is experimental.
// TODO(https://crbug.com/962685): Make the supportsSession checks first after
// this issue is fixed.
promise_test(t => { promise_test(t => {
let promise = navigator.xr.requestSession('immersive-ar'); let promise = navigator.xr.supportsSession('immersive-ar');
if (OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) { if (OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) {
return promise_rejects(t, "SecurityError", promise); return promise_rejects(t, "NotSupportedError", promise);
} else { } else {
return promise_rejects(t, new TypeError(), promise); return promise_rejects(t, new TypeError(), promise);
} }
}, "immersive-ar is not recognized by requestSession() with a WebXR token."); }, "immersive-ar is not recognized by supportsSession() with a WebXR token.");
promise_test(t => { promise_test(t => {
let promise = navigator.xr.supportsSession('immersive-ar'); let promise = navigator.xr.requestSession('immersive-ar');
if (OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) { if (OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) {
return promise_rejects(t, "NotSupportedError", promise); return promise_rejects(t, "SecurityError", promise);
} else { } else {
return promise_rejects(t, new TypeError(), promise); return promise_rejects(t, new TypeError(), promise);
} }
}, "immersive-ar is not recognized by supportsSession() with a WebXR token."); }, "immersive-ar is not recognized by requestSession() with a WebXR token.");
// Verify the rejection reason matches that for other invalid enum values. // Verify the rejection reason matches that for other invalid enum values.
// It only makes sense to run these when the failure occurs. // It only makes sense to run these when the failure occurs.
if (!OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) { if (!OriginTrialsHelper.is_runtime_flag_enabled('webXREnabled')) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment