windows_webview/
protocol.rs1use super::*;
2use std::cell::RefCell;
3use windows_core::implement_decl;
4
5pub(crate) const WEB_RESOURCE_CONTEXT_ALL: COREWEBVIEW2_WEB_RESOURCE_CONTEXT = 0;
7
8const WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL: COREWEBVIEW2_WEB_RESOURCE_REQUEST_SOURCE_KINDS =
11 u32::MAX;
12
13pub(crate) unsafe fn add_requested_filter(
15 webview: &ICoreWebView2,
16 uri: impl Param<PCWSTR>,
17) -> Result<()> {
18 unsafe {
19 match webview.cast::<ICoreWebView2_22>() {
20 Ok(webview) => webview
21 .AddWebResourceRequestedFilterWithRequestSourceKinds(
22 uri,
23 WEB_RESOURCE_CONTEXT_ALL,
24 WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL,
25 )
26 .ok(),
27 Err(_) => webview
28 .AddWebResourceRequestedFilter(uri, WEB_RESOURCE_CONTEXT_ALL)
29 .ok(),
30 }
31 }
32}
33
34pub(crate) unsafe fn remove_requested_filter(webview: &ICoreWebView2, uri: impl Param<PCWSTR>) {
36 let _ = unsafe {
37 match webview.cast::<ICoreWebView2_22>() {
38 Ok(webview) => webview.RemoveWebResourceRequestedFilterWithRequestSourceKinds(
39 uri,
40 WEB_RESOURCE_CONTEXT_ALL,
41 WEB_RESOURCE_REQUEST_SOURCE_KINDS_ALL,
42 ),
43 Err(_) => webview.RemoveWebResourceRequestedFilter(uri, WEB_RESOURCE_CONTEXT_ALL),
44 }
45 };
46}
47
48pub struct WebResourceRequest(pub(crate) ICoreWebView2WebResourceRequest);
51
52impl WebResourceRequest {
53 pub fn uri(&self) -> String {
55 unsafe { string::take_result(self.0.Uri()) }
56 }
57
58 pub fn method(&self) -> String {
60 unsafe { string::take_result(self.0.Method()) }
61 }
62
63 pub fn headers(&self) -> Vec<(String, String)> {
65 unsafe { self.collect_headers() }.unwrap_or_default()
66 }
67
68 unsafe fn collect_headers(&self) -> Result<Vec<(String, String)>> {
69 let iterator = unsafe { self.0.Headers()?.GetIterator()? };
70 let mut headers = Vec::new();
71
72 while unsafe { iterator.HasCurrentHeader()? }.as_bool() {
73 let mut name: LPWSTR = std::ptr::null_mut();
74 let mut value: LPWSTR = std::ptr::null_mut();
75 unsafe { iterator.GetCurrentHeader(&mut name, &mut value).ok()? };
76 headers.push((unsafe { string::take(name) }, unsafe {
77 string::take(value)
78 }));
79 let _ = unsafe { iterator.MoveNext()? };
80 }
81
82 Ok(headers)
83 }
84}
85
86pub struct WebResourceResponse {
91 body: Vec<u8>,
92 status_code: i32,
93 reason_phrase: String,
94 headers: Vec<(String, String)>,
95}
96
97impl WebResourceResponse {
98 pub fn new(body: impl Into<Vec<u8>>) -> Self {
100 Self {
101 body: body.into(),
102 status_code: 200,
103 reason_phrase: "OK".to_string(),
104 headers: Vec::new(),
105 }
106 }
107
108 pub fn status(mut self, code: u16, reason: &str) -> Self {
111 self.status_code = i32::from(code);
112 self.reason_phrase = reason.to_string();
113 self
114 }
115
116 pub fn header(mut self, name: &str, value: &str) -> Self {
118 self.headers.push((name.to_string(), value.to_string()));
119 self
120 }
121
122 pub fn content_type(self, value: &str) -> Self {
124 self.header("Content-Type", value)
125 }
126
127 unsafe fn into_response(
128 self,
129 environment: &ICoreWebView2Environment,
130 ) -> Result<ICoreWebView2WebResourceResponse> {
131 let stream = if self.body.is_empty() {
132 None
133 } else {
134 unsafe { SHCreateMemStream(self.body.as_ptr(), self.body.len() as u32) }
135 };
136
137 let mut headers = String::new();
138 for (name, value) in &self.headers {
139 headers.push_str(name);
140 headers.push_str(": ");
141 headers.push_str(value);
142 headers.push_str("\r\n");
143 }
144
145 let reason = HSTRING::from(&self.reason_phrase);
146 let headers = HSTRING::from(&headers);
147
148 unsafe {
149 environment.CreateWebResourceResponse(
150 stream.as_ref(),
151 self.status_code,
152 &reason,
153 &headers,
154 )
155 }
156 }
157}
158
159pub(crate) struct WebResourceRequested {
161 handler: RefCell<Box<dyn FnMut(WebResourceRequest) -> Option<WebResourceResponse>>>,
162 environment: ICoreWebView2Environment,
163}
164
165implement_decl! {
166 impl WebResourceRequested as pub(crate) WebResourceRequested_Impl:
167 [ICoreWebView2WebResourceRequestedEventHandler]
168}
169
170impl WebResourceRequested {
171 pub(crate) fn create<F>(
172 environment: ICoreWebView2Environment,
173 handler: F,
174 ) -> ICoreWebView2WebResourceRequestedEventHandler
175 where
176 F: FnMut(WebResourceRequest) -> Option<WebResourceResponse> + 'static,
177 {
178 Self {
179 handler: RefCell::new(Box::new(handler)),
180 environment,
181 }
182 .into()
183 }
184}
185
186impl ICoreWebView2WebResourceRequestedEventHandler_Impl for WebResourceRequested_Impl {
187 fn Invoke(
188 &self,
189 _sender: Ref<ICoreWebView2>,
190 args: Ref<ICoreWebView2WebResourceRequestedEventArgs>,
191 ) -> Result<()> {
192 let args = args.ok()?;
193 let request = WebResourceRequest(unsafe { args.Request()? });
194
195 if let Some(response) = (*self.handler.borrow_mut())(request) {
196 let response = unsafe { response.into_response(&self.environment)? };
197 unsafe { args.SetResponse(&response).ok()? };
198 }
199
200 Ok(())
201 }
202}