Commit 12b476b0 authored by Florent Castelli's avatar Florent Castelli Committed by Commit Bot

Properly translate RTCError objects to DOMException or RangeError

RangeErrors are not DOMException and the function we used
to translate them to DOMException couldn't handle anything else.
Using an ExceptionState, we can properly reject the promises with
the right type of exception.

Bug: 849214
Change-Id: I14ad11ba43910a83770d66c6976509c0feba3408
Reviewed-on: https://chromium-review.googlesource.com/1097325
Commit-Queue: Florent Castelli <orphis@chromium.org>
Reviewed-by: default avatarHenrik Boström <hbos@chromium.org>
Reviewed-by: default avatarYuki Shiino <yukishiino@chromium.org>
Cr-Commit-Position: refs/heads/master@{#567979}
parent cb0687b1
This is a testharness.js-based test.
PASS Add null candidate should reject with TypeError
FAIL Add ICE candidate before setting remote description should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Error processing ICE candidate" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
FAIL Add ICE candidate before setting remote description should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
PASS Add ICE candidate after setting remote description should succeed
PASS Add ICE candidate with RTCIceCandidate should succeed
FAIL Add candidate with only valid sdpMid should succeed promise_test: Unhandled rejection with value: object "OperationError: Error processing ICE candidate"
FAIL Add candidate with only valid sdpMLineIndex should succeed promise_test: Unhandled rejection with value: object "OperationError: Error processing ICE candidate"
FAIL Add candidate with only valid sdpMid should succeed promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
FAIL Add candidate with only valid sdpMLineIndex should succeed promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
PASS addIceCandidate with first sdpMid and sdpMLineIndex add candidate to first media stream
PASS addIceCandidate with second sdpMid and sdpMLineIndex should add candidate to second media stream
PASS Add candidate for first media stream with null ufrag should add candidate to first media stream
PASS Adding multiple candidates should add candidates to their corresponding media stream
FAIL Add with empty candidate string (end of candidate) should succeed promise_test: Unhandled rejection with value: object "OperationError: Error processing ICE candidate"
FAIL Add candidate with both sdpMid and sdpMLineIndex manually set to null should reject with TypeError assert_throws: function "function() { throw e }" threw object "OperationError: Error processing ICE candidate" ("OperationError") expected object "TypeError" ("TypeError")
FAIL Add with empty candidate string (end of candidate) should succeed promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
FAIL Add candidate with both sdpMid and sdpMLineIndex manually set to null should reject with TypeError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate" ("OperationError") expected object "TypeError" ("TypeError")
PASS Add candidate with only valid candidate string should reject with TypeError
FAIL Add candidate with invalid candidate string and both sdpMid and sdpMLineIndex null should reject with TypeError assert_throws: function "function() { throw e }" threw object "OperationError: Error processing ICE candidate" ("OperationError") expected object "TypeError" ("TypeError")
FAIL Add candidate with invalid candidate string and both sdpMid and sdpMLineIndex null should reject with TypeError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate" ("OperationError") expected object "TypeError" ("TypeError")
PASS Add candidate with empty dict should reject with TypeError
FAIL Add candidate with manually filled default values should reject with TypeError assert_throws: function "function() { throw e }" threw object "OperationError: Error processing ICE candidate" ("OperationError") expected object "TypeError" ("TypeError")
FAIL Add candidate with manually filled default values should reject with TypeError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate" ("OperationError") expected object "TypeError" ("TypeError")
PASS Add candidate with invalid sdpMid should reject with OperationError
PASS Add candidate with invalid sdpMLineIndex should reject with OperationError
FAIL Invalid sdpMLineIndex should be ignored if valid sdpMid is provided promise_test: Unhandled rejection with value: object "OperationError: Error processing ICE candidate"
FAIL Invalid sdpMLineIndex should be ignored if valid sdpMid is provided promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate"
PASS Add candidate for media stream 2 with null ufrag should succeed
FAIL Add candidate with invalid ufrag should reject with OperationError assert_unreached: Should have rejected: undefined Reached unreachable code
PASS Add candidate with invalid candidate string should reject with OperationError
......
This is a testharness.js-based test.
FAIL setLocalDescription(pranswer) from stable state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to set local pranswer sdp: Called in wrong state: kStable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
FAIL setLocalDescription(pranswer) from stable state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local pranswer sdp: Called in wrong state: kStable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
FAIL setLocalDescription(pranswer) should succeed assert_not_equals: Expect session description to be defined got disallowed value undefined
PASS setLocalDescription(pranswer) can be applied multiple times while still in have-local-pranswer
FAIL setLocalDescription(answer) from have-local-pranswer state should succeed assert_not_equals: Expect session description to be defined got disallowed value undefined
......
......@@ -2,7 +2,7 @@ This is a testharness.js-based test.
FAIL setLocalDescription() with valid answer should succeed assert_not_equals: Expect session description to be defined got disallowed value undefined
FAIL setLocalDescription() with type answer and null sdp should use lastAnswer generated from createAnswer assert_not_equals: Expect session description to be defined got disallowed value undefined
PASS setLocalDescription() with answer not created by own createAnswer() should reject with InvalidModificationError
FAIL Calling setLocalDescription(answer) from stable state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to set local answer sdp: Called in wrong state: kStable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
FAIL Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to set local answer sdp: Called in wrong state: kHaveLocalOffer" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
FAIL Calling setLocalDescription(answer) from stable state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kStable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
FAIL Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kHaveLocalOffer" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
Harness: the test ran to completion.
......@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_error_util.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
......@@ -42,16 +43,68 @@ DOMException* CreateDOMExceptionFromRTCError(const webrtc::RTCError& error) {
return DOMException::Create(DOMExceptionCode::kInvalidAccessError,
error.message());
case webrtc::RTCErrorType::INVALID_RANGE:
// TODO(https://crbug.com/849214): This crashes.
return DOMException::Create(ESErrorType::kRangeError, error.message());
// INVALID_RANGE should create a RangeError, which isn't a DOMException
default:
LOG(ERROR) << "Got unhandled RTC error "
<< static_cast<int>(error.type());
// No DOM equivalent. Needs per-error evaluation.
// No DOM equivalent.
// Needs per-error evaluation or use ThrowExceptionFromRTCError.
NOTREACHED();
break;
}
NOTREACHED();
return nullptr;
}
void ThrowExceptionFromRTCError(const webrtc::RTCError& error,
ExceptionState& exception_state) {
switch (error.type()) {
case webrtc::RTCErrorType::NONE:
// This should never happen.
NOTREACHED();
break;
case webrtc::RTCErrorType::SYNTAX_ERROR:
exception_state.ThrowDOMException(DOMExceptionCode::kSyntaxError,
error.message());
return;
case webrtc::RTCErrorType::INVALID_MODIFICATION:
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidModificationError, error.message());
return;
case webrtc::RTCErrorType::NETWORK_ERROR:
exception_state.ThrowDOMException(DOMExceptionCode::kNetworkError,
error.message());
return;
case webrtc::RTCErrorType::UNSUPPORTED_PARAMETER:
case webrtc::RTCErrorType::UNSUPPORTED_OPERATION:
case webrtc::RTCErrorType::RESOURCE_EXHAUSTED:
case webrtc::RTCErrorType::INTERNAL_ERROR:
exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
error.message());
return;
case webrtc::RTCErrorType::INVALID_STATE:
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
error.message());
return;
case webrtc::RTCErrorType::INVALID_PARAMETER:
// One use of this value is to signal invalid SDP syntax.
// According to spec, this should return an RTCError with name
// "RTCError" and detail "sdp-syntax-error", with
// "sdpLineNumber" set to indicate the line where the error
// occured.
// TODO(https://crbug.com/821806): Implement the RTCError object.
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
error.message());
return;
case webrtc::RTCErrorType::INVALID_RANGE:
exception_state.ThrowRangeError(error.message());
return;
default:
LOG(ERROR) << "Got unhandled RTC error "
<< static_cast<int>(error.type());
NOTREACHED();
break;
}
NOTREACHED();
}
} // namespace blink
......@@ -11,9 +11,12 @@
namespace blink {
class DOMException;
class ExceptionState;
DOMException* CreateDOMExceptionFromRTCError(const webrtc::RTCError&);
void ThrowExceptionFromRTCError(const webrtc::RTCError&, ExceptionState&);
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ERROR_UTIL_H_
......@@ -623,7 +623,8 @@ ScriptPromise RTCPeerConnection::createOffer(ScriptState* script_state,
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
RTCSessionDescriptionRequest* request =
RTCSessionDescriptionRequestPromiseImpl::Create(this, resolver);
RTCSessionDescriptionRequestPromiseImpl::Create(
this, resolver, "RTCPeerConnection", "createOffer");
if (options.hasOfferToReceiveAudio() || options.hasOfferToReceiveVideo()) {
ExecutionContext* context = ExecutionContext::From(script_state);
UseCounter::Count(
......@@ -708,7 +709,8 @@ ScriptPromise RTCPeerConnection::createAnswer(ScriptState* script_state,
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
RTCSessionDescriptionRequest* request =
RTCSessionDescriptionRequestPromiseImpl::Create(this, resolver);
RTCSessionDescriptionRequestPromiseImpl::Create(
this, resolver, "RTCPeerConnection", "createAnswer");
peer_handler_->CreateAnswer(request, ConvertToWebRTCAnswerOptions(options));
return promise;
}
......@@ -808,7 +810,8 @@ ScriptPromise RTCPeerConnection::setLocalDescription(
}
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
RTCVoidRequest* request = RTCVoidRequestPromiseImpl::Create(this, resolver);
RTCVoidRequest* request = RTCVoidRequestPromiseImpl::Create(
this, resolver, "RTCPeerConnection", "setLocalDescription");
peer_handler_->SetLocalDescription(
request, WebRTCSessionDescription(session_description_init.type(), sdp));
return promise;
......@@ -875,7 +878,8 @@ ScriptPromise RTCPeerConnection::setRemoteDescription(
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
RTCVoidRequest* request = RTCVoidRequestPromiseImpl::Create(this, resolver);
RTCVoidRequest* request = RTCVoidRequestPromiseImpl::Create(
this, resolver, "RTCPeerConnection", "setRemoteDescription");
peer_handler_->SetRemoteDescription(
request, WebRTCSessionDescription(session_description_init.type(),
session_description_init.sdp()));
......@@ -1107,7 +1111,8 @@ ScriptPromise RTCPeerConnection::addIceCandidate(
ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
ScriptPromise promise = resolver->Promise();
RTCVoidRequest* request = RTCVoidRequestPromiseImpl::Create(this, resolver);
RTCVoidRequest* request = RTCVoidRequestPromiseImpl::Create(
this, resolver, "RTCPeerConnection", "addIceCandidate");
scoped_refptr<WebRTCICECandidate> web_candidate = ConvertToWebRTCIceCandidate(
ExecutionContext::From(script_state), candidate);
bool implemented =
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.h"
#include "third_party/blink/public/platform/web_rtc_dtmf_sender_handler.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
......@@ -12,6 +13,7 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_void_request_script_promise_resolver_impl.h"
#include "third_party/blink/renderer/modules/peerconnection/web_rtc_stats_report_callback_resolver.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_void_request.h"
namespace blink {
......@@ -32,7 +34,12 @@ class ReplaceTrackRequest : public RTCVoidRequest {
}
void RequestFailed(const webrtc::RTCError& error) override {
resolver_->Reject(CreateDOMExceptionFromRTCError(error));
ScriptState::Scope scope(resolver_->GetScriptState());
ExceptionState exception_state(resolver_->GetScriptState()->GetIsolate(),
ExceptionState::kExecutionContext,
"RTCRtpSender", "replaceTrack");
ThrowExceptionFromRTCError(error, exception_state);
resolver_->Reject(exception_state);
}
void Trace(blink::Visitor* visitor) override {
......@@ -51,7 +58,10 @@ class ReplaceTrackRequest : public RTCVoidRequest {
class SetParametersRequest : public RTCVoidRequestScriptPromiseResolverImpl {
public:
SetParametersRequest(ScriptPromiseResolver* resolver, RTCRtpSender* sender)
: RTCVoidRequestScriptPromiseResolverImpl(resolver), sender_(sender) {}
: RTCVoidRequestScriptPromiseResolverImpl(resolver,
"RTCRtpSender",
"setParameters"),
sender_(sender) {}
void RequestSucceeded() override {
sender_->ClearLastReturnedParameters();
......
......@@ -14,16 +14,23 @@
namespace blink {
RTCSessionDescriptionRequestPromiseImpl*
RTCSessionDescriptionRequestPromiseImpl::Create(
RTCPeerConnection* requester,
ScriptPromiseResolver* resolver) {
return new RTCSessionDescriptionRequestPromiseImpl(requester, resolver);
RTCSessionDescriptionRequestPromiseImpl::Create(RTCPeerConnection* requester,
ScriptPromiseResolver* resolver,
const char* interface_name,
const char* property_name) {
return new RTCSessionDescriptionRequestPromiseImpl(
requester, resolver, interface_name, property_name);
}
RTCSessionDescriptionRequestPromiseImpl::
RTCSessionDescriptionRequestPromiseImpl(RTCPeerConnection* requester,
ScriptPromiseResolver* resolver)
: requester_(requester), resolver_(resolver) {
ScriptPromiseResolver* resolver,
const char* interface_name,
const char* property_name)
: requester_(requester),
resolver_(resolver),
interface_name_(interface_name),
property_name_(property_name) {
DCHECK(requester_);
DCHECK(resolver_);
}
......@@ -49,7 +56,12 @@ void RTCSessionDescriptionRequestPromiseImpl::RequestSucceeded(
void RTCSessionDescriptionRequestPromiseImpl::RequestFailed(
const webrtc::RTCError& error) {
if (requester_ && requester_->ShouldFireDefaultCallbacks()) {
resolver_->Reject(CreateDOMExceptionFromRTCError(error));
ScriptState::Scope scope(resolver_->GetScriptState());
ExceptionState exception_state(resolver_->GetScriptState()->GetIsolate(),
ExceptionState::kExecutionContext,
interface_name_, property_name_);
ThrowExceptionFromRTCError(error, exception_state);
resolver_->Reject(exception_state);
} else {
// This is needed to have the resolver release its internal resources
// while leaving the associated promise pending as specified.
......
......@@ -19,7 +19,9 @@ class RTCSessionDescriptionRequestPromiseImpl final
public:
static RTCSessionDescriptionRequestPromiseImpl* Create(
RTCPeerConnection*,
ScriptPromiseResolver*);
ScriptPromiseResolver*,
const char* interface_name,
const char* property_name);
~RTCSessionDescriptionRequestPromiseImpl() override;
// RTCSessionDescriptionRequest
......@@ -30,12 +32,16 @@ class RTCSessionDescriptionRequestPromiseImpl final
private:
RTCSessionDescriptionRequestPromiseImpl(RTCPeerConnection*,
ScriptPromiseResolver*);
ScriptPromiseResolver*,
const char* interface_name,
const char* property_name);
void Clear();
Member<RTCPeerConnection> requester_;
Member<ScriptPromiseResolver> resolver_;
const char* interface_name_;
const char* property_name_;
};
} // namespace blink
......
......@@ -13,14 +13,22 @@ namespace blink {
RTCVoidRequestPromiseImpl* RTCVoidRequestPromiseImpl::Create(
RTCPeerConnection* requester,
ScriptPromiseResolver* resolver) {
return new RTCVoidRequestPromiseImpl(requester, resolver);
ScriptPromiseResolver* resolver,
const char* interface_name,
const char* property_name) {
return new RTCVoidRequestPromiseImpl(requester, resolver, interface_name,
property_name);
}
RTCVoidRequestPromiseImpl::RTCVoidRequestPromiseImpl(
RTCPeerConnection* requester,
ScriptPromiseResolver* resolver)
: requester_(requester), resolver_(resolver) {
ScriptPromiseResolver* resolver,
const char* interface_name,
const char* property_name)
: requester_(requester),
resolver_(resolver),
interface_name_(interface_name),
property_name_(property_name) {
DCHECK(requester_);
DCHECK(resolver_);
}
......@@ -41,7 +49,12 @@ void RTCVoidRequestPromiseImpl::RequestSucceeded() {
void RTCVoidRequestPromiseImpl::RequestFailed(const webrtc::RTCError& error) {
if (requester_ && requester_->ShouldFireDefaultCallbacks()) {
resolver_->Reject(CreateDOMExceptionFromRTCError(error));
ScriptState::Scope scope(resolver_->GetScriptState());
ExceptionState exception_state(resolver_->GetScriptState()->GetIsolate(),
ExceptionState::kExecutionContext,
interface_name_, property_name_);
ThrowExceptionFromRTCError(error, exception_state);
resolver_->Reject(exception_state);
} else {
// This is needed to have the resolver release its internal resources
// while leaving the associated promise pending as specified.
......
......@@ -16,7 +16,9 @@ class RTCPeerConnection;
class RTCVoidRequestPromiseImpl final : public RTCVoidRequest {
public:
static RTCVoidRequestPromiseImpl* Create(RTCPeerConnection*,
ScriptPromiseResolver*);
ScriptPromiseResolver*,
const char* interface_name,
const char* property_name);
~RTCVoidRequestPromiseImpl() override;
// RTCVoidRequest
......@@ -26,12 +28,17 @@ class RTCVoidRequestPromiseImpl final : public RTCVoidRequest {
void Trace(blink::Visitor*) override;
private:
RTCVoidRequestPromiseImpl(RTCPeerConnection*, ScriptPromiseResolver*);
RTCVoidRequestPromiseImpl(RTCPeerConnection*,
ScriptPromiseResolver*,
const char* interface_name,
const char* property_name);
void Clear();
Member<RTCPeerConnection> requester_;
Member<ScriptPromiseResolver> resolver_;
const char* interface_name_;
const char* property_name_;
};
} // namespace blink
......
......@@ -11,14 +11,20 @@
namespace blink {
RTCVoidRequestScriptPromiseResolverImpl*
RTCVoidRequestScriptPromiseResolverImpl::Create(
ScriptPromiseResolver* resolver) {
return new RTCVoidRequestScriptPromiseResolverImpl(resolver);
RTCVoidRequestScriptPromiseResolverImpl::Create(ScriptPromiseResolver* resolver,
const char* interface_name,
const char* property_name) {
return new RTCVoidRequestScriptPromiseResolverImpl(resolver, interface_name,
property_name);
}
RTCVoidRequestScriptPromiseResolverImpl::
RTCVoidRequestScriptPromiseResolverImpl(ScriptPromiseResolver* resolver)
: resolver_(resolver) {
RTCVoidRequestScriptPromiseResolverImpl(ScriptPromiseResolver* resolver,
const char* interface_name,
const char* property_name)
: resolver_(resolver),
interface_name_(interface_name),
property_name_(property_name) {
DCHECK(resolver_);
}
......@@ -31,7 +37,12 @@ void RTCVoidRequestScriptPromiseResolverImpl::RequestSucceeded() {
void RTCVoidRequestScriptPromiseResolverImpl::RequestFailed(
const webrtc::RTCError& error) {
resolver_->Reject(CreateDOMExceptionFromRTCError(error));
ScriptState::Scope scope(resolver_->GetScriptState());
ExceptionState exception_state(resolver_->GetScriptState()->GetIsolate(),
ExceptionState::kExecutionContext,
interface_name_, property_name_);
ThrowExceptionFromRTCError(error, exception_state);
resolver_->Reject(exception_state);
}
void RTCVoidRequestScriptPromiseResolverImpl::Trace(blink::Visitor* visitor) {
......
......@@ -15,7 +15,9 @@ class ScriptPromiseResolver;
class RTCVoidRequestScriptPromiseResolverImpl : public RTCVoidRequest {
public:
static RTCVoidRequestScriptPromiseResolverImpl* Create(
ScriptPromiseResolver*);
ScriptPromiseResolver*,
const char* interface_name,
const char* property_name);
~RTCVoidRequestScriptPromiseResolverImpl() override;
// RTCVoidRequest
......@@ -25,9 +27,13 @@ class RTCVoidRequestScriptPromiseResolverImpl : public RTCVoidRequest {
void Trace(blink::Visitor*) override;
protected:
RTCVoidRequestScriptPromiseResolverImpl(ScriptPromiseResolver*);
RTCVoidRequestScriptPromiseResolverImpl(ScriptPromiseResolver*,
const char* interface_name,
const char* property_name);
Member<ScriptPromiseResolver> resolver_;
const char* interface_name_;
const char* property_name_;
};
} // namespace blink
......
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