Commit 69b20d6d authored by mek@chromium.org's avatar mek@chromium.org

Update client side navigator.connect API to use ServicePortCollection [3/3]

This is part of a series of patches to update the client side API of what was
formerly known as navigator.connect to follow the new spec based on
navigator.services and a new ServicePort type.

This patch removes the old client side API from blink, and removes now
redundant code from the layout tests.

[1/3] https://codereview.chromium.org/1191393003 Blink side changes
[2/3] https://codereview.chromium.org/1192713004 Content side changes
[3/3] https://codereview.chromium.org/1198653004 This patch

BUG=426458

Review URL: https://codereview.chromium.org/1198653004

git-svn-id: svn://svn.chromium.org/blink/trunk@198024 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 1a91b711
......@@ -12,7 +12,7 @@
<script>
var sw_scope = 'resources/service-worker-scope' + window.location.pathname;
run_connect_tests(function(t, service) {
return first_to_resolve([wrap_in_port(navigator.services.connect(service)), navigator.connect(service)]);
run_connect_tests(function(t, service, options) {
return navigator.services.connect(service, options);
});
</script>
......@@ -12,7 +12,7 @@
<script>
var sw_scope = 'resources/service-worker-scope' + window.location.pathname;
run_postmessage_tests(location.origin, function(t, service) {
return first_to_resolve([wrap_in_port(navigator.services.connect(service)), navigator.connect(service)]);
run_postmessage_tests(location.origin, function(t, service, options) {
return wrap_in_port(navigator.services.connect(service, options));
});
</script>
......@@ -5,9 +5,17 @@ if ("importScripts" in self) {
self.onmessage = function(e) {
var service = e.data.connect;
first_to_resolve([wrap_in_port(navigator.services.connect(service)), navigator.connect(service)])
wrap_in_port(navigator.services.connect(service, e.data.options))
.then(function(port) {
e.data.port.postMessage({success: true, result: port}, [port]);
e.data.port.postMessage({
success: true,
result: {
port: port,
targetURL: port.targetURL,
name: port.name,
data: port.data
}
}, [port]);
})
.catch(function(error) {
// Not all errors can be serialized as a SerializedScriptValue, so
......
......@@ -53,7 +53,8 @@ function run_connect_tests(connect_method) {
return connect_method(t, scope + '/service');
})
.then(function(port) {
assert_class_string(port, 'MessagePort');
var targetURL = new URL(port.targetURL);
assert_equals(targetURL.pathname, base_path() + scope + '/service');
return service_worker_unregister(t, scope);
});
}, 'Connection succeeds if service worker accepts connection event.');
......@@ -84,8 +85,28 @@ function run_connect_tests(connect_method) {
return connect_method(t, scope + '/service?accept');
})
.then(function(port) {
assert_class_string(port, 'MessagePort');
var targetURL = new URL(port.targetURL);
assert_equals(targetURL.pathname, base_path() + scope + '/service');
return service_worker_unregister(t, scope);
});
}, 'Connection succeeds if service worker accepts connection event async.');
promise_test(function(t) {
var scope = sw_scope + '/accepting';
var sw_url = 'resources/accepting-worker.js';
return service_worker_unregister_and_register(t, sw_url, scope)
.then(function(registration) {
return wait_for_state(t, registration.installing, 'activated');
})
.then(function() {
return connect_method(t, scope + '/service', {name: 'somename', data: 'somedata'});
})
.then(function(port) {
var targetURL = new URL(port.targetURL);
assert_equals(targetURL.pathname, base_path() + scope + '/service');
assert_equals(port.name, 'somename');
assert_equals(port.data, 'somedata');
return service_worker_unregister(t, scope);
});
}, 'Returned port has correct name and data fields');
}
......@@ -17,9 +17,11 @@ function reply_as_promise(t, port) {
});
}
// Method that behaves similarly to navigator.connect, but the actual connect
// call is made from a cross origin iframe.
function cross_origin_connect(t, service) {
// Method that behaves similarly to navigator.services.connect, but the actual
// connect call is made from a cross origin iframe. Also the returned port is a
// MessagePort instead of a ServicePort, but with targetURL, name and data
// attributes set.
function cross_origin_connect(t, service, options) {
// |service| could be a relative URL, but for this to work from the iframe it
// needs an absolute URL.
var target_url = new URL(service, location.origin + base_path());
......@@ -28,52 +30,43 @@ function cross_origin_connect(t, service) {
.then(function(iframe) {
var channel = new MessageChannel();
iframe.contentWindow.postMessage(
{connect: target_url.href, port: channel.port2}, '*', [channel.port2]);
{connect: target_url.href, port: channel.port2, options: options}, '*', [channel.port2]);
return reply_as_promise(t, channel.port1);
});
})
.then(function(result) {
var port = result.port;
port.targetURL = result.targetURL;
port.name = result.name;
port.data = result.data;
return port;
});
}
// Method that behaves similarly to navigator.connect, but the actual connect
// call is made from a worker.
function connect_from_worker(t, service) {
// call is made from a worker. Also the returned port is a MessagePort instead
// of a ServicePort, but with targetURL, name and data attributes set.
function connect_from_worker(t, service, options) {
// |service| is a relative URL, but for this to work from the worker it needs
// an absolute URL.
var target_url = location.origin + base_path() + service;
var worker = new Worker('resources/connect-helper.js');
var channel = new MessageChannel();
worker.postMessage
({connect: target_url, port: channel.port2}, [channel.port2]);
return reply_as_promise(t, channel.port1);
}
// Similar to Promise.race, except that returned promise only rejects if all
// passed promises reject. Used temporarily to support both old and new client
// side APIs.
function first_to_resolve(promises) {
return new Promise(function(resolve, reject) {
var remaining = promises.length;
var resolved = false;
for (var i = 0; i < promises.length; ++i) {
Promise.resolve(promises[i])
.then(function(result) {
if (!resolved) {
resolve(result);
resolved = true;
}
})
.catch(function(result) {
remaining--;
if (remaining === 0) {
reject(result);
}
});
}
});
({connect: target_url, port: channel.port2, options: options}, [channel.port2]);
return reply_as_promise(t, channel.port1)
.then(function(result) {
var port = result.port;
port.targetURL = result.targetURL;
port.name = result.name;
port.data = result.data;
return port;
});
}
// Takes (a promise resolving to) a ServicePort instance, and returns a Promise
// that resolves to a MessagePort wrapping that ServicePort. Used to support
// both old and new APIs at the same time.
// that resolves to a MessagePort wrapping that ServicePort. Used to simplify
// testing code and to allow forwarding a connection from a cross origin iframe
// or worker to the main test runner.
function wrap_in_port(maybe_port) {
return Promise.resolve(maybe_port).then(
function(port) {
......@@ -86,6 +79,9 @@ function wrap_in_port(maybe_port) {
navigator.services.onmessage = function(event) {
channel.port2.postMessage(event.data, event.ports);
};
channel.port1.targetURL = port.targetURL;
channel.port1.name = port.name;
channel.port1.data = port.data;
return channel.port1;
}
);
......
......@@ -281,10 +281,8 @@
'mediastream/NavigatorUserMedia.idl',
'mediastream/URLMediaStream.idl',
'mediastream/WindowMediaStream.idl',
'navigatorconnect/NavigatorConnect.idl',
'navigatorconnect/NavigatorServices.idl',
'navigatorconnect/ServiceWorkerGlobalScopeNavigatorConnect.idl',
'navigatorconnect/WorkerNavigatorConnect.idl',
'navigatorconnect/WorkerNavigatorServices.idl',
'navigatorcontentutils/NavigatorContentUtils.idl',
'netinfo/NavigatorNetworkInformation.idl',
......@@ -1027,8 +1025,6 @@
'navigatorconnect/CrossOriginConnectEvent.h',
'navigatorconnect/CrossOriginServiceWorkerClient.cpp',
'navigatorconnect/CrossOriginServiceWorkerClient.h',
'navigatorconnect/NavigatorConnect.cpp',
'navigatorconnect/NavigatorConnect.h',
'navigatorconnect/NavigatorServices.cpp',
'navigatorconnect/NavigatorServices.h',
'navigatorconnect/ServicePort.cpp',
......@@ -1036,7 +1032,6 @@
'navigatorconnect/ServicePortCollection.cpp',
'navigatorconnect/ServicePortCollection.h',
'navigatorconnect/ServiceWorkerGlobalScopeNavigatorConnect.h',
'navigatorconnect/WorkerNavigatorConnect.h',
'navigatorconnect/WorkerNavigatorServices.cpp',
'navigatorconnect/WorkerNavigatorServices.h',
'navigatorcontentutils/NavigatorContentUtils.cpp',
......
// Copyright 2014 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 "config.h"
#include "modules/navigatorconnect/NavigatorConnect.h"
#include "bindings/core/v8/ScriptPromiseResolver.h"
#include "core/dom/DOMException.h"
#include "core/dom/ExceptionCode.h"
#include "core/dom/MessageChannel.h"
#include "core/dom/MessagePort.h"
#include "public/platform/Platform.h"
#include "public/platform/WebNavigatorConnectProvider.h"
namespace blink {
namespace {
class ConnectCallbacks : public WebNavigatorConnectPortCallbacks {
public:
ConnectCallbacks(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver)
: m_resolver(resolver)
{
ASSERT(m_resolver);
}
~ConnectCallbacks() override { }
void onSuccess(WebMessagePortChannel* channelRaw) override
{
OwnPtr<WebMessagePortChannel> channel = adoptPtr(channelRaw);
if (!m_resolver->executionContext() || m_resolver->executionContext()->activeDOMObjectsAreStopped()) {
return;
}
RefPtrWillBeRawPtr<MessagePort> port = MessagePort::create(*m_resolver->executionContext());
port->entangle(channel.release());
m_resolver->resolve(port);
}
void onError() override
{
if (!m_resolver->executionContext() || m_resolver->executionContext()->activeDOMObjectsAreStopped()) {
return;
}
m_resolver->reject(DOMException::create(AbortError));
}
private:
RefPtrWillBePersistent<ScriptPromiseResolver> m_resolver;
WTF_MAKE_NONCOPYABLE(ConnectCallbacks);
};
} // namespace
ScriptPromise NavigatorConnect::connect(ScriptState* scriptState, const String& url)
{
WebNavigatorConnectProvider* provider = Platform::current()->navigatorConnectProvider();
if (!provider)
return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
provider->connect(
scriptState->executionContext()->completeURL(url),
scriptState->executionContext()->securityOrigin()->toString(),
new ConnectCallbacks(resolver));
return promise;
}
} // namespace blink
// Copyright 2014 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 NavigatorConnect_h
#define NavigatorConnect_h
#include "bindings/core/v8/ScriptPromise.h"
#include "wtf/text/WTFString.h"
namespace blink {
class Navigator;
class ScriptState;
class NavigatorConnect {
public:
static ScriptPromise connect(ScriptState* scriptState, Navigator&, const String& url)
{
return connect(scriptState, url);
}
static ScriptPromise connect(ScriptState*, const String& url);
};
} // namespace blink
#endif // NavigatorConnect_h
// Copyright 2014 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://mkruisselbrink.github.io/navigator-connect/#idl-def-NavigatorConnect
[
RuntimeEnabled=NavigatorConnect,
] partial interface Navigator {
[CallWith=ScriptState] Promise connect(USVString url);
};
// Copyright 2014 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 WorkerNavigatorConnect_h
#define WorkerNavigatorConnect_h
#include "modules/navigatorconnect/NavigatorConnect.h"
namespace blink {
class WorkerNavigator;
class WorkerNavigatorConnect {
public:
static ScriptPromise connect(ScriptState* scriptState, WorkerNavigator&, const String& url)
{
return NavigatorConnect::connect(scriptState, url);
}
};
} // namespace blink
#endif // WorkerNavigatorConnect_h
// Copyright 2014 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://mkruisselbrink.github.io/navigator-connect/#idl-def-NavigatorConnect
[
RuntimeEnabled=NavigatorConnect,
] partial interface WorkerNavigator {
[CallWith=ScriptState] Promise connect(USVString url);
};
// Copyright 2014 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 WebNavigatorConnectProvider_h
#define WebNavigatorConnectProvider_h
#include "WebCallbacks.h"
namespace blink {
class WebMessagePortChannel;
class WebString;
class WebURL;
typedef WebCallbacks<void, void> WebNavigatorConnectCallbacks;
typedef WebCallbacks<WebMessagePortChannel, void> WebNavigatorConnectPortCallbacks;
class WebNavigatorConnectProvider {
public:
virtual ~WebNavigatorConnectProvider() { }
// Initiates a connection from the given origin to the given URL. When
// successful the service can communicate with the client over the given
// channel. The origin isn't passed as WebSecurityOrigin because that would
// be a layering violation (platform/ code shouldn't depend on web/ code).
// Ownership of the WebMessagePortChannel and WebNavigatorConnectCallbacks
// objects are both transferred to the provider.
virtual void connect(const WebURL&, const WebString& origin, WebNavigatorConnectPortCallbacks*) { }
};
} // namespace blink
#endif // WebNavigatorConnectProvider_h
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