mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-28 15:40:04 +00:00
Merge pull request #1981 from lightpanda-io/window_cross_origin
Window cross origin
This commit is contained in:
@@ -300,7 +300,9 @@ pub fn init(self: *Page, frame_id: u32, session: *Session, parent: ?*Page) !void
|
|||||||
._performance = Performance.init(),
|
._performance = Performance.init(),
|
||||||
._screen = screen,
|
._screen = screen,
|
||||||
._visual_viewport = visual_viewport,
|
._visual_viewport = visual_viewport,
|
||||||
|
._cross_origin_wrapper = undefined,
|
||||||
});
|
});
|
||||||
|
self.window._cross_origin_wrapper = .{ .window = self.window };
|
||||||
|
|
||||||
self._style_manager = try StyleManager.init(self);
|
self._style_manager = try StyleManager.init(self);
|
||||||
errdefer self._style_manager.deinit();
|
errdefer self._style_manager.deinit();
|
||||||
|
|||||||
51
src/browser/tests/window/cross_origin.html
Normal file
51
src/browser/tests/window/cross_origin.html
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<script src="../testing.js"></script>
|
||||||
|
|
||||||
|
<iframe src=support/frame1.html></iframe>
|
||||||
|
|
||||||
|
<script id=post_message type=module>
|
||||||
|
const state = await testing.async();
|
||||||
|
|
||||||
|
{
|
||||||
|
const ALT_BASE = testing.BASE_URL.replace('127.0.0.1', 'localhost');
|
||||||
|
|
||||||
|
{
|
||||||
|
let iframe2 = document.createElement('iframe');
|
||||||
|
iframe2.src = ALT_BASE + 'window/support/frame1.html';
|
||||||
|
document.documentElement.appendChild(iframe2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let iframe3 = document.createElement('iframe');
|
||||||
|
iframe3.src = ALT_BASE + 'window/support/frame2.html';
|
||||||
|
document.documentElement.appendChild(iframe3);
|
||||||
|
}
|
||||||
|
|
||||||
|
let captures = [];
|
||||||
|
window.addEventListener('message', (e) => {
|
||||||
|
captures.push(e.data);
|
||||||
|
if (captures.length == 3) {
|
||||||
|
state.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await state.done(() => {
|
||||||
|
const expected_urls = [
|
||||||
|
testing.BASE_URL + 'window/support/frame1.html',
|
||||||
|
ALT_BASE + 'window/support/frame1.html',
|
||||||
|
ALT_BASE + 'window/support/frame2.html',
|
||||||
|
];
|
||||||
|
|
||||||
|
// No strong order guarantee for messaages, and we don't care about the order
|
||||||
|
// so long as it's the correct data.
|
||||||
|
testing.expectEqual(expected_urls.sort(), captures.map((c) => {return c.url}).sort());
|
||||||
|
captures.forEach((c) => {
|
||||||
|
if (c.url.includes(testing.BASE_URL)) {
|
||||||
|
testing.expectEqual(false, c.document_is_undefined);
|
||||||
|
} else {
|
||||||
|
testing.expectEqual(true, c.document_is_undefined);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
7
src/browser/tests/window/support/frame1.html
Normal file
7
src/browser/tests/window/support/frame1.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<script>
|
||||||
|
window.parent.postMessage({
|
||||||
|
url: location.toString(),
|
||||||
|
document_is_undefined: window.parent.document === undefined,
|
||||||
|
}, '*')
|
||||||
|
</script>
|
||||||
7
src/browser/tests/window/support/frame2.html
Normal file
7
src/browser/tests/window/support/frame2.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<script>
|
||||||
|
window.top.postMessage({
|
||||||
|
url: location.toString(),
|
||||||
|
document_is_undefined: window.top.document === undefined,
|
||||||
|
}, '*')
|
||||||
|
</script>
|
||||||
@@ -49,6 +49,10 @@ const IS_DEBUG = builtin.mode == .Debug;
|
|||||||
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
pub fn registerTypes() []const type {
|
||||||
|
return &.{ Window, CrossOriginWindow };
|
||||||
|
}
|
||||||
|
|
||||||
const Window = @This();
|
const Window = @This();
|
||||||
|
|
||||||
_proto: *EventTarget,
|
_proto: *EventTarget,
|
||||||
@@ -87,6 +91,8 @@ _scroll_pos: struct {
|
|||||||
.y = 0,
|
.y = 0,
|
||||||
.state = .done,
|
.state = .done,
|
||||||
},
|
},
|
||||||
|
// A cross origin wrapper for this window
|
||||||
|
_cross_origin_wrapper: CrossOriginWindow,
|
||||||
|
|
||||||
pub fn asEventTarget(self: *Window) *EventTarget {
|
pub fn asEventTarget(self: *Window) *EventTarget {
|
||||||
return self._proto;
|
return self._proto;
|
||||||
@@ -104,19 +110,19 @@ pub fn getWindow(self: *Window) *Window {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getTop(self: *Window) *Window {
|
pub fn getTop(self: *Window, page: *Page) Access {
|
||||||
var p = self._page;
|
var p = self._page;
|
||||||
while (p.parent) |parent| {
|
while (p.parent) |parent| {
|
||||||
p = parent;
|
p = parent;
|
||||||
}
|
}
|
||||||
return p.window;
|
return Access.init(page.window, p.window);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getParent(self: *Window) *Window {
|
pub fn getParent(self: *Window, page: *Page) Access {
|
||||||
if (self._page.parent) |p| {
|
if (self._page.parent) |p| {
|
||||||
return p.window;
|
return Access.init(page.window, p.window);
|
||||||
}
|
}
|
||||||
return self;
|
return .{ .window = self };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getDocument(self: *Window) *Document {
|
pub fn getDocument(self: *Window) *Document {
|
||||||
@@ -606,6 +612,25 @@ pub fn unhandledPromiseRejection(self: *Window, no_handler: bool, rejection: js.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const Access = union(enum) {
|
||||||
|
window: *Window,
|
||||||
|
cross_origin: *CrossOriginWindow,
|
||||||
|
|
||||||
|
pub fn init(callee: *Window, accessing: *Window) Access {
|
||||||
|
if (callee == accessing) {
|
||||||
|
// common enough that it's worth the check
|
||||||
|
return .{ .window = accessing };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callee._page.js.origin == accessing._page.js.origin) {
|
||||||
|
// two different windows, but same origin, return the full window
|
||||||
|
return .{ .window = accessing };
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{ .cross_origin = &accessing._cross_origin_wrapper };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const ScheduleOpts = struct {
|
const ScheduleOpts = struct {
|
||||||
repeat: bool,
|
repeat: bool,
|
||||||
params: []js.Value.Temp,
|
params: []js.Value.Temp,
|
||||||
@@ -892,6 +917,41 @@ pub const JsApi = struct {
|
|||||||
}.prompt, .{});
|
}.prompt, .{});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CrossOriginWindow = struct {
|
||||||
|
window: *Window,
|
||||||
|
|
||||||
|
pub fn postMessage(self: *CrossOriginWindow, message: js.Value.Temp, target_origin: ?[]const u8, page: *Page) !void {
|
||||||
|
return self.window.postMessage(message, target_origin, page);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getTop(self: *CrossOriginWindow, page: *Page) Access {
|
||||||
|
return self.window.getParent(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getParent(self: *CrossOriginWindow, page: *Page) Access {
|
||||||
|
return self.window.getParent(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getFramesLength(self: *const CrossOriginWindow) u32 {
|
||||||
|
return self.window.getFramesLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const JsApi = struct {
|
||||||
|
pub const bridge = js.Bridge(CrossOriginWindow);
|
||||||
|
|
||||||
|
pub const Meta = struct {
|
||||||
|
pub const name = "CrossOriginWindow";
|
||||||
|
pub const prototype_chain = bridge.prototypeChain();
|
||||||
|
pub var class_id: bridge.ClassId = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const postMessage = bridge.function(CrossOriginWindow.postMessage, .{});
|
||||||
|
pub const top = bridge.accessor(CrossOriginWindow.getTop, null, .{});
|
||||||
|
pub const parent = bridge.accessor(CrossOriginWindow.getParent, null, .{});
|
||||||
|
pub const length = bridge.accessor(CrossOriginWindow.getFramesLength, null, .{});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const testing = @import("../../testing.zig");
|
const testing = @import("../../testing.zig");
|
||||||
test "WebApi: Window" {
|
test "WebApi: Window" {
|
||||||
try testing.htmlRunner("window", .{});
|
try testing.htmlRunner("window", .{});
|
||||||
|
|||||||
@@ -39,8 +39,9 @@ pub fn asNode(self: *IFrame) *Node {
|
|||||||
return self.asElement().asNode();
|
return self.asElement().asNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getContentWindow(self: *const IFrame) ?*Window {
|
pub fn getContentWindow(self: *const IFrame, page: *Page) ?Window.Access {
|
||||||
return self._window;
|
const frame_window = self._window orelse return null;
|
||||||
|
return Window.Access.init(page.window, frame_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getContentDocument(self: *const IFrame) ?*Document {
|
pub fn getContentDocument(self: *const IFrame) ?*Document {
|
||||||
|
|||||||
Reference in New Issue
Block a user