[Problem/Bug]: WebResourceRequested is not raised for subresources of a cross-origin iframe in a NewWindow WebView2
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 54/100
Hướng nghiên cứu
Start by reproducing the issue with the Rust/wry sample in the issue, especially the NewWindowRequested setup and WebResourceRequested filter registration. Compare the logged requests for same-origin and cross-origin iframe subresources in the popup, including with REREGISTER=1. Done means the popup's cross-origin iframe scripts and fetch requests are raised through WebResourceRequested and served by the custom protocol.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
What happened?
In a WebView2 that is passed to CoreWebView2NewWindowRequestedEventArgs.NewWindow (a window.open() popup), WebResourceRequested is not raised for the subresource requests of a cross-origin iframe. The request for the iframe document is raised, but its scripts and fetch() calls are not. When the content is served from WebResourceRequested (a custom host such as http://frame.localhost/), those requests go to the network and fail with net::ERR_CONNECTION_REFUSED.
Every WebView2 gets the filter
AddWebResourceRequestedFilterWithRequestSourceKinds(L"http://frame.localhost/*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL, COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL).
| Request | WebResourceRequested |
|---|---|
| Cross-origin iframe in a normally created WebView2: document and subresources | raised |
| Same-origin iframe in the popup: document and subresources | raised |
| Cross-origin script loaded by the popup's top-level document | raised |
| Cross-origin iframe in the popup: document | raised |
| Cross-origin iframe in the popup: subresources | not raised |
The last row is the same for an about:blank popup filled by the opener and for a popup that navigates to its own page.
Adding the filters and a second WebResourceRequested handler again after NewWindow is set, as suggested in #4689, does not change it: the second handler logs the iframe document but none of its subresources.
It looks like #2341 still applies to WebView2s created through NewWindowRequested. Related: #4689, #4181.
Found through Tauri / wry, which implement custom protocols this way, so a cross-origin iframe in any window.open() window of such an app cannot load its resources.
Importance
Moderate. My app's user experience is affected, but still usable.
Runtime Channel
Stable release (WebView2 Runtime)
Runtime Version
156.0.4314.50
SDK Version
1.0.3650.58
Framework
Win32
Operating System
Windows 11
OS Version
10.0.26300.9711
Repro steps
Rust, wry 0.55.1 with webview2-com 0.38.2 (SDK 1.0.3650.58). Sequence per WebView2, as wry does it:
- Create the controller with the opener's environment.
AddWebResourceRequestedFilterWithRequestSourceKindsforhttp://app.localhost/*andhttp://frame.localhost/*(context ALL, source kinds ALL), thenadd_WebResourceRequested, which serves both hosts.- In
NewWindowRequested: take a deferral, create the popup WebView2 the same way (steps 1 and 2), setargs.NewWindow, complete the deferral.
The main page (http://app.localhost/) opens three popups. Each iframe reports whether its script loaded and whether its fetch() succeeded.
cargo run:
WebView2 156.0.4314.50
1-cross-origin-iframe-in-main-window: frame.js loaded, fetch: ok
3-cross-origin-iframe-in-about-blank-popup: frame.js FAILED, fetch: error Failed to fetch
2-same-origin-iframe-in-about-blank-popup: frame.js loaded, fetch: ok
4-cross-origin-iframe-in-about-blank-popup-after-1s: frame.js FAILED, fetch: error Failed to fetch
5-popup-page-itself: cross-origin frame.js loaded
6-cross-origin-iframe-in-popup-page: frame.js FAILED, fetch: error Failed to fetch
With REREGISTER=1, the filters and a second handler that only logs are added again after NewWindow is set. It sees the documents of the cross-origin iframes and the subresources of the same-origin iframe, but never frame.localhost/frame.js or frame.localhost/data.txt from inside an iframe:
WebView2 156.0.4314.50
1-cross-origin-iframe-in-main-window: frame.js loaded, fetch: ok
seen by the handler added after SetNewWindow: http://app.localhost/frame.html?2-same-origin-iframe-in-about-blank-popup
seen by the handler added after SetNewWindow: http://frame.localhost/frame.html?3-cross-origin-iframe-in-about-blank-popup
seen by the handler added after SetNewWindow: http://app.localhost/frame.js
seen by the handler added after SetNewWindow: http://app.localhost/data.txt
3-cross-origin-iframe-in-about-blank-popup: frame.js FAILED, fetch: error Failed to fetch
2-same-origin-iframe-in-about-blank-popup: frame.js loaded, fetch: ok
seen by the handler added after SetNewWindow: http://frame.localhost/frame.html?4-cross-origin-iframe-in-about-blank-popup-after-1s
4-cross-origin-iframe-in-about-blank-popup-after-1s: frame.js FAILED, fetch: error Failed to fetch
seen by the handler added after SetNewWindow: http://app.localhost/popup.html
seen by the handler added after SetNewWindow: http://frame.localhost/frame.js
5-popup-page-itself: cross-origin frame.js loaded
seen by the handler added after SetNewWindow: http://frame.localhost/frame.html?6-cross-origin-iframe-in-popup-page
6-cross-origin-iframe-in-popup-page: frame.js FAILED, fetch: error Failed to fetch
seen by the handler added after SetNewWindow: http://app.localhost/favicon.ico
(http://frame.localhost/frame.js in this log is the script of the popup's top-level page, case 5.)
Cargo.toml
[package]
name = "popup-iframe-protocol"
version = "0.1.0"
edition = "2021"
[dependencies]
wry = "=0.55.1"
tao = "0.35"
webview2-com = "=0.38.2"
windows-core = "0.61"
src/main.rs
use std::{borrow::Cow, cell::{Cell, RefCell}, rc::Rc, time::Duration};
use tao::{
event::Event,
event_loop::{ControlFlow, EventLoopBuilder},
window::WindowBuilder,
};
use webview2_com::{take_pwstr, Microsoft::Web::WebView2::Win32::*, WebResourceRequestedEventHandler};
use windows_core::{Interface, HSTRING, PWSTR};
use wry::{
http::{header::CONTENT_TYPE, Request, Response},
NewWindowResponse, WebViewBuilder, WebViewBuilderExtWindows, WebViewExtWindows, WebViewId,
};
enum Ev {
Exit,
AfterSetNewWindow,
}
// REREGISTER=1: once wry has called SetNewWindow, add the filters again and a second handler that only logs.
unsafe fn reregister(webview: &ICoreWebView2) {
let w22: ICoreWebView2_22 = webview.cast().unwrap();
for f in ["http://app.localhost/*", "http://frame.localhost/*"] {
w22.AddWebResourceRequestedFilterWithRequestSourceKinds(
&HSTRING::from(f),
COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL,
COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL,
)
.unwrap();
}
let mut token = 0i64;
webview
.add_WebResourceRequested(
&WebResourceRequestedEventHandler::create(Box::new(|_, args| {
if let Some(args) = args {
let mut uri = PWSTR::null();
args.Request()?.Uri(&mut uri)?;
println!(" seen by the handler added after SetNewWindow: {}", take_pwstr(uri));
}
Ok(())
})),
&mut token,
)
.unwrap();
}
// The page is served by the `app` protocol (http://app.localhost/), the iframes by `frame`
// (http://frame.localhost/, cross-origin) or by `app` (same-origin). Both protocols serve the same files.
const MAIN: &str = r#"<!doctype html><title>main</title>
<iframe src="http://frame.localhost/frame.html?1-cross-origin-iframe-in-main-window"></iframe>
<script>
addEventListener('message', (e) => window.ipc.postMessage(String(e.data)));
const frame = (doc, origin, name) => {
const f = doc.createElement('iframe');
f.src = origin + '/frame.html?' + name;
doc.body.append(f);
};
setTimeout(() => {
// about:blank popup, filled by the opener right after window.open()
const w = window.open('about:blank', 'a', 'popup,width=500,height=300');
w.document.open(); w.document.write('<!doctype html><title>a</title>'); w.document.close();
frame(w.document, 'http://app.localhost', '2-same-origin-iframe-in-about-blank-popup');
frame(w.document, 'http://frame.localhost', '3-cross-origin-iframe-in-about-blank-popup');
}, 500);
setTimeout(() => {
const w = window.open('about:blank', 'b', 'popup,width=500,height=300');
setTimeout(() => frame(w.document, 'http://frame.localhost', '4-cross-origin-iframe-in-about-blank-popup-after-1s'), 1000);
}, 1500);
setTimeout(() => window.open('popup.html', 'c', 'popup,width=500,height=300'), 3500);
</script>"#;
const POPUP: &str = r#"<!doctype html><title>c</title>
<script src="http://frame.localhost/frame.js"></script>
<script>opener.postMessage('5-popup-page-itself: cross-origin frame.js ' + (window.frameJs ? 'loaded' : 'FAILED'), '*');</script>
<iframe src="http://frame.localhost/frame.html?6-cross-origin-iframe-in-popup-page"></iframe>"#;
const FRAME: &str = r#"<!doctype html>
<script src="frame.js"></script>
<script>
fetch('data.txt').then((r) => r.text(), (e) => 'error ' + e.message).then((f) =>
(top.opener || top).postMessage(location.search.slice(1) + ': frame.js ' +
(window.frameJs ? 'loaded' : 'FAILED') + ', fetch: ' + f, '*'));
</script>"#;
fn serve(_id: WebViewId, req: Request<Vec<u8>>) -> Response<Cow<'static, [u8]>> {
let (mime, body) = match req.uri().path() {
"/" => ("text/html", MAIN),
"/popup.html" => ("text/html", POPUP),
"/frame.html" => ("text/html", FRAME),
"/frame.js" => ("text/javascript", "window.frameJs = true;"),
"/data.txt" => ("text/plain", "ok"),
_ => ("text/plain", ""),
};
Response::builder()
.header(CONTENT_TYPE, mime)
.header("Access-Control-Allow-Origin", "*")
.body(Cow::Borrowed(body.as_bytes()))
.unwrap()
}
fn main() -> wry::Result<()> {
println!("WebView2 {}", wry::webview_version()?);
let event_loop = EventLoopBuilder::<Ev>::with_user_event().build();
let proxy = event_loop.create_proxy();
let timeout = proxy.clone();
let after = proxy.clone();
std::thread::spawn(move || {
std::thread::sleep(Duration::from_secs(10));
let _ = timeout.send_event(Ev::Exit);
});
// Windows for the popups, created up front and shown when the popup is requested.
let spare = Rc::new(RefCell::new(
(0..3)
.map(|_| WindowBuilder::new().with_visible(false).build(&event_loop).unwrap())
.collect::<Vec<_>>(),
));
let keep = Rc::new(RefCell::new(Vec::new()));
let reports = Rc::new(Cell::new(0));
let main_window = WindowBuilder::new().with_title("main").build(&event_loop).unwrap();
let keep_ = keep.clone();
let _main = WebViewBuilder::new()
.with_custom_protocol("app".into(), serve)
.with_custom_protocol("frame".into(), serve)
.with_url("http://app.localhost/")
.with_ipc_handler(move |req: Request<String>| {
println!("{}", req.body());
reports.set(reports.get() + 1);
if reports.get() == 6 {
let _ = proxy.send_event(Ev::Exit);
}
})
.with_new_window_req_handler(move |_url, features| {
let Some(window) = spare.borrow_mut().pop() else {
return NewWindowResponse::Deny;
};
let webview = WebViewBuilder::new()
.with_environment(features.opener.environment.clone())
.with_custom_protocol("app".into(), serve)
.with_custom_protocol("frame".into(), serve)
.build(&window)
.unwrap();
window.set_visible(true);
let core = webview.webview();
keep_.borrow_mut().push((window, webview));
if std::env::var_os("REREGISTER").is_some() {
let _ = after.send_event(Ev::AfterSetNewWindow);
}
NewWindowResponse::Create { webview: core }
})
.build(&main_window)?;
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::UserEvent(Ev::Exit) => *control_flow = ControlFlow::Exit,
Event::UserEvent(Ev::AfterSetNewWindow) => {
if let Some((_, webview)) = keep.borrow().last() {
unsafe { reregister(&webview.webview()) };
}
}
_ => {}
}
});
}
Repros in Edge Browser
No, issue does not reproduce in the corresponding Edge version
Regression
Don't know
Last working version (if regression)
No response
- Ngôn ngữ chính
- PowerShell
- Star
- 526
- Fork
- 68
- Merge trung bình
- 15 ngày 5 giờ
- Pull request đã merge (30 ngày)
- 1
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của MicrosoftEdge/WebView2Feedback
-
bug
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 72/100
MicrosoftEdge/WebView2Feedback#5749 · 1 bình luận ·
-
[Problem/Bug]: CSS animations/transitions freeze intermittently on runtime 156 when --force-high-performance-gpu is passedCó thể đã có người làm @ambikakunnath đã nhận 1 ngày trước. Đang mởregression
MicrosoftEdge/WebView2Feedback#5788 · 1 người được giao ·
-
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 30/100
MicrosoftEdge/WebView2Feedback#5786 ·
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 36/100
MicrosoftEdge/WebView2Feedback#5785 ·
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
MicrosoftEdge/WebView2Feedback#5784 ·
Tất cả issue của MicrosoftEdge/WebView2Feedback
Issue tương tự
-
Bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Fix unused variable warningsĐang mởbug triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
envoyproxy/envoy#48897 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
backend bug documentation
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
geolens-io/geolens#3568 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Condition block says two different large integers are equal (compares numeric strings as floats)Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Significant-Gravitas/AutoGPT#16480 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
API: `tsc.exe` opens a visible console window on Windows when the parent process has no consoleĐang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
microsoft/TypeScript#65083 ·
Maintainer thường phản hồi trong vòng 1 ngày