New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow browsing contexts to resolve to cross-origin windows #15358
Allow browsing contexts to resolve to cross-origin windows #15358
Conversation
Heads up! This PR modifies the following files:
|
cc @avadacatavra @bzbarsky @Ms2ger |
#[inline] | ||
pub fn get_cx(&self) -> *mut JSContext { | ||
unsafe { JS_GetContext(self.get_runtime()) } | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? We might as well use Runtime::new()
; that's probably faster than two out-of-line calls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This probably isn't needed any more, originally I was fighting to try to get Servo to have globals that aren't GlobalScope
s but eventually gave up. This looks like code that was left over from that fight.
@@ -61,7 +70,7 @@ impl BrowsingContext { | |||
let WindowProxyHandler(handler) = window.windowproxy_handler(); | |||
assert!(!handler.is_null()); | |||
|
|||
let cx = window.get_cx(); | |||
let cx = window.reflector().get_cx(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
@@ -104,13 +114,13 @@ impl BrowsingContext { | |||
/// Change the Window that this browsing context's WindowProxy resolves to. | |||
// TODO: support setting the window proxy to a dummy value, | |||
// to handle the case when the active document is in another script thread. | |||
pub fn set_window_proxy(&self, window: &Window) { | |||
fn set_window_proxy<W: DomObject>(&self, window: &W, traps: &ProxyTraps) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allowing any DomObject
here does not sound like a great strategy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto. The problem was that when I started this, XOriginWindow
was a global, but not a GlobalScope
. Now it is, so I can make this a GlobalScope
, so we can statically check that it's only called with globals.
} | ||
|
||
pub fn unset_currently_active(&self) { | ||
let win = XOriginWindow::new(self); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would CrossOriginWindow
be that much harder to type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooh, bikeshedding! XThreadWindow
? CrossThreadWindow
? DissimillarOriginWindow
?
|
||
// https://html.spec.whatwg.org/multipage/#dom-location-href | ||
fn Stringifier(&self) -> DOMString { | ||
DOMString::from("<XOriginWindow>") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Er yes, not sure what to put here. Stringifiers aren't allowed to throw, so we have to return something. Once we have XOWs, this will never be called so we can panic!
, but in the mean time we have to return some DOMString
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Er... Why are stringifiers not allowed to throw? There's nothing that prevents a spec from defining a stringifier that sometimes throws.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bzbarsky D'oh! Fixed this, the stringifier now throws a security exception.
use js::jsval::{JSVal, UndefinedValue}; | ||
use msg::constellation_msg::PipelineId; | ||
|
||
// TODO: documentation! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yes, must write some of that.
@@ -4,7 +4,7 @@ function get_host_info() { | |||
var HTTP_PORT2 = '{{ports[http][1]}}'; | |||
var HTTPS_PORT = '{{ports[https][0]}}'; | |||
var ORIGINAL_HOST = '{{host}}'; | |||
var REMOTE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('www1.' + ORIGINAL_HOST); | |||
var REMOTE_HOST = (ORIGINAL_HOST === '127.0.0.1') ? '127.0.0.2' : '127.0.0.1'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
r? @jgraham
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jgraham the reason for this change is to run the test suite with a non-similar REMOTE_HOST
. At the moment, ORIGINAL_HOST
and REMOTE_HOST
are similar-origin, so we never actually run any tests cross-thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this break tests? REMOTE_HOST is supposed to be a URL that is actually reachable; I would expect the case that uses 127.0.0.2 to time out whenever it attempts to connect.
☔ The latest upstream changes (presumably #15405) made this pull request unmergeable. Please resolve the merge conflicts. |
ee3c42c
to
df7c985
Compare
Looks like a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing particularly concerning here. Well done!
|
||
// https://html.spec.whatwg.org/multipage/#window | ||
[Global, NoInterfaceObject] | ||
interface XOriginWindow : GlobalScope { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: this makes iframe.contentWindow instanceof Window
return false for cross-origin iframes. It might be possible to override the hasInstance proxy trap for this, but XOriginLocation can't do that. I'm not sure what the solution is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh good point. Should I just file an issue for this?
One possible solution, but it would mean rewriting codegen, would be to allow more than one Servo implementation of a webidl class, in particular to make Foo::Wrap
generic in any type which implements FooMethods
, not specific to Foo
. This isn't an easy change though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An issue would be good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed #15476.
pub fn unset_currently_active(&self) { | ||
let window = XOriginWindow::new(self); | ||
let globalscope = window.global(); | ||
self.set_window_proxy(&*globalscope, &XORIGIN_PROXY_HANDLER); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a confusing way of writing:
let window = XOriginWindow::new(self);
self.set_window_proxy(&*window.upcast(), &XORIGIN_PROXY_HANDLER);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
@@ -144,6 +154,23 @@ impl BrowsingContext { | |||
} | |||
} | |||
|
|||
pub fn set_currently_active(&self, window: &Window) { | |||
let globalscope = window.global(); | |||
self.set_window_proxy(&*globalscope, &PROXY_HANDLER); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let globalscope = window.upcast();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
unsafe { | ||
debug!("Setting window proxy of {:p}.", self); | ||
let WindowProxyHandler(handler) = window.windowproxy_handler(); | ||
let handler = CreateWrapperProxyHandler(traps); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't need to create a new handler every time here. We can create it once and store it in DomStaticData like the regular windowproxy handler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, is CreateWrapperProxyHandler
expensive?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's more that we only need a singleton, and creating more will lead to memory leaks if we don't clean them up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't they just get gc'd when the window proxy is unreachable?
reflector: Reflector::new(), | ||
window: JS::from_ref(window), | ||
}; | ||
unsafe { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can use reflect_dom_object here and remove the unsafe_code allow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. This was a holdover from XOriginWindow
not implementing GlobalScope
.
// Any timer events fired on this window are ignored. | ||
let (timer_event_chan, _) = ipc::channel().unwrap(); | ||
let win = box XOriginWindow { | ||
globalscope: GlobalScope::new_inherited(PipelineId::new(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may want a TODO here about storing the actual pipeline that this cross-origin window represents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could do that for the initial pipeline id, but to keep that id up-to-date, we'd have to send a lot of messages around (N messages ever time the pipeline changed) which seems not worth it. I'll add a comment about this.
@@ -4,7 +4,7 @@ function get_host_info() { | |||
var HTTP_PORT2 = '{{ports[http][1]}}'; | |||
var HTTPS_PORT = '{{ports[https][0]}}'; | |||
var ORIGINAL_HOST = '{{host}}'; | |||
var REMOTE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('www1.' + ORIGINAL_HOST); | |||
var REMOTE_HOST = (ORIGINAL_HOST === '127.0.0.1') ? '127.0.0.2' : '127.0.0.1'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this break tests? REMOTE_HOST is supposed to be a URL that is actually reachable; I would expect the case that uses 127.0.0.2 to time out whenever it attempts to connect.
For some reason, github isn't letting me reply to #15358 (comment) Good point, there's no http server running on 127.0.0.2. As a patch, I can set it to |
Yeah, http://testthewebforward.org/docs/test-format-guidelines.html#tests-involving-multiple-origins only describes subdomains unfortunately. |
Well, https and multiple ports are supposed to give you dissimilar origins. I still don't really understand why servo can't use those things as a part of the iframe process heuristics? But if we want another top level host, that should be possible but will require more coordination to check that we have buy-in. |
Multiple ports is not enough to give you dissimilar origins. If you have "http://foo.com:10" and "http://foo.com:20" and they both set document.domain to "foo.com", they end up same origin-domain. https is enough, though. |
I don't think we want to require all our cross-origin tests to run with one server http and one https. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jgraham will need to sign off on the get-host-info.sub.js change.
@@ -45,6 +46,9 @@ pub struct BrowsingContext { | |||
|
|||
/// The pipeline id of the currently active document. | |||
/// May be None, when the currently active document is in another script thread. | |||
/// We do not try to keep the pipeline id for documents in other threads, | |||
/// as this would require the constelltion notifying many script threads about |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/constelltion/constellation/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
let cx = globalscope.get_cx(); | ||
let loc = box XOriginLocation { | ||
#[allow(unrooted_must_root)] | ||
pub fn new_inherited(window: &XOriginWindow) -> XOriginLocation { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be public.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
tests/wpt/mozilla/meta/MANIFEST.json
Outdated
"mozilla/referrer-policy/generic/subresource/mozresource.pyc": [ | ||
"c3d7573593042e1d218e532071225d92c4920954", | ||
"support" | ||
], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll need to remove the pyc files from your working tree and run manifest-update again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Okay, my guess is that this test is genuinely timing out on the CI hardware, I'll try splitting it into subtests and see if that helps. |
1f11bf8
to
7153880
Compare
809ecd4
to
3ad8a6d
Compare
I radically trimmed back @bors-servo r=jdm |
📌 Commit 3ad8a6d has been approved by |
⌛ Testing commit 3ad8a6d with merge 0740e20... |
…ow, r=jdm Allow browsing contexts to resolve to cross-origin windows <!-- Please describe your changes on the following line: --> This PR implements cross-thread `WindowProxy` objects. At the moment, if a `Window` performs a non-similar-origin navigation, the old script thread does not update its `WindowProxy`, since the new `Window` is in the new script thread. With this PR, the `WindowProxy` is updated to a dummy `XOriginWindow` object, that only implements the whitelisted methods that are allowed to be called cross-origin. This PR does not include working implementations of some of the cross-origin `Window` or `Location` methods. This PR causes some cross-origin wpt tests to now pass, in particular `/html/browsers/origin/cross-origin-objects/cross-origin-objects.html ` now passes `Only whitelisted properties are accessible cross-origin`. There are some CORS failures in `fetch`, I suspect caused by the incorrect setting of `origin` in fetch requests. Although there are some functions that now throw `SecurityException`, it is not meant to be a complete implementation, which will have to wait for XOWs to land. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #15180. - [X] There are tests for these changes <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15358) <!-- Reviewable:end -->
💔 Test failed - mac-rel-wpt2 |
Hmm:
The first one is #14775, the second is caused by the test running while |
3ad8a6d
to
e8d7655
Compare
OK, I rewrote the test to be more robust against timing variations. @bors-servo r=jdm |
📌 Commit e8d7655 has been approved by |
…ow, r=jdm Allow browsing contexts to resolve to cross-origin windows <!-- Please describe your changes on the following line: --> This PR implements cross-thread `WindowProxy` objects. At the moment, if a `Window` performs a non-similar-origin navigation, the old script thread does not update its `WindowProxy`, since the new `Window` is in the new script thread. With this PR, the `WindowProxy` is updated to a dummy `XOriginWindow` object, that only implements the whitelisted methods that are allowed to be called cross-origin. This PR does not include working implementations of some of the cross-origin `Window` or `Location` methods. This PR causes some cross-origin wpt tests to now pass, in particular `/html/browsers/origin/cross-origin-objects/cross-origin-objects.html ` now passes `Only whitelisted properties are accessible cross-origin`. There are some CORS failures in `fetch`, I suspect caused by the incorrect setting of `origin` in fetch requests. Although there are some functions that now throw `SecurityException`, it is not meant to be a complete implementation, which will have to wait for XOWs to land. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #15180. - [X] There are tests for these changes <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15358) <!-- Reviewable:end -->
☀️ Test successful - android, arm32, arm64, linux-dev, linux-rel-css, linux-rel-wpt, mac-dev-unit, mac-rel-css, mac-rel-wpt1, mac-rel-wpt2, windows-gnu-dev, windows-msvc-dev |
This PR implements cross-thread
WindowProxy
objects.At the moment, if a
Window
performs a non-similar-origin navigation, the old script thread does not update itsWindowProxy
, since the newWindow
is in the new script thread. With this PR, theWindowProxy
is updated to a dummyXOriginWindow
object, that only implements the whitelisted methods that are allowed to be called cross-origin.This PR does not include working implementations of some of the cross-origin
Window
orLocation
methods.This PR causes some cross-origin wpt tests to now pass, in particular
/html/browsers/origin/cross-origin-objects/cross-origin-objects.html
now passesOnly whitelisted properties are accessible cross-origin
. There are some CORS failures infetch
, I suspect caused by the incorrect setting oforigin
in fetch requests.Although there are some functions that now throw
SecurityException
, it is not meant to be a complete implementation, which will have to wait for XOWs to land../mach build -d
does not report any errors./mach test-tidy
does not report any errorsThis change is