Commit 87c098f0 authored by Eric Willigers's avatar Eric Willigers Committed by Commit Bot

Direct Sockets: Browser implementation for TCP connection establishment

DirectSocketsServiceImpl::OpenTcpSocket() now calls
CreateTCPConnectedSocket() on the network context.

Browser test DirectSocketsBrowserTest.OpenTcp_Options verifies
that the remote address, port, buffer sizes and no-delay flag
are passed successfully.

NavigatorSocket::PendingRequest has been split into
TCPSocket and UDPSocket classes, currently with no web-exposed
members implemented.
https://github.com/WICG/raw-sockets/blob/master/docs/explainer.md#tcp
https://github.com/WICG/raw-sockets/blob/master/docs/explainer.md#udp




Explainer: https://github.com/WICG/raw-sockets/blob/master/docs/explainer.md

Intent to Prototype:
https://groups.google.com/a/chromium.org/g/blink-dev/c/ARtkaw4e9T4/m/npjeMssPCAAJ

Design doc:
https://docs.google.com/document/d/1Xa5nFkIWxkL3hZHvDYWPhT8sZvNeFpCUKNuqIwZHxnE/edit?usp=sharing


This is a reland of https://chromium-review.googlesource.com/c/chromium/src/+/2391181
which was reverted https://chromium-review.googlesource.com/c/chromium/src/+/2404821
as 'New tests are failing on many builders'


Some new tests are temporarily disabled while we investigate their
failures on specific bots - crbug.com/1141241

Bug: 905818,1141241
Change-Id: I13bedf1fdc160b3d1fc857a3debde73e3203ffee
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2465343
Auto-Submit: Eric Willigers <ericwilligers@chromium.org>
Commit-Queue: Eric Willigers <ericwilligers@chromium.org>
Reviewed-by: default avatarGlen Robertson <glenrob@chromium.org>
Reviewed-by: default avatarJeremy Roman <jbroman@chromium.org>
Reviewed-by: default avatarChristian Dullweber <dullweber@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#820088}
parent 6819e886
...@@ -773,8 +773,6 @@ source_set("browser") { ...@@ -773,8 +773,6 @@ source_set("browser") {
"devtools/shared_worker_devtools_manager.h", "devtools/shared_worker_devtools_manager.h",
"devtools/worker_devtools_agent_host.cc", "devtools/worker_devtools_agent_host.cc",
"devtools/worker_devtools_agent_host.h", "devtools/worker_devtools_agent_host.h",
"direct_sockets/direct_sockets_service_impl.cc",
"direct_sockets/direct_sockets_service_impl.h",
"display_cutout/display_cutout_constants.h", "display_cutout/display_cutout_constants.h",
"display_cutout/display_cutout_host_impl.cc", "display_cutout/display_cutout_host_impl.cc",
"display_cutout/display_cutout_host_impl.h", "display_cutout/display_cutout_host_impl.h",
...@@ -2595,6 +2593,10 @@ source_set("browser") { ...@@ -2595,6 +2593,10 @@ source_set("browser") {
"host_zoom_map_impl.h", "host_zoom_map_impl.h",
"media/session/audio_focus_delegate_default.cc", "media/session/audio_focus_delegate_default.cc",
# The Direct Sockets API is not implemented on Android.
"direct_sockets/direct_sockets_service_impl.cc",
"direct_sockets/direct_sockets_service_impl.h",
# The Serial API is not implemented on Android. # The Serial API is not implemented on Android.
"serial/serial_service.cc", "serial/serial_service.cc",
"serial/serial_service.h", "serial/serial_service.h",
......
...@@ -2,22 +2,96 @@ ...@@ -2,22 +2,96 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <vector>
#include "base/optional.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "content/browser/direct_sockets/direct_sockets_service_impl.h" #include "content/browser/direct_sockets/direct_sockets_service_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h" #include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h" #include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h" #include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/ip_address.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/tcp_socket.mojom.h"
#include "services/network/test/test_network_context.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace content { namespace content {
namespace {
enum class ProtocolType { kTcp, kUdp };
struct RecordedCall {
ProtocolType protocol_type;
std::string remote_address;
uint16_t remote_port;
int32_t send_buffer_size = 0;
int32_t receive_buffer_size = 0;
bool no_delay = false;
};
class MockNetworkContext : public network::TestNetworkContext {
public:
explicit MockNetworkContext(net::Error result) : result_(result) {}
const std::vector<RecordedCall>& history() const { return history_; }
// network::TestNetworkContext:
void CreateTCPConnectedSocket(
const base::Optional<net::IPEndPoint>& local_addr,
const net::AddressList& remote_addr_list,
network::mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojo::PendingReceiver<network::mojom::TCPConnectedSocket> socket,
mojo::PendingRemote<network::mojom::SocketObserver> observer,
CreateTCPConnectedSocketCallback callback) override {
history_.push_back(RecordedCall{
ProtocolType::kTcp, remote_addr_list[0].address().ToString(),
remote_addr_list[0].port(),
tcp_connected_socket_options->send_buffer_size,
tcp_connected_socket_options->receive_buffer_size,
tcp_connected_socket_options->no_delay});
std::move(callback).Run(result_, base::nullopt, base::nullopt,
mojo::ScopedDataPipeConsumerHandle(),
mojo::ScopedDataPipeProducerHandle());
}
private:
const net::Error result_;
std::vector<RecordedCall> history_;
};
net::Error UnconditionallyPermitConnection(
const blink::mojom::DirectSocketOptions& options,
net::IPAddress& remote_address) {
DCHECK(options.remote_hostname.has_value());
DCHECK(remote_address.AssignFromIPLiteral(*options.remote_hostname));
EXPECT_EQ(remote_address.ToString(), *options.remote_hostname);
return net::OK;
}
} // anonymous namespace
class DirectSocketsBrowserTest : public ContentBrowserTest { class DirectSocketsBrowserTest : public ContentBrowserTest {
public: public:
DirectSocketsBrowserTest() { DirectSocketsBrowserTest() {
...@@ -29,6 +103,34 @@ class DirectSocketsBrowserTest : public ContentBrowserTest { ...@@ -29,6 +103,34 @@ class DirectSocketsBrowserTest : public ContentBrowserTest {
return embedded_test_server()->GetURL("/direct_sockets/index.html"); return embedded_test_server()->GetURL("/direct_sockets/index.html");
} }
network::mojom::NetworkContext* GetNetworkContext() {
return BrowserContext::GetDefaultStoragePartition(browser_context())
->GetNetworkContext();
}
// Returns the port listening for TCP connections.
uint16_t StartTcpServer() {
net::IPEndPoint local_addr;
base::RunLoop run_loop;
GetNetworkContext()->CreateTCPServerSocket(
net::IPEndPoint(net::IPAddress::IPv4Localhost(),
/*port=*/0),
/*backlog=*/5,
net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
tcp_server_socket_.BindNewPipeAndPassReceiver(),
base::BindLambdaForTesting(
[&local_addr, &run_loop](
int32_t result,
const base::Optional<net::IPEndPoint>& local_addr_out) {
DCHECK_EQ(result, net::OK);
DCHECK(local_addr_out.has_value());
local_addr = *local_addr_out;
run_loop.Quit();
}));
run_loop.Run();
return local_addr.port();
}
protected: protected:
void SetUp() override { void SetUp() override {
embedded_test_server()->AddDefaultHandlers(GetTestDataFilePath()); embedded_test_server()->AddDefaultHandlers(GetTestDataFilePath());
...@@ -38,19 +140,24 @@ class DirectSocketsBrowserTest : public ContentBrowserTest { ...@@ -38,19 +140,24 @@ class DirectSocketsBrowserTest : public ContentBrowserTest {
} }
private: private:
BrowserContext* browser_context() {
return shell()->web_contents()->GetBrowserContext();
}
base::test::ScopedFeatureList feature_list_; base::test::ScopedFeatureList feature_list_;
mojo::Remote<network::mojom::TCPServerSocket> tcp_server_socket_;
}; };
IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, OpenTcp_Success) { // TODO(crbug.com/1141241): Resolve failures on linux-bfcache-rel bots.
IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, DISABLED_OpenTcp_Success) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestPageURL())); EXPECT_TRUE(NavigateToURL(shell(), GetTestPageURL()));
DirectSocketsServiceImpl::SetPermissionCallbackForTesting( DirectSocketsServiceImpl::SetPermissionCallbackForTesting(
base::BindLambdaForTesting( base::BindRepeating(&UnconditionallyPermitConnection));
[&](const blink::mojom::DirectSocketOptions&) { return net::OK; }));
// TODO(crbug.com/905818): Use port from a listening net::TCPServerSocket. const uint16_t listening_port = StartTcpServer();
const std::string script = base::StringPrintf( const std::string script = base::StringPrintf(
"openTcp({remoteAddress: '127.0.0.1', remotePort: %d})", 0); "openTcp({remoteAddress: '127.0.0.1', remotePort: %d})", listening_port);
EXPECT_EQ("openTcp succeeded", EvalJs(shell(), script)); EXPECT_EQ("openTcp succeeded", EvalJs(shell(), script));
} }
...@@ -58,9 +165,9 @@ IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, OpenTcp_Success) { ...@@ -58,9 +165,9 @@ IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, OpenTcp_Success) {
IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, OpenTcp_NotAllowedError) { IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, OpenTcp_NotAllowedError) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestPageURL())); EXPECT_TRUE(NavigateToURL(shell(), GetTestPageURL()));
// TODO(crbug.com/905818): Use port from a listening net::TCPServerSocket. const uint16_t listening_port = StartTcpServer();
const std::string script = base::StringPrintf( const std::string script = base::StringPrintf(
"openTcp({remoteAddress: '127.0.0.1', remotePort: %d})", 0); "openTcp({remoteAddress: '127.0.0.1', remotePort: %d})", listening_port);
EXPECT_EQ("openTcp failed: NotAllowedError: Permission denied", EXPECT_EQ("openTcp failed: NotAllowedError: Permission denied",
EvalJs(shell(), script)); EvalJs(shell(), script));
...@@ -77,12 +184,79 @@ IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, OpenTcp_CannotEvadeCors) { ...@@ -77,12 +184,79 @@ IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, OpenTcp_CannotEvadeCors) {
EvalJs(shell(), script)); EvalJs(shell(), script));
} }
IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, OpenUdp_Success) { // TODO(crbug.com/1141241): Resolve failures on linux-bfcache-rel bots.
IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, DISABLED_OpenTcp_OptionsOne) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestPageURL()));
DirectSocketsServiceImpl::SetPermissionCallbackForTesting(
base::BindRepeating(&UnconditionallyPermitConnection));
MockNetworkContext mock_network_context(net::ERR_PROXY_CONNECTION_FAILED);
DirectSocketsServiceImpl::SetNetworkContextForTesting(&mock_network_context);
const std::string expected_result =
"openTcp failed: NotAllowedError: Permission denied";
const std::string script =
R"(
openTcp({
remoteAddress: '12.34.56.78',
remotePort: 9012,
sendBufferSize: 3456,
receiveBufferSize: 7890,
noDelay: false
})
)";
EXPECT_EQ(expected_result, EvalJs(shell(), script));
DCHECK_EQ(1U, mock_network_context.history().size());
const RecordedCall& call = mock_network_context.history()[0];
EXPECT_EQ(ProtocolType::kTcp, call.protocol_type);
EXPECT_EQ("12.34.56.78", call.remote_address);
EXPECT_EQ(9012, call.remote_port);
EXPECT_EQ(3456, call.send_buffer_size);
EXPECT_EQ(7890, call.receive_buffer_size);
EXPECT_EQ(false, call.no_delay);
}
// TODO(crbug.com/1141241): Resolve failures on linux-bfcache-rel bots.
IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, DISABLED_OpenTcp_OptionsTwo) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestPageURL()));
DirectSocketsServiceImpl::SetPermissionCallbackForTesting(
base::BindRepeating(&UnconditionallyPermitConnection));
MockNetworkContext mock_network_context(net::OK);
DirectSocketsServiceImpl::SetNetworkContextForTesting(&mock_network_context);
const std::string expected_result = "openTcp succeeded";
const std::string script =
R"(
openTcp({
remoteAddress: 'fedc:ba98:7654:3210:fedc:ba98:7654:3210',
remotePort: 789,
sendBufferSize: 0,
receiveBufferSize: 1234,
noDelay: true
})
)";
EXPECT_EQ(expected_result, EvalJs(shell(), script));
DCHECK_EQ(1U, mock_network_context.history().size());
const RecordedCall& call = mock_network_context.history()[0];
EXPECT_EQ(ProtocolType::kTcp, call.protocol_type);
EXPECT_EQ("fedc:ba98:7654:3210:fedc:ba98:7654:3210", call.remote_address);
EXPECT_EQ(789, call.remote_port);
EXPECT_EQ(0, call.send_buffer_size);
EXPECT_EQ(1234, call.receive_buffer_size);
EXPECT_EQ(true, call.no_delay);
}
// TODO(crbug.com/1141241): Resolve failures on linux-bfcache-rel bots.
IN_PROC_BROWSER_TEST_F(DirectSocketsBrowserTest, DISABLED_OpenUdp_Success) {
EXPECT_TRUE(NavigateToURL(shell(), GetTestPageURL())); EXPECT_TRUE(NavigateToURL(shell(), GetTestPageURL()));
DirectSocketsServiceImpl::SetPermissionCallbackForTesting( DirectSocketsServiceImpl::SetPermissionCallbackForTesting(
base::BindLambdaForTesting( base::BindRepeating(&UnconditionallyPermitConnection));
[&](const blink::mojom::DirectSocketOptions&) { return net::OK; }));
// TODO(crbug.com/1119620): Use port from a listening net::UDPServerSocket. // TODO(crbug.com/1119620): Use port from a listening net::UDPServerSocket.
const std::string script = base::StringPrintf( const std::string script = base::StringPrintf(
......
...@@ -14,11 +14,16 @@ ...@@ -14,11 +14,16 @@
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h" #include "content/public/common/content_features.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/address_list.h"
#include "services/network/public/mojom/network_context.mojom.h"
namespace content { namespace content {
namespace { namespace {
constexpr int32_t kMaxBufferSize = 32 * 1024 * 1024;
DirectSocketsServiceImpl::PermissionCallback& DirectSocketsServiceImpl::PermissionCallback&
GetPermissionCallbackForTesting() { GetPermissionCallbackForTesting() {
static base::NoDestructor<DirectSocketsServiceImpl::PermissionCallback> static base::NoDestructor<DirectSocketsServiceImpl::PermissionCallback>
...@@ -26,6 +31,11 @@ GetPermissionCallbackForTesting() { ...@@ -26,6 +31,11 @@ GetPermissionCallbackForTesting() {
return *callback; return *callback;
} }
network::mojom::NetworkContext*& GetNetworkContextForTesting() {
static network::mojom::NetworkContext* network_context = nullptr;
return network_context;
}
} // namespace } // namespace
DirectSocketsServiceImpl::DirectSocketsServiceImpl(RenderFrameHost& frame_host) DirectSocketsServiceImpl::DirectSocketsServiceImpl(RenderFrameHost& frame_host)
...@@ -44,42 +54,71 @@ void DirectSocketsServiceImpl::CreateForFrame( ...@@ -44,42 +54,71 @@ void DirectSocketsServiceImpl::CreateForFrame(
void DirectSocketsServiceImpl::OpenTcpSocket( void DirectSocketsServiceImpl::OpenTcpSocket(
blink::mojom::DirectSocketOptionsPtr options, blink::mojom::DirectSocketOptionsPtr options,
const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
mojo::PendingReceiver<network::mojom::TCPConnectedSocket> receiver,
mojo::PendingRemote<network::mojom::SocketObserver> observer,
OpenTcpSocketCallback callback) { OpenTcpSocketCallback callback) {
if (!options) { if (!options) {
mojo::ReportBadMessage("Invalid request to open socket"); mojo::ReportBadMessage("Invalid request to open socket");
return; return;
} }
net::Error result = EnsurePermission(*options); net::IPAddress remote_address;
const net::Error result = ValidateOptions(*options, remote_address);
// TODO(crbug.com/1119681): Collect metrics for usage and permission checks // TODO(crbug.com/1119681): Collect metrics for usage and permission checks
if (result == net::OK) { if (result != net::OK) {
// TODO(crbug.com/905818): GetNetworkContext()->CreateTCPConnectedSocket std::move(callback).Run(result, base::nullopt, base::nullopt,
GetNetworkContext(); mojo::ScopedDataPipeConsumerHandle(),
NOTIMPLEMENTED(); mojo::ScopedDataPipeProducerHandle());
return;
} }
std::move(callback).Run(result); // TODO(crbug.com/905818): Populate local_addr from options.
const base::Optional<net::IPEndPoint> local_addr = base::nullopt;
network::mojom::TCPConnectedSocketOptionsPtr tcp_connected_socket_options =
network::mojom::TCPConnectedSocketOptions::New();
if (options->send_buffer_size > 0) {
tcp_connected_socket_options->send_buffer_size =
std::min(options->send_buffer_size, kMaxBufferSize);
}
if (options->receive_buffer_size > 0) {
tcp_connected_socket_options->receive_buffer_size =
std::min(options->receive_buffer_size, kMaxBufferSize);
}
tcp_connected_socket_options->no_delay = options->no_delay;
GetNetworkContext()->CreateTCPConnectedSocket(
local_addr,
net::AddressList::CreateFromIPAddress(remote_address,
options->remote_port),
std::move(tcp_connected_socket_options), traffic_annotation,
std::move(receiver), std::move(observer), std::move(callback));
} }
void DirectSocketsServiceImpl::OpenUdpSocket( void DirectSocketsServiceImpl::OpenUdpSocket(
blink::mojom::DirectSocketOptionsPtr options, blink::mojom::DirectSocketOptionsPtr options,
mojo::PendingReceiver<network::mojom::UDPSocket> receiver,
mojo::PendingRemote<network::mojom::UDPSocketListener> listener,
OpenUdpSocketCallback callback) { OpenUdpSocketCallback callback) {
if (!options) { if (!options) {
mojo::ReportBadMessage("Invalid request to open socket"); mojo::ReportBadMessage("Invalid request to open socket");
return; return;
} }
net::Error result = EnsurePermission(*options); net::IPAddress remote_address;
const net::Error result = ValidateOptions(*options, remote_address);
// TODO(crbug.com/1119681): Collect metrics for usage and permission checks // TODO(crbug.com/1119681): Collect metrics for usage and permission checks
if (result == net::OK) { if (result == net::OK) {
// TODO(crbug.com/1119620): GetNetworkContext()->CreateUDPSocket // TODO(crbug.com/1119620): GetNetworkContext()->CreateUDPSocket
// TODO(crbug.com/1119620): Connect(remote_addr, udp_socket_options)
GetNetworkContext(); GetNetworkContext();
NOTIMPLEMENTED(); NOTIMPLEMENTED();
} }
std::move(callback).Run(result); std::move(callback).Run(result, base::nullopt, base::nullopt);
} }
// static // static
...@@ -88,6 +127,12 @@ void DirectSocketsServiceImpl::SetPermissionCallbackForTesting( ...@@ -88,6 +127,12 @@ void DirectSocketsServiceImpl::SetPermissionCallbackForTesting(
GetPermissionCallbackForTesting() = std::move(callback); GetPermissionCallbackForTesting() = std::move(callback);
} }
// static
void DirectSocketsServiceImpl::SetNetworkContextForTesting(
network::mojom::NetworkContext* network_context) {
GetNetworkContextForTesting() = network_context;
}
void DirectSocketsServiceImpl::RenderFrameDeleted( void DirectSocketsServiceImpl::RenderFrameDeleted(
RenderFrameHost* render_frame_host) { RenderFrameHost* render_frame_host) {
if (render_frame_host == frame_host_) if (render_frame_host == frame_host_)
...@@ -98,15 +143,16 @@ void DirectSocketsServiceImpl::WebContentsDestroyed() { ...@@ -98,15 +143,16 @@ void DirectSocketsServiceImpl::WebContentsDestroyed() {
frame_host_ = nullptr; frame_host_ = nullptr;
} }
net::Error DirectSocketsServiceImpl::EnsurePermission( net::Error DirectSocketsServiceImpl::ValidateOptions(
const blink::mojom::DirectSocketOptions& options) { const blink::mojom::DirectSocketOptions& options,
net::IPAddress& remote_address) {
DCHECK(base::FeatureList::IsEnabled(features::kDirectSockets)); DCHECK(base::FeatureList::IsEnabled(features::kDirectSockets));
if (!frame_host_) if (!frame_host_)
return net::ERR_CONTEXT_SHUT_DOWN; return net::ERR_CONTEXT_SHUT_DOWN;
if (GetPermissionCallbackForTesting()) if (GetPermissionCallbackForTesting())
return GetPermissionCallbackForTesting().Run(options); return GetPermissionCallbackForTesting().Run(options, remote_address);
if (options.send_buffer_size < 0 || options.receive_buffer_size < 0) if (options.send_buffer_size < 0 || options.receive_buffer_size < 0)
return net::ERR_INVALID_ARGUMENT; return net::ERR_INVALID_ARGUMENT;
...@@ -120,15 +166,28 @@ net::Error DirectSocketsServiceImpl::EnsurePermission( ...@@ -120,15 +166,28 @@ net::Error DirectSocketsServiceImpl::EnsurePermission(
return net::ERR_UNSAFE_PORT; return net::ERR_UNSAFE_PORT;
} }
// EnsurePermission() will need to become asynchronous: // ValidateOptions() will need to become asynchronous:
// TODO(crbug.com/1119597): Show consent dialog // TODO(crbug.com/1119597): Show connection dialog.
// TODO(crbug.com/1119597): Use the hostname provided by the user.
// TODO(crbug.com/1119661): Reject hostnames that resolve to non-public // TODO(crbug.com/1119661): Reject hostnames that resolve to non-public
// addresses. // addresses.
if (!options.remote_hostname)
return net::ERR_NAME_NOT_RESOLVED;
// TODO(crbug.com/905818): Support resolved hostnames.
// TODO(crbug.com/1124255): Support mDNS.
if (!remote_address.AssignFromIPLiteral(*options.remote_hostname))
return net::ERR_NAME_NOT_RESOLVED;
return net::ERR_NOT_IMPLEMENTED; return net::ERR_NOT_IMPLEMENTED;
} }
network::mojom::NetworkContext* DirectSocketsServiceImpl::GetNetworkContext() { network::mojom::NetworkContext* DirectSocketsServiceImpl::GetNetworkContext() {
if (network::mojom::NetworkContext* network_context =
GetNetworkContextForTesting()) {
return network_context;
}
return frame_host_->GetStoragePartition()->GetNetworkContext(); return frame_host_->GetStoragePartition()->GetNetworkContext();
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_receiver.h"
#include "net/base/ip_address.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom.h" #include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom.h"
...@@ -28,8 +29,8 @@ class CONTENT_EXPORT DirectSocketsServiceImpl ...@@ -28,8 +29,8 @@ class CONTENT_EXPORT DirectSocketsServiceImpl
: public blink::mojom::DirectSocketsService, : public blink::mojom::DirectSocketsService,
public WebContentsObserver { public WebContentsObserver {
public: public:
using PermissionCallback = base::RepeatingCallback<net::Error( using PermissionCallback = base::RepeatingCallback<
const blink::mojom::DirectSocketOptions&)>; net::Error(const blink::mojom::DirectSocketOptions&, net::IPAddress&)>;
explicit DirectSocketsServiceImpl(RenderFrameHost& frame_host); explicit DirectSocketsServiceImpl(RenderFrameHost& frame_host);
~DirectSocketsServiceImpl() override = default; ~DirectSocketsServiceImpl() override = default;
...@@ -42,10 +43,17 @@ class CONTENT_EXPORT DirectSocketsServiceImpl ...@@ -42,10 +43,17 @@ class CONTENT_EXPORT DirectSocketsServiceImpl
mojo::PendingReceiver<blink::mojom::DirectSocketsService> receiver); mojo::PendingReceiver<blink::mojom::DirectSocketsService> receiver);
// blink::mojom::DirectSocketsService override: // blink::mojom::DirectSocketsService override:
void OpenTcpSocket(blink::mojom::DirectSocketOptionsPtr options, void OpenTcpSocket(
OpenTcpSocketCallback callback) override; blink::mojom::DirectSocketOptionsPtr options,
void OpenUdpSocket(blink::mojom::DirectSocketOptionsPtr options, const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
OpenUdpSocketCallback callback) override; mojo::PendingReceiver<network::mojom::TCPConnectedSocket> socket,
mojo::PendingRemote<network::mojom::SocketObserver> observer,
OpenTcpSocketCallback callback) override;
void OpenUdpSocket(
blink::mojom::DirectSocketOptionsPtr options,
mojo::PendingReceiver<network::mojom::UDPSocket> receiver,
mojo::PendingRemote<network::mojom::UDPSocketListener> listener,
OpenUdpSocketCallback callback) override;
// WebContentsObserver override: // WebContentsObserver override:
void RenderFrameDeleted(RenderFrameHost* render_frame_host) override; void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
...@@ -53,10 +61,15 @@ class CONTENT_EXPORT DirectSocketsServiceImpl ...@@ -53,10 +61,15 @@ class CONTENT_EXPORT DirectSocketsServiceImpl
static void SetPermissionCallbackForTesting(PermissionCallback callback); static void SetPermissionCallbackForTesting(PermissionCallback callback);
static void SetNetworkContextForTesting(network::mojom::NetworkContext*);
private: private:
friend class DirectSocketsUnitTest; friend class DirectSocketsUnitTest;
net::Error EnsurePermission(const blink::mojom::DirectSocketOptions& options); // Returns net::OK and populates |remote_address| if the options are valid and
// the connection is permitted.
net::Error ValidateOptions(const blink::mojom::DirectSocketOptions& options,
net::IPAddress& remote_address);
network::mojom::NetworkContext* GetNetworkContext(); network::mojom::NetworkContext* GetNetworkContext();
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "content/browser/direct_sockets/direct_sockets_service_impl.h" #include "content/browser/direct_sockets/direct_sockets_service_impl.h"
#include "content/public/common/content_features.h" #include "content/public/common/content_features.h"
#include "content/public/test/test_renderer_host.h" #include "content/public/test/test_renderer_host.h"
#include "net/base/ip_address.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom.h" #include "third_party/blink/public/mojom/direct_sockets/direct_sockets.mojom.h"
...@@ -30,9 +31,9 @@ class DirectSocketsUnitTest : public RenderViewHostTestHarness { ...@@ -30,9 +31,9 @@ class DirectSocketsUnitTest : public RenderViewHostTestHarness {
return *direct_sockets_service_; return *direct_sockets_service_;
} }
net::Error EnsurePermission( net::Error ValidateOptions(const blink::mojom::DirectSocketOptions& options) {
const blink::mojom::DirectSocketOptions& options) { net::IPAddress remote_address;
return direct_sockets_service().EnsurePermission(options); return direct_sockets_service().ValidateOptions(options, remote_address);
} }
private: private:
...@@ -44,14 +45,20 @@ TEST_F(DirectSocketsUnitTest, RenderFrameDeleted) { ...@@ -44,14 +45,20 @@ TEST_F(DirectSocketsUnitTest, RenderFrameDeleted) {
direct_sockets_service().RenderFrameDeleted(main_rfh()); direct_sockets_service().RenderFrameDeleted(main_rfh());
blink::mojom::DirectSocketOptions options; blink::mojom::DirectSocketOptions options;
EXPECT_EQ(EnsurePermission(options), net::ERR_CONTEXT_SHUT_DOWN); EXPECT_EQ(ValidateOptions(options), net::ERR_CONTEXT_SHUT_DOWN);
} }
TEST_F(DirectSocketsUnitTest, WebContentsDestroyed) { TEST_F(DirectSocketsUnitTest, WebContentsDestroyed) {
direct_sockets_service().WebContentsDestroyed(); direct_sockets_service().WebContentsDestroyed();
blink::mojom::DirectSocketOptions options; blink::mojom::DirectSocketOptions options;
EXPECT_EQ(EnsurePermission(options), net::ERR_CONTEXT_SHUT_DOWN); EXPECT_EQ(ValidateOptions(options), net::ERR_CONTEXT_SHUT_DOWN);
}
// TODO(crbug.com/1119597): Allow the user to enter the address.
TEST_F(DirectSocketsUnitTest, RemoteAddressCurrentlyRequired) {
blink::mojom::DirectSocketOptions options;
EXPECT_EQ(ValidateOptions(options), net::ERR_NAME_NOT_RESOLVED);
} }
} // namespace content } // namespace content
...@@ -47,7 +47,6 @@ mojom("mojom_platform") { ...@@ -47,7 +47,6 @@ mojom("mojom_platform") {
"devtools/devtools_agent.mojom", "devtools/devtools_agent.mojom",
"devtools/devtools_frontend.mojom", "devtools/devtools_frontend.mojom",
"devtools/inspector_issue.mojom", "devtools/inspector_issue.mojom",
"direct_sockets/direct_sockets.mojom",
"disk_allocator.mojom", "disk_allocator.mojom",
"favicon/favicon_url.mojom", "favicon/favicon_url.mojom",
"feature_observer/feature_observer.mojom", "feature_observer/feature_observer.mojom",
...@@ -249,7 +248,10 @@ mojom("mojom_platform") { ...@@ -249,7 +248,10 @@ mojom("mojom_platform") {
"//ui/latency/mojom", "//ui/latency/mojom",
] ]
} else { } else {
sources += [ "serial/serial.mojom" ] sources += [
"direct_sockets/direct_sockets.mojom",
"serial/serial.mojom",
]
} }
if (is_mac) { if (is_mac) {
......
...@@ -7,6 +7,11 @@ module blink.mojom; ...@@ -7,6 +7,11 @@ module blink.mojom;
// Explainer for the Direct Sockets API: // Explainer for the Direct Sockets API:
// https://github.com/WICG/raw-sockets/blob/master/docs/explainer.md // https://github.com/WICG/raw-sockets/blob/master/docs/explainer.md
import "services/network/public/mojom/ip_endpoint.mojom";
import "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom";
import "services/network/public/mojom/tcp_socket.mojom";
import "services/network/public/mojom/udp_socket.mojom";
struct DirectSocketOptions { struct DirectSocketOptions {
string? local_hostname; string? local_hostname;
uint16 local_port = 0; uint16 local_port = 0;
...@@ -17,8 +22,7 @@ struct DirectSocketOptions { ...@@ -17,8 +22,7 @@ struct DirectSocketOptions {
int32 send_buffer_size = 0; int32 send_buffer_size = 0;
int32 receive_buffer_size = 0; int32 receive_buffer_size = 0;
// These are only relevant for TCP: // Only relevant for TCP:
bool keep_alive = false;
bool no_delay = false; bool no_delay = false;
}; };
...@@ -26,15 +30,32 @@ struct DirectSocketOptions { ...@@ -26,15 +30,32 @@ struct DirectSocketOptions {
// permission checking, chooser showing, etc. // permission checking, chooser showing, etc.
// The browser process implements the interface, and the renderer process // The browser process implements the interface, and the renderer process
// sends messages to it. // sends messages to it.
// The return values are net::Error codes. 0 indicates success.
interface DirectSocketsService { interface DirectSocketsService {
// TODO(crbug.com/905818): Return TCP socket details // Creates a connected TCP socket.
// |result| is a net::Error code (net::OK on success).
// |observer| if non-null will be used to listen for any network connection
// error on the newly established connection.
// Caller is to use |send_stream| to send data and |receive_stream|
// to receive data over the connection.
OpenTcpSocket( OpenTcpSocket(
DirectSocketOptions options) DirectSocketOptions options,
=> (int32 result); network.mojom.MutableNetworkTrafficAnnotationTag traffic_annotation,
pending_receiver<network.mojom.TCPConnectedSocket> receiver,
// TODO(crbug.com/1119620): Return UDP socket details pending_remote<network.mojom.SocketObserver>? observer)
=> (int32 result,
network.mojom.IPEndPoint? local_addr,
network.mojom.IPEndPoint? peer_addr,
handle<data_pipe_consumer>? receive_stream,
handle<data_pipe_producer>? send_stream);
// Creates a 'connected' UDP socket.
// |result| is a net::Error code (net::OK on success).
// Caller can supply a |listener| to listen for incoming datagrams.
OpenUdpSocket( OpenUdpSocket(
DirectSocketOptions options) DirectSocketOptions options,
=> (int32 result); pending_receiver<network.mojom.UDPSocket> receiver,
pending_remote<network.mojom.UDPSocketListener>? listener)
=> (int32 result,
network.mojom.IPEndPoint? local_addr,
network.mojom.IPEndPoint? peer_addr);
}; };
...@@ -745,8 +745,6 @@ generated_dictionary_sources_in_modules = [ ...@@ -745,8 +745,6 @@ generated_dictionary_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_sensor_options.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_sensor_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_share_data.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_share_data.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_share_data.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_share_data.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_socket_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_socket_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_spatial_sensor_options.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_spatial_sensor_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_spatial_sensor_options.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_spatial_sensor_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_speech_recognition_error_event_init.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_speech_recognition_error_event_init.cc",
...@@ -2219,7 +2217,7 @@ generated_interface_sources_in_modules = [ ...@@ -2219,7 +2217,7 @@ generated_interface_sources_in_modules = [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_world_tracking_state.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_xr_world_tracking_state.h",
] ]
# Serial # Serial and Direct Sockets
if (!is_android) { if (!is_android) {
generated_dictionary_sources_in_modules += [ generated_dictionary_sources_in_modules += [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_connection_event_init.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_connection_event_init.cc",
...@@ -2236,6 +2234,8 @@ if (!is_android) { ...@@ -2236,6 +2234,8 @@ if (!is_android) {
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_port_info.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_port_info.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_port_request_options.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_port_request_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_port_request_options.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_port_request_options.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_socket_options.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_socket_options.h",
] ]
generated_enumeration_sources_in_modules += [ generated_enumeration_sources_in_modules += [
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_flow_control_type.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_flow_control_type.cc",
...@@ -2250,6 +2250,10 @@ if (!is_android) { ...@@ -2250,6 +2250,10 @@ if (!is_android) {
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_connection_event.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_connection_event.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_port.cc", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_port.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_port.h", "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_serial_port.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_tcp_socket.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_tcp_socket.h",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_udp_socket.cc",
"$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_udp_socket.h",
] ]
} }
......
...@@ -175,8 +175,6 @@ static_idl_files_in_modules = get_path_info( ...@@ -175,8 +175,6 @@ static_idl_files_in_modules = get_path_info(
"//third_party/blink/renderer/modules/device_orientation/device_orientation_event_init.idl", "//third_party/blink/renderer/modules/device_orientation/device_orientation_event_init.idl",
"//third_party/blink/renderer/modules/device_orientation/window_device_motion.idl", "//third_party/blink/renderer/modules/device_orientation/window_device_motion.idl",
"//third_party/blink/renderer/modules/device_orientation/window_device_orientation.idl", "//third_party/blink/renderer/modules/device_orientation/window_device_orientation.idl",
"//third_party/blink/renderer/modules/direct_sockets/navigator_socket.idl",
"//third_party/blink/renderer/modules/direct_sockets/socket_options.idl",
"//third_party/blink/renderer/modules/donottrack/navigator_do_not_track.idl", "//third_party/blink/renderer/modules/donottrack/navigator_do_not_track.idl",
"//third_party/blink/renderer/modules/encoding/text_decode_options.idl", "//third_party/blink/renderer/modules/encoding/text_decode_options.idl",
"//third_party/blink/renderer/modules/encoding/text_decoder.idl", "//third_party/blink/renderer/modules/encoding/text_decoder.idl",
...@@ -1021,10 +1019,14 @@ static_idl_files_in_modules = get_path_info( ...@@ -1021,10 +1019,14 @@ static_idl_files_in_modules = get_path_info(
], ],
"abspath") "abspath")
# Serial # Serial and Direct Sockets
if (!is_android) { if (!is_android) {
static_idl_files_in_modules += get_path_info( static_idl_files_in_modules += get_path_info(
[ [
"//third_party/blink/renderer/modules/direct_sockets/navigator_socket.idl",
"//third_party/blink/renderer/modules/direct_sockets/tcp_socket.idl",
"//third_party/blink/renderer/modules/direct_sockets/udp_socket.idl",
"//third_party/blink/renderer/modules/direct_sockets/socket_options.idl",
"//third_party/blink/renderer/modules/serial/navigator_serial.idl", "//third_party/blink/renderer/modules/serial/navigator_serial.idl",
"//third_party/blink/renderer/modules/serial/serial.idl", "//third_party/blink/renderer/modules/serial/serial.idl",
"//third_party/blink/renderer/modules/serial/serial_connection_event.idl", "//third_party/blink/renderer/modules/serial/serial_connection_event.idl",
......
...@@ -136,7 +136,6 @@ component("modules") { ...@@ -136,7 +136,6 @@ component("modules") {
"//third_party/blink/renderer/modules/presentation", "//third_party/blink/renderer/modules/presentation",
"//third_party/blink/renderer/modules/push_messaging", "//third_party/blink/renderer/modules/push_messaging",
"//third_party/blink/renderer/modules/quota", "//third_party/blink/renderer/modules/quota",
"//third_party/blink/renderer/modules/direct_sockets",
"//third_party/blink/renderer/modules/remoteplayback", "//third_party/blink/renderer/modules/remoteplayback",
"//third_party/blink/renderer/modules/sanitizer_api", "//third_party/blink/renderer/modules/sanitizer_api",
"//third_party/blink/renderer/modules/scheduler", "//third_party/blink/renderer/modules/scheduler",
...@@ -169,7 +168,10 @@ component("modules") { ...@@ -169,7 +168,10 @@ component("modules") {
if (is_android) { if (is_android) {
sub_modules += [ "//third_party/blink/renderer/modules/remote_objects" ] sub_modules += [ "//third_party/blink/renderer/modules/remote_objects" ]
} else { } else {
sub_modules += [ "//third_party/blink/renderer/modules/serial" ] sub_modules += [
"//third_party/blink/renderer/modules/direct_sockets",
"//third_party/blink/renderer/modules/serial",
]
} }
deps = [ deps = [
......
...@@ -4,6 +4,7 @@ include_rules = [ ...@@ -4,6 +4,7 @@ include_rules = [
"+base/strings/char_traits.h", "+base/strings/char_traits.h",
"+mojo/public/cpp/bindings", "+mojo/public/cpp/bindings",
"+mojo/public/cpp/system", "+mojo/public/cpp/system",
"+net/base/net_errors.h",
"+services/device/public/mojom", "+services/device/public/mojom",
"+services/network/public/cpp/shared_url_loader_factory.h", "+services/network/public/cpp/shared_url_loader_factory.h",
"+services/viz/public/mojom/hit_test/hit_test_region_list.mojom-blink.h", "+services/viz/public/mojom/hit_test/hit_test_region_list.mojom-blink.h",
......
...@@ -8,5 +8,10 @@ blink_modules_sources("direct_sockets") { ...@@ -8,5 +8,10 @@ blink_modules_sources("direct_sockets") {
sources = [ sources = [
"navigator_socket.cc", "navigator_socket.cc",
"navigator_socket.h", "navigator_socket.h",
"tcp_socket.cc",
"tcp_socket.h",
"udp_socket.cc",
"udp_socket.h",
] ]
deps = [ "//net:net" ]
} }
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
modules_idl_files = [
"tcp_socket.idl",
"udp_socket.idl",
]
modules_dictionary_idl_files = [ "socket_options.idl" ] modules_dictionary_idl_files = [ "socket_options.idl" ]
modules_dependency_idl_files = [ "navigator_socket.idl" ] modules_dependency_idl_files = [ "navigator_socket.idl" ]
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
#include "third_party/blink/renderer/modules/direct_sockets/navigator_socket.h" #include "third_party/blink/renderer/modules/direct_sockets/navigator_socket.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h"
#include "services/network/public/mojom/tcp_socket.mojom-blink.h"
#include "services/network/public/mojom/udp_socket.mojom-blink.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h" #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/task_type.h" #include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
...@@ -18,84 +21,26 @@ ...@@ -18,84 +21,26 @@
#include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/persistent.h" #include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
#include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink { namespace blink {
class NavigatorSocket::PendingRequest final constexpr net::NetworkTrafficAnnotationTag kDirectSocketsTrafficAnnotation =
: public GarbageCollected<PendingRequest> { net::DefineNetworkTrafficAnnotation("direct_sockets", R"(
public: semantics {
PendingRequest(NavigatorSocket&, ScriptPromiseResolver&); sender: "Direct Sockets API"
description: "Web app request to communicate with network device"
// TODO(crbug.com/905818): Resolve Promise<TCPSocket> trigger: "User completes network connection dialog"
void TcpCallback(int32_t result); data: "Any data sent by web app"
destination: OTHER
// TODO(crbug.com/1119620): Resolve Promise<UDPSocket> destination_other: "Address entered by user in connection dialog"
void UdpCallback(int32_t result); }
policy {
void OnConnectionError(); cookies_allowed: NO
setting: "This feature cannot yet be controlled by settings."
void Trace(Visitor* visitor) const { policy_exception_justification: "To be implemented"
visitor->Trace(navigator_); }
visitor->Trace(resolver_); )");
}
private:
WeakMember<NavigatorSocket> navigator_;
Member<ScriptPromiseResolver> resolver_;
FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle
feature_handle_for_scheduler_;
};
NavigatorSocket::PendingRequest::PendingRequest(
NavigatorSocket& navigator_socket,
ScriptPromiseResolver& resolver)
: navigator_(&navigator_socket),
resolver_(&resolver),
feature_handle_for_scheduler_(
ExecutionContext::From(resolver_->GetScriptState())
->GetScheduler()
->RegisterFeature(
SchedulingPolicy::Feature::
kOutstandingNetworkRequestDirectSocket,
{SchedulingPolicy::RecordMetricsForBackForwardCache()})) {}
void NavigatorSocket::PendingRequest::TcpCallback(int32_t result) {
if (navigator_)
navigator_->pending_requests_.erase(this);
// TODO(crbug.com/905818): Compare with net::OK
if (result == 0) {
// TODO(crbug.com/905818): Resolve TCPSocket
NOTIMPLEMENTED();
resolver_->Resolve();
} else {
resolver_->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotAllowedError, "Permission denied"));
}
}
void NavigatorSocket::PendingRequest::UdpCallback(int32_t result) {
if (navigator_)
navigator_->pending_requests_.erase(this);
// TODO(crbug.com/1119620): Compare with net::OK
if (result == 0) {
// TODO(crbug.com/1119620): Resolve UDPSocket
NOTIMPLEMENTED();
resolver_->Resolve();
} else {
resolver_->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotAllowedError, "Permission denied"));
}
}
void NavigatorSocket::PendingRequest::OnConnectionError() {
resolver_->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kAbortError,
"Internal error: could not connect to DirectSocketsService interface."));
}
const char NavigatorSocket::kSupplementName[] = "NavigatorSocket"; const char NavigatorSocket::kSupplementName[] = "NavigatorSocket";
...@@ -136,14 +81,16 @@ void NavigatorSocket::ContextDestroyed() {} ...@@ -136,14 +81,16 @@ void NavigatorSocket::ContextDestroyed() {}
void NavigatorSocket::ContextLifecycleStateChanged( void NavigatorSocket::ContextLifecycleStateChanged(
mojom::blink::FrameLifecycleState state) { mojom::blink::FrameLifecycleState state) {
// TODO(crbug.com/1120868) close connections when the lifecycle state is not if (state == mojom::blink::FrameLifecycleState::kFrozen) {
// "active". // Clear service_remote_ and pending connections.
NOTIMPLEMENTED(); OnConnectionError();
}
} }
void NavigatorSocket::Trace(Visitor* visitor) const { void NavigatorSocket::Trace(Visitor* visitor) const {
visitor->Trace(service_remote_); visitor->Trace(service_remote_);
visitor->Trace(pending_requests_); visitor->Trace(pending_tcp_);
visitor->Trace(pending_udp_);
Supplement<ExecutionContext>::Trace(visitor); Supplement<ExecutionContext>::Trace(visitor);
ExecutionContextLifecycleStateObserver::Trace(visitor); ExecutionContextLifecycleStateObserver::Trace(visitor);
} }
...@@ -181,8 +128,6 @@ mojom::blink::DirectSocketOptionsPtr NavigatorSocket::CreateSocketOptions( ...@@ -181,8 +128,6 @@ mojom::blink::DirectSocketOptionsPtr NavigatorSocket::CreateSocketOptions(
if (options.hasReceiveBufferSize()) if (options.hasReceiveBufferSize())
socket_options->receive_buffer_size = options.receiveBufferSize(); socket_options->receive_buffer_size = options.receiveBufferSize();
if (options.hasKeepAlive())
socket_options->keep_alive = options.keepAlive();
if (options.hasNoDelay()) if (options.hasNoDelay())
socket_options->no_delay = options.noDelay(); socket_options->no_delay = options.noDelay();
...@@ -196,14 +141,16 @@ ScriptPromise NavigatorSocket::openTCPSocket(ScriptState* script_state, ...@@ -196,14 +141,16 @@ ScriptPromise NavigatorSocket::openTCPSocket(ScriptState* script_state,
return ScriptPromise(); return ScriptPromise();
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
PendingRequest* pending = TCPSocket* pending = MakeGarbageCollected<TCPSocket>(*resolver);
MakeGarbageCollected<PendingRequest>(*this, *resolver); pending_tcp_.insert(pending);
pending_requests_.insert(pending);
ScriptPromise promise = resolver->Promise(); ScriptPromise promise = resolver->Promise();
service_remote_->OpenTcpSocket( service_remote_->OpenTcpSocket(
CreateSocketOptions(*options), CreateSocketOptions(*options),
WTF::Bind(&PendingRequest::TcpCallback, WrapPersistent(pending))); net::MutableNetworkTrafficAnnotationTag(kDirectSocketsTrafficAnnotation),
pending->GetTCPSocketReceiver(), pending->GetTCPSocketObserver(),
WTF::Bind(&NavigatorSocket::OnTcpOpen, WrapPersistent(this),
WrapPersistent(pending)));
return promise; return promise;
} }
...@@ -214,20 +161,22 @@ ScriptPromise NavigatorSocket::openUDPSocket(ScriptState* script_state, ...@@ -214,20 +161,22 @@ ScriptPromise NavigatorSocket::openUDPSocket(ScriptState* script_state,
return ScriptPromise(); return ScriptPromise();
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
PendingRequest* pending = UDPSocket* pending = MakeGarbageCollected<UDPSocket>(*resolver);
MakeGarbageCollected<PendingRequest>(*this, *resolver); pending_udp_.insert(pending);
pending_requests_.insert(pending);
ScriptPromise promise = resolver->Promise(); ScriptPromise promise = resolver->Promise();
service_remote_->OpenUdpSocket( service_remote_->OpenUdpSocket(
CreateSocketOptions(*options), CreateSocketOptions(*options), pending->GetUDPSocketReceiver(),
WTF::Bind(&PendingRequest::UdpCallback, WrapPersistent(pending))); pending->GetUDPSocketListener(),
WTF::Bind(&NavigatorSocket::OnUdpOpen, WrapPersistent(this),
WrapPersistent(pending)));
return promise; return promise;
} }
bool NavigatorSocket::OpenSocketPermitted(ScriptState* script_state, bool NavigatorSocket::OpenSocketPermitted(ScriptState* script_state,
const SocketOptions* options, const SocketOptions* options,
ExceptionState& exception_state) { ExceptionState& exception_state) {
DCHECK_EQ(ExecutionContext::From(script_state), GetExecutionContext());
LocalDOMWindow* const window = script_state->ContextIsValid() LocalDOMWindow* const window = script_state->ContextIsValid()
? LocalDOMWindow::From(script_state) ? LocalDOMWindow::From(script_state)
: nullptr; : nullptr;
...@@ -256,11 +205,39 @@ bool NavigatorSocket::OpenSocketPermitted(ScriptState* script_state, ...@@ -256,11 +205,39 @@ bool NavigatorSocket::OpenSocketPermitted(ScriptState* script_state,
return true; return true;
} }
void NavigatorSocket::OnTcpOpen(
TCPSocket* socket,
int32_t result,
const base::Optional<net::IPEndPoint>& local_addr,
const base::Optional<net::IPEndPoint>& peer_addr,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream) {
pending_tcp_.erase(socket);
socket->Init(result, local_addr, peer_addr, std::move(receive_stream),
std::move(send_stream));
}
void NavigatorSocket::OnUdpOpen(
UDPSocket* socket,
int32_t result,
const base::Optional<net::IPEndPoint>& local_addr,
const base::Optional<net::IPEndPoint>& peer_addr) {
pending_udp_.erase(socket);
socket->Init(result, local_addr, peer_addr);
}
void NavigatorSocket::OnConnectionError() { void NavigatorSocket::OnConnectionError() {
for (auto& pending : pending_requests_) { for (auto& pending : pending_tcp_) {
pending->OnConnectionError(); pending->Init(net::Error::ERR_CONTEXT_SHUT_DOWN, base::nullopt,
base::nullopt, mojo::ScopedDataPipeConsumerHandle(),
mojo::ScopedDataPipeProducerHandle());
}
for (auto& pending : pending_udp_) {
pending->Init(net::Error::ERR_CONTEXT_SHUT_DOWN, base::nullopt,
base::nullopt);
} }
pending_requests_.clear(); pending_tcp_.clear();
pending_udp_.clear();
service_remote_.reset(); service_remote_.reset();
} }
......
...@@ -9,10 +9,13 @@ ...@@ -9,10 +9,13 @@
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h" #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h"
#include "third_party/blink/renderer/modules/direct_sockets/tcp_socket.h"
#include "third_party/blink/renderer/modules/direct_sockets/udp_socket.h"
#include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h" #include "third_party/blink/renderer/platform/bindings/exception_code.h"
#include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h" #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h" #include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h"
#include "third_party/blink/renderer/platform/supplementable.h" #include "third_party/blink/renderer/platform/supplementable.h"
...@@ -59,8 +62,6 @@ class MODULES_EXPORT NavigatorSocket final ...@@ -59,8 +62,6 @@ class MODULES_EXPORT NavigatorSocket final
void Trace(Visitor*) const override; void Trace(Visitor*) const override;
private: private:
class PendingRequest;
// Binds service_remote_ if not already bound. // Binds service_remote_ if not already bound.
void EnsureServiceConnected(LocalDOMWindow&); void EnsureServiceConnected(LocalDOMWindow&);
...@@ -78,12 +79,25 @@ class MODULES_EXPORT NavigatorSocket final ...@@ -78,12 +79,25 @@ class MODULES_EXPORT NavigatorSocket final
// Updates exception state whenever returning false. // Updates exception state whenever returning false.
bool OpenSocketPermitted(ScriptState*, const SocketOptions*, ExceptionState&); bool OpenSocketPermitted(ScriptState*, const SocketOptions*, ExceptionState&);
void OnTcpOpen(TCPSocket* socket,
int32_t result,
const base::Optional<net::IPEndPoint>& local_addr,
const base::Optional<net::IPEndPoint>& peer_addr,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream);
void OnUdpOpen(UDPSocket* socket,
int32_t result,
const base::Optional<net::IPEndPoint>& local_addr,
const base::Optional<net::IPEndPoint>& peer_addr);
void OnConnectionError(); void OnConnectionError();
HeapMojoRemote<blink::mojom::blink::DirectSocketsService> service_remote_{ HeapMojoRemote<blink::mojom::blink::DirectSocketsService> service_remote_{
nullptr}; nullptr};
HeapHashSet<Member<PendingRequest>> pending_requests_; HeapHashSet<Member<TCPSocket>> pending_tcp_;
HeapHashSet<Member<UDPSocket>> pending_udp_;
}; };
} // namespace blink } // namespace blink
......
...@@ -9,11 +9,9 @@ ...@@ -9,11 +9,9 @@
ImplementedAs=NavigatorSocket, ImplementedAs=NavigatorSocket,
RuntimeEnabled=DirectSockets RuntimeEnabled=DirectSockets
] partial interface Navigator { ] partial interface Navigator {
// TODO(crbug.com/905818): Return Promise<TCPSocket>
[SecureContext, RaisesException, CallWith=ScriptState, Measure] [SecureContext, RaisesException, CallWith=ScriptState, Measure]
Promise<void> openTCPSocket(optional SocketOptions options = {}); Promise<TCPSocket> openTCPSocket(optional SocketOptions options = {});
// TODO(crbug.com/1119620): Return Promise<UDPSocket>
[SecureContext, RaisesException, CallWith=ScriptState, Measure] [SecureContext, RaisesException, CallWith=ScriptState, Measure]
Promise<void> openUDPSocket(optional SocketOptions options = {}); Promise<UDPSocket> openUDPSocket(optional SocketOptions options = {});
}; };
// Copyright 2020 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.
#include "third_party/blink/renderer/modules/direct_sockets/tcp_socket.h"
#include "base/macros.h"
#include "net/base/net_errors.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
TCPSocket::TCPSocket(ScriptPromiseResolver& resolver)
: resolver_(&resolver),
feature_handle_for_scheduler_(
ExecutionContext::From(resolver_->GetScriptState())
->GetScheduler()
->RegisterFeature(
SchedulingPolicy::Feature::
kOutstandingNetworkRequestDirectSocket,
{SchedulingPolicy::RecordMetricsForBackForwardCache()})) {
DCHECK(resolver_);
}
TCPSocket::~TCPSocket() = default;
mojo::PendingReceiver<network::mojom::blink::TCPConnectedSocket>
TCPSocket::GetTCPSocketReceiver() {
DCHECK(resolver_);
return tcp_socket_.BindNewPipeAndPassReceiver();
}
mojo::PendingRemote<network::mojom::blink::SocketObserver>
TCPSocket::GetTCPSocketObserver() {
DCHECK(resolver_);
auto result = socket_observer_receiver_.BindNewPipeAndPassRemote();
socket_observer_receiver_.set_disconnect_handler(WTF::Bind(
&TCPSocket::OnSocketObserverConnectionError, WrapPersistent(this)));
return result;
}
void TCPSocket::Init(int32_t result,
const base::Optional<net::IPEndPoint>& local_addr,
const base::Optional<net::IPEndPoint>& peer_addr,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream) {
DCHECK(resolver_);
if (result == net::Error::OK) {
// TODO(crbug.com/905818): Finish initialization.
NOTIMPLEMENTED();
resolver_->Resolve(this);
} else {
resolver_->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotAllowedError, "Permission denied"));
}
resolver_ = nullptr;
}
ScriptPromise TCPSocket::close(ScriptState*, ExceptionState&) {
// TODO(crbug.com/905818): Implement close.
NOTIMPLEMENTED();
return ScriptPromise();
}
void TCPSocket::OnReadError(int32_t net_error) {
// TODO(crbug.com/905818): Implement error handling.
NOTIMPLEMENTED();
}
void TCPSocket::OnWriteError(int32_t net_error) {
// TODO(crbug.com/905818): Implement error handling.
NOTIMPLEMENTED();
}
void TCPSocket::Trace(Visitor* visitor) const {
visitor->Trace(resolver_);
ScriptWrappable::Trace(visitor);
}
void TCPSocket::OnSocketObserverConnectionError() {
// TODO(crbug.com/905818): Implement error handling.
NOTIMPLEMENTED();
}
} // namespace blink
// Copyright 2020 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.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_TCP_SOCKET_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_TCP_SOCKET_H_
#include "base/optional.h"
#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 "mojo/public/cpp/system/data_pipe.h"
#include "services/network/public/mojom/tcp_socket.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.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/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
namespace net {
class IPEndPoint;
} // namespace net
namespace blink {
class MODULES_EXPORT TCPSocket final
: public ScriptWrappable,
public network::mojom::blink::SocketObserver {
DEFINE_WRAPPERTYPEINFO();
public:
explicit TCPSocket(ScriptPromiseResolver&);
~TCPSocket() override;
TCPSocket(const TCPSocket&) = delete;
TCPSocket& operator=(const TCPSocket&) = delete;
// Called by NavigatorSocket when initiating a connection:
mojo::PendingReceiver<network::mojom::blink::TCPConnectedSocket>
GetTCPSocketReceiver();
mojo::PendingRemote<network::mojom::blink::SocketObserver>
GetTCPSocketObserver();
void Init(int32_t result,
const base::Optional<net::IPEndPoint>& local_addr,
const base::Optional<net::IPEndPoint>& peer_addr,
mojo::ScopedDataPipeConsumerHandle receive_stream,
mojo::ScopedDataPipeProducerHandle send_stream);
// Web-exposed function
ScriptPromise close(ScriptState*, ExceptionState&);
// network::mojom::blink::SocketObserver:
void OnReadError(int32_t net_error) override;
void OnWriteError(int32_t net_error) override;
// ScriptWrappable:
void Trace(Visitor* visitor) const override;
private:
void OnSocketObserverConnectionError();
Member<ScriptPromiseResolver> resolver_;
FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle
feature_handle_for_scheduler_;
mojo::Remote<network::mojom::blink::TCPConnectedSocket> tcp_socket_;
mojo::Receiver<network::mojom::blink::SocketObserver>
socket_observer_receiver_{this};
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_TCP_SOCKET_H_
// Copyright 2020 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://github.com/WICG/raw-sockets/blob/master/docs/explainer.md#tcp
[
Exposed=Window,
RuntimeEnabled=DirectSockets,
SecureContext
] interface TCPSocket {
// TODO(crbug.com/905818): Add support for sending, receiving
// TODO(crbug.com/905818): Add measurement
[RaisesException, CallWith=ScriptState]
Promise<void> close();
};
// Copyright 2020 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.
#include "third_party/blink/renderer/modules/direct_sockets/udp_socket.h"
#include "base/macros.h"
#include "net/base/net_errors.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
UDPSocket::UDPSocket(ScriptPromiseResolver& resolver)
: resolver_(&resolver),
feature_handle_for_scheduler_(
ExecutionContext::From(resolver_->GetScriptState())
->GetScheduler()
->RegisterFeature(
SchedulingPolicy::Feature::
kOutstandingNetworkRequestDirectSocket,
{SchedulingPolicy::RecordMetricsForBackForwardCache()})) {
DCHECK(resolver_);
}
UDPSocket::~UDPSocket() = default;
mojo::PendingReceiver<network::mojom::blink::UDPSocket>
UDPSocket::GetUDPSocketReceiver() {
DCHECK(resolver_);
return udp_socket_.BindNewPipeAndPassReceiver();
}
mojo::PendingRemote<network::mojom::blink::UDPSocketListener>
UDPSocket::GetUDPSocketListener() {
DCHECK(resolver_);
auto result = socket_listener_receiver_.BindNewPipeAndPassRemote();
socket_listener_receiver_.set_disconnect_handler(WTF::Bind(
&UDPSocket::OnSocketListenerConnectionError, WrapPersistent(this)));
return result;
}
void UDPSocket::Init(int32_t result,
const base::Optional<net::IPEndPoint>& local_addr,
const base::Optional<net::IPEndPoint>& peer_addr) {
DCHECK(resolver_);
if (result == net::Error::OK) {
// TODO(crbug.com/1119620): Finish initialization.
NOTIMPLEMENTED();
resolver_->Resolve(this);
} else {
resolver_->Reject(MakeGarbageCollected<DOMException>(
DOMExceptionCode::kNotAllowedError, "Permission denied"));
}
resolver_ = nullptr;
}
ScriptPromise UDPSocket::close(ScriptState*, ExceptionState&) {
// TODO(crbug.com/905818): Implement close.
NOTIMPLEMENTED();
return ScriptPromise();
}
void UDPSocket::OnReceived(int32_t result,
const base::Optional<::net::IPEndPoint>& src_addr,
base::Optional<::base::span<const ::uint8_t>> data) {
// TODO(crbug.com/1119620): Implement.
NOTIMPLEMENTED();
}
void UDPSocket::Trace(Visitor* visitor) const {
visitor->Trace(resolver_);
ScriptWrappable::Trace(visitor);
}
void UDPSocket::OnSocketListenerConnectionError() {
// TODO(crbug.com/1119620): Implement UDP error handling.
NOTIMPLEMENTED();
}
} // namespace blink
// Copyright 2020 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.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_UDP_SOCKET_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_UDP_SOCKET_H_
#include "base/optional.h"
#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/udp_socket.mojom-blink.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.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/heap/heap.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
namespace net {
class IPEndPoint;
} // namespace net
namespace blink {
class MODULES_EXPORT UDPSocket final
: public ScriptWrappable,
public network::mojom::blink::UDPSocketListener {
DEFINE_WRAPPERTYPEINFO();
public:
explicit UDPSocket(ScriptPromiseResolver&);
~UDPSocket() override;
UDPSocket(const UDPSocket&) = delete;
UDPSocket& operator=(const UDPSocket&) = delete;
// Called by NavigatorSocket when initiating a connection:
mojo::PendingReceiver<network::mojom::blink::UDPSocket>
GetUDPSocketReceiver();
mojo::PendingRemote<network::mojom::blink::UDPSocketListener>
GetUDPSocketListener();
void Init(int32_t result,
const base::Optional<net::IPEndPoint>& local_addr,
const base::Optional<net::IPEndPoint>& peer_addr);
// Web-exposed function
ScriptPromise close(ScriptState*, ExceptionState&);
// network::mojom::blink::UDPSocketListener:
void OnReceived(int32_t result,
const base::Optional<::net::IPEndPoint>& src_addr,
base::Optional<::base::span<const ::uint8_t>> data) override;
// ScriptWrappable:
void Trace(Visitor* visitor) const override;
private:
void OnSocketListenerConnectionError();
Member<ScriptPromiseResolver> resolver_;
FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle
feature_handle_for_scheduler_;
mojo::Remote<network::mojom::blink::UDPSocket> udp_socket_;
mojo::Receiver<network::mojom::blink::UDPSocketListener>
socket_listener_receiver_{this};
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_DIRECT_SOCKETS_UDP_SOCKET_H_
// Copyright 2020 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://github.com/WICG/raw-sockets/blob/master/docs/explainer.md#udp
[
Exposed=Window,
RuntimeEnabled=DirectSockets,
SecureContext
] interface UDPSocket {
// TODO(crbug.com/1119620): Add support for sending, receiving
// TODO(crbug.com/1119620): Add measurement
[RaisesException, CallWith=ScriptState]
Promise<void> close();
};
...@@ -108,7 +108,6 @@ _idl_imports = [ ...@@ -108,7 +108,6 @@ _idl_imports = [
"//third_party/blink/renderer/modules/presentation/idls.gni", "//third_party/blink/renderer/modules/presentation/idls.gni",
"//third_party/blink/renderer/modules/push_messaging/idls.gni", "//third_party/blink/renderer/modules/push_messaging/idls.gni",
"//third_party/blink/renderer/modules/quota/idls.gni", "//third_party/blink/renderer/modules/quota/idls.gni",
"//third_party/blink/renderer/modules/direct_sockets/idls.gni",
"//third_party/blink/renderer/modules/remoteplayback/idls.gni", "//third_party/blink/renderer/modules/remoteplayback/idls.gni",
"//third_party/blink/renderer/modules/sanitizer_api/idls.gni", "//third_party/blink/renderer/modules/sanitizer_api/idls.gni",
"//third_party/blink/renderer/modules/scheduler/idls.gni", "//third_party/blink/renderer/modules/scheduler/idls.gni",
...@@ -140,7 +139,10 @@ _idl_imports = [ ...@@ -140,7 +139,10 @@ _idl_imports = [
# TODO(dcheng): For whatever reason, is_android doesn't seem to be defined, even # TODO(dcheng): For whatever reason, is_android doesn't seem to be defined, even
# if using import() instead of read_file() in the foreach() loop below... # if using import() instead of read_file() in the foreach() loop below...
if (!is_android) { if (!is_android) {
_idl_imports += [ "//third_party/blink/renderer/modules/serial/idls.gni" ] _idl_imports += [
"//third_party/blink/renderer/modules/direct_sockets/idls.gni",
"//third_party/blink/renderer/modules/serial/idls.gni",
]
} }
# Do not add IDL files directly to these lists. See _idl_imports above instead # Do not add IDL files directly to these lists. See _idl_imports above instead
......
...@@ -1173,6 +1173,17 @@ _CONFIG = [ ...@@ -1173,6 +1173,17 @@ _CONFIG = [
'sigslot::.+', 'sigslot::.+',
], ],
}, },
{
'paths': [
'third_party/blink/renderer/modules/direct_sockets/',
],
'allowed': [
'net::DefineNetworkTrafficAnnotation',
'net::Error',
'net::MutableNetworkTrafficAnnotationTag',
'net::NetworkTrafficAnnotationTag',
]
},
{ {
'paths': ['third_party/blink/renderer/modules/manifest/'], 'paths': ['third_party/blink/renderer/modules/manifest/'],
'allowed': ['net::ParseMimeTypeWithoutParameter'], 'allowed': ['net::ParseMimeTypeWithoutParameter'],
......
...@@ -8271,6 +8271,10 @@ interface SyncManager ...@@ -8271,6 +8271,10 @@ interface SyncManager
method constructor method constructor
method getTags method getTags
method register method register
interface TCPSocket
attribute @@toStringTag
method close
method constructor
interface TaskAttributionTiming : PerformanceEntry interface TaskAttributionTiming : PerformanceEntry
attribute @@toStringTag attribute @@toStringTag
getter containerId getter containerId
...@@ -8533,6 +8537,10 @@ interface TrustedTypePolicyFactory : EventTarget ...@@ -8533,6 +8537,10 @@ interface TrustedTypePolicyFactory : EventTarget
method isScript method isScript
method isScriptURL method isScriptURL
setter onbeforecreatepolicy setter onbeforecreatepolicy
interface UDPSocket
attribute @@toStringTag
method close
method constructor
interface UIEvent : Event interface UIEvent : Event
attribute @@toStringTag attribute @@toStringTag
getter detail getter detail
......
...@@ -86,6 +86,7 @@ Refer to README.md for content description and update process. ...@@ -86,6 +86,7 @@ Refer to README.md for content description and update process.
<item id="dial_get_app_info" added_in_milestone="65" hash_code="15952025" type="0" deprecated="2018-02-27" content_hash_code="90542080" file_path=""/> <item id="dial_get_app_info" added_in_milestone="65" hash_code="15952025" type="0" deprecated="2018-02-27" content_hash_code="90542080" file_path=""/>
<item id="dial_get_device_description" added_in_milestone="62" hash_code="50422598" type="0" deprecated="2018-02-27" content_hash_code="129827780" file_path=""/> <item id="dial_get_device_description" added_in_milestone="62" hash_code="50422598" type="0" deprecated="2018-02-27" content_hash_code="129827780" file_path=""/>
<item id="dial_url_fetcher" added_in_milestone="67" hash_code="41424546" type="0" content_hash_code="129828432" os_list="linux,windows" file_path="chrome/browser/media/router/discovery/dial/dial_url_fetcher.cc"/> <item id="dial_url_fetcher" added_in_milestone="67" hash_code="41424546" type="0" content_hash_code="129828432" os_list="linux,windows" file_path="chrome/browser/media/router/discovery/dial/dial_url_fetcher.cc"/>
<item id="direct_sockets" added_in_milestone="88" hash_code="32472991" type="0" content_hash_code="64752301" os_list="linux,windows" file_path="third_party/blink/renderer/modules/direct_sockets/navigator_socket.cc"/>
<item id="dns_over_https" added_in_milestone="66" hash_code="79895226" type="0" content_hash_code="45123510" os_list="linux,windows" file_path="net/dns/dns_transaction.cc"/> <item id="dns_over_https" added_in_milestone="66" hash_code="79895226" type="0" content_hash_code="45123510" os_list="linux,windows" file_path="net/dns/dns_transaction.cc"/>
<item id="dns_transaction" added_in_milestone="65" hash_code="79227717" type="0" content_hash_code="132206495" os_list="linux,windows" file_path="net/dns/dns_transaction.cc"/> <item id="dns_transaction" added_in_milestone="65" hash_code="79227717" type="0" content_hash_code="132206495" os_list="linux,windows" file_path="net/dns/dns_transaction.cc"/>
<item id="dom_distiller" added_in_milestone="62" hash_code="3989826" type="0" content_hash_code="106153970" os_list="linux,windows" file_path="components/dom_distiller/core/distiller_url_fetcher.cc"/> <item id="dom_distiller" added_in_milestone="62" hash_code="3989826" type="0" content_hash_code="106153970" os_list="linux,windows" file_path="components/dom_distiller/core/distiller_url_fetcher.cc"/>
......
...@@ -152,6 +152,7 @@ hidden="true" so that these annotations don't show up in the document. ...@@ -152,6 +152,7 @@ hidden="true" so that these annotations don't show up in the document.
<traffic_annotation unique_id="origin_policy_loader"/> <traffic_annotation unique_id="origin_policy_loader"/>
<traffic_annotation unique_id="services_http_server_error_response"/> <traffic_annotation unique_id="services_http_server_error_response"/>
<traffic_annotation unique_id="webrtc_peer_connection"/> <traffic_annotation unique_id="webrtc_peer_connection"/>
<traffic_annotation unique_id="direct_sockets"/>
<traffic_annotation unique_id="floc_id_provider_impl"/> <traffic_annotation unique_id="floc_id_provider_impl"/>
<traffic_annotation unique_id="gstatic_change_password_override_urls"/> <traffic_annotation unique_id="gstatic_change_password_override_urls"/>
<traffic_annotation unique_id="interest_feedv2_image_send"/> <traffic_annotation unique_id="interest_feedv2_image_send"/>
......
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