Commit 43d4baee authored by Adam Rice's avatar Adam Rice Committed by Commit Bot

Implement connection and close for QuicTransport

QuicTransport is a low-level JavaScript interface to permit
communication via the QUIC protocol. This CL implements only the
connection and close parts of the API, along with unit tests.

Bug: 1011392
Change-Id: I7383680e04c83a45f483e5d542e9227f8288ed65
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1899631Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Commit-Queue: Adam Rice <ricea@chromium.org>
Cr-Commit-Position: refs/heads/master@{#715349}
parent 4a910ce9
......@@ -877,6 +877,7 @@ modules_dictionary_idl_files =
"websockets/websocket_close_info.idl",
"websockets/websocket_connection.idl",
"websockets/websocket_stream_options.idl",
"webtransport/web_transport_close_info.idl",
"webusb/usb_connection_event_init.idl",
"webusb/usb_control_transfer_parameters.idl",
"webusb/usb_device_filter.idl",
......
......@@ -13,7 +13,9 @@ blink_modules_sources("webtransport") {
jumbo_source_set("unit_tests") {
testonly = true
sources = []
sources = [
"quic_transport_test.cc",
]
configs += [
"//third_party/blink/renderer:config",
......
......@@ -4,63 +4,177 @@
#include "third_party/blink/renderer/modules/webtransport/quic_transport.h"
#include <utility>
#include "mojo/public/cpp/bindings/remote.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/mojom/webtransport/quic_transport_connector.mojom-blink.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
namespace {
KURL ReparseURLAsHTTPS(KURL url) {
url.SetProtocol("https");
return url;
}
} // namespace
QuicTransport* QuicTransport::Create(ScriptState* script_state,
const String& url) {
const String& url,
ExceptionState& exception_state) {
DVLOG(1) << "QuicTransport::Create() url=" << url;
auto* transport =
MakeGarbageCollected<QuicTransport>(PassKey(), script_state, url);
transport->Init();
transport->Init(exception_state);
return transport;
}
QuicTransport::QuicTransport(PassKey,
ScriptState* script_state,
const String& url)
: script_state_(script_state),
url_(url),
handshake_client_receiver_(this) {}
: ContextLifecycleObserver(ExecutionContext::From(script_state)),
url_(NullURL(), url) {}
void QuicTransport::close(const WebTransportCloseInfo* close_info) {
DVLOG(1) << "QuicTransport::close() this=" << this;
// TODO(ricea): Send |close_info| to the network service.
Dispose();
}
void QuicTransport::OnConnectionEstablished(
mojo::PendingRemote<network::mojom::blink::QuicTransport>,
mojo::PendingReceiver<network::mojom::blink::QuicTransportClient>) {
mojo::PendingRemote<network::mojom::blink::QuicTransport> quic_transport,
mojo::PendingReceiver<network::mojom::blink::QuicTransportClient>
client_receiver) {
DVLOG(1) << "QuicTransport::OnConnectionEstablished() this=" << this;
handshake_client_receiver_.reset();
// TODO(ricea): Report to devtools.
auto task_runner =
GetExecutionContext()->GetTaskRunner(TaskType::kNetworking);
client_receiver_.Bind(std::move(client_receiver), task_runner);
client_receiver_.set_disconnect_handler(
WTF::Bind(&QuicTransport::OnConnectionError, WrapWeakPersistent(this)));
DCHECK(!quic_transport_);
quic_transport_.Bind(std::move(quic_transport), task_runner);
}
QuicTransport::~QuicTransport() = default;
void QuicTransport::OnHandshakeFailed() {
DVLOG(1) << "QuicTransport::OnHandshakeFailed() this=" << this;
handshake_client_receiver_.reset();
}
void QuicTransport::ContextDestroyed(ExecutionContext* execution_context) {
DVLOG(1) << "QuicTransport::ContextDestroyed() this=" << this;
Dispose();
}
bool QuicTransport::HasPendingActivity() const {
DVLOG(1) << "QuicTransport::HasPendingActivity() this=" << this;
return handshake_client_receiver_.is_bound() || client_receiver_.is_bound();
}
void QuicTransport::Trace(Visitor* visitor) {
visitor->Trace(script_state_);
ContextLifecycleObserver::Trace(visitor);
ScriptWrappable::Trace(visitor);
}
void QuicTransport::Init() {
void QuicTransport::Init(ExceptionState& exception_state) {
DVLOG(1) << "QuicTransport::Init() url=" << url_ << " this=" << this;
if (!url_.IsValid()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
"The URL '" + url_.ElidedString() + "' is invalid.");
return;
}
if (!url_.ProtocolIs("quic-transport")) {
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
"The URL's scheme must be 'quic-transport'. '" + url_.Protocol() +
"' is not allowed.");
return;
}
// TODO(ricea): Use the URL as-is once "quic-transport" it has been added to
// the "special" schemes list.
KURL url_as_https = ReparseURLAsHTTPS(url_);
if (!url_as_https.IsValid()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
"The URL '" + url_.ElidedString() + "' is invalid.");
return;
}
if (url_as_https.HasFragmentIdentifier()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kSyntaxError,
"The URL contains a fragment identifier ('#" +
url_as_https.FragmentIdentifier() +
"'). Fragment identifiers are not allowed in QuicTransport URLs.");
return;
}
auto* execution_context = GetExecutionContext();
if (!execution_context->GetContentSecurityPolicyForWorld()
->AllowConnectToSource(url_as_https)) {
// TODO(ricea): This error should probably be asynchronous like it is for
// WebSockets and fetch.
exception_state.ThrowSecurityError(
"Failed to connect to '" + url_.ElidedString() + "'",
"Refused to connect to '" + url_.ElidedString() +
"' because it violates the document's Content Security Policy");
return;
}
// TODO(ricea): Register SchedulingPolicy so that we don't get throttled and
// to disable bfcache. Must be done before shipping.
// TODO(ricea): Check the SubresourceFilter and fail asynchronously if
// disallowed. Must be done before shipping.
mojo::Remote<mojom::blink::QuicTransportConnector> connector;
ExecutionContext* execution_context = ExecutionContext::From(script_state_);
auto* interface_provider = execution_context->GetInterfaceProvider();
DCHECK(execution_context->GetInterfaceProvider());
execution_context->GetInterfaceProvider()->GetInterface(
connector.BindNewPipeAndPassReceiver(
execution_context->GetTaskRunner(TaskType::kNetworking)));
DCHECK(interface_provider);
interface_provider->GetInterface(connector.BindNewPipeAndPassReceiver(
execution_context->GetTaskRunner(TaskType::kNetworking)));
connector->Connect(
url_, handshake_client_receiver_.BindNewPipeAndPassRemote(
execution_context->GetTaskRunner(TaskType::kNetworking)));
// TODO(yhirano): Attach a disconnect handler for
// |handshake_client_receiver_|.
handshake_client_receiver_.set_disconnect_handler(
WTF::Bind(&QuicTransport::OnConnectionError, WrapWeakPersistent(this)));
// TODO(ricea): Report something to devtools.
}
void QuicTransport::Dispose() {
DVLOG(1) << "QuicTransport::Dispose() this=" << this;
quic_transport_.reset();
handshake_client_receiver_.reset();
client_receiver_.reset();
}
void QuicTransport::OnConnectionError() {
DVLOG(1) << "QuicTransport::OnConnectionError() this=" << this;
Dispose();
}
} // namespace blink
......@@ -9,7 +9,10 @@
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/quic_transport.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
......@@ -17,20 +20,32 @@
namespace blink {
class ExceptionState;
class ExecutionContext;
class ScriptState;
class WebTransportCloseInfo;
class MODULES_EXPORT QuicTransport final
: public ScriptWrappable,
public network::mojom::blink::QuicTransportHandshakeClient {
public ActiveScriptWrappable<QuicTransport>,
public ContextLifecycleObserver,
public network::mojom::blink::QuicTransportHandshakeClient,
public network::mojom::blink::QuicTransportClient {
DEFINE_WRAPPERTYPEINFO();
USING_PRE_FINALIZER(QuicTransport, Dispose);
USING_GARBAGE_COLLECTED_MIXIN(QuicTransport);
public:
using PassKey = util::PassKey<QuicTransport>;
static QuicTransport* Create(ScriptState* script_state, const String& url);
static QuicTransport* Create(ScriptState* script_state,
const String& url,
ExceptionState&);
QuicTransport(PassKey, ScriptState*, const String& url);
~QuicTransport() override = default;
~QuicTransport() override;
// QuicTransport IDL implementation.
void close(const WebTransportCloseInfo*);
// QuicTransportHandshakeClient implementation
void OnConnectionEstablished(
......@@ -39,19 +54,28 @@ class MODULES_EXPORT QuicTransport final
override;
void OnHandshakeFailed() override;
// Implementation of ContextLifecycleObserver
void ContextDestroyed(ExecutionContext*) final;
// Implementation of ActiveScriptWrappable
bool HasPendingActivity() const final;
// ScriptWrappable implementation
void Trace(Visitor* visitor) override;
private:
void Init();
void Init(ExceptionState&);
void Dispose();
void OnConnectionError();
const Member<ScriptState> script_state_;
const KURL url_;
mojo::Remote<network::mojom::blink::QuicTransport> quic_transport_;
mojo::Receiver<network::mojom::blink::QuicTransportHandshakeClient>
handshake_client_receiver_;
handshake_client_receiver_{this};
mojo::Receiver<network::mojom::blink::QuicTransportClient> client_receiver_{
this};
};
} // namespace blink
#endif
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBTRANSPORT_QUIC_TRANSPORT_H_
......@@ -4,13 +4,17 @@
// https://wicg.github.io/web-transport/#quic-transport
[
ActiveScriptWrappable,
Constructor(USVString url),
Exposed=(Window, Worker),
Exposed=(Window,Worker),
RuntimeEnabled=QuicTransport,
ConstructorCallWith=ScriptState
ConstructorCallWith=ScriptState,
RaisesException=Constructor
] interface QuicTransport {
// QuicTransport is the first, and at this moment only, transport which is
// implemented. In the (draft) spec there are many mix-in interfaces which
// QuicTransport includes, but we define all their methods/attributes here
// for simplicity.
void close(optional WebTransportCloseInfo closeInfo);
};
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// https://wicg.github.io/web-transport/#dictdef-webtransportcloseinfo
dictionary WebTransportCloseInfo {
unsigned short errorCode = 0;
DOMString reason = "";
};
......@@ -1221,6 +1221,7 @@ interface PushSubscriptionOptions
method constructor
interface QuicTransport
attribute @@toStringTag
method close
method constructor
interface ReadableStream
attribute @@toStringTag
......
......@@ -1155,6 +1155,7 @@ Starting worker: resources/global-interface-listing-worker.js
[Worker] method constructor
[Worker] interface QuicTransport
[Worker] attribute @@toStringTag
[Worker] method close
[Worker] method constructor
[Worker] interface ReadableStream
[Worker] attribute @@toStringTag
......
......@@ -6144,6 +6144,7 @@ interface PushSubscriptionOptions
method constructor
interface QuicTransport
attribute @@toStringTag
method close
method constructor
interface RTCCertificate
attribute @@toStringTag
......
......@@ -1137,6 +1137,7 @@ Starting worker: resources/global-interface-listing-worker.js
[Worker] method constructor
[Worker] interface QuicTransport
[Worker] attribute @@toStringTag
[Worker] method close
[Worker] method constructor
[Worker] interface ReadableStream
[Worker] attribute @@toStringTag
......
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