Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

How to intercept an HTTP API request from webview? #1087

Open
prabhupant opened this issue Nov 20, 2023 · 4 comments
Open

How to intercept an HTTP API request from webview? #1087

prabhupant opened this issue Nov 20, 2023 · 4 comments

Comments

@prabhupant
Copy link

prabhupant commented Nov 20, 2023

I want to intercept the HTTP request that comes from WebView in Wry. Here is my code

use wry::{
    application::{
        event::{Event, StartCause, WindowEvent},
        event_loop::{ControlFlow, EventLoop},
        window::WindowBuilder,
    },
    webview,
};
use wry::http::{HeaderMap, HeaderValue};

fn main() -> wry::Result<()> {


    let user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36";

    let mut header = HeaderMap::new();
    header.append("User-Agent", HeaderValue::from_static(user_agent));

    let event_loop = EventLoop::new();
    
    let window = WindowBuilder::new()
        .with_title("Clone Teams")
        .on_web_resource_request()
        .build(&event_loop)?;

    let _webview = webview::WebViewBuilder::new(window)?
        .with_url_and_headers("https://teams.microsoft.com", header)?
        .with_user_agent(user_agent)
        .with_clipboard(true)
        .build()?;

    webview::WebView::clear_all_browsing_data(&_webview).expect("Error while clearing cache");

    event_loop.run(move |event, _, control_flow| {
        *control_flow = ControlFlow::Wait;

        let url = _webview.url();

        if url.as_str().contains("beta/users") {
            println!("URL Is {}", url);
        }

        match event {
            Event::NewEvents(StartCause::Init) => println!("CloneTeams has started!"),
            Event::WindowEvent {
                event: WindowEvent::CloseRequested,
                ..
            } => *control_flow = ControlFlow::Exit,
            _ => (),
        }
    });
}

I was able to do all the things here with Teams, open the app and login, but I want to see how can I intercept the HTTP requests that are made by Teams while it is inside my Wry's WebView.

I could not find any method in WebView of Wry that can give me that.

There was one in Tauri on_web_resource_request (ref) but it returns a Builder<Wry> type which I could not inject into the Wry window here.

Can someone help me with this? Any help would be appreciated

@wusyong
Copy link
Member

wusyong commented Nov 21, 2023

That one from Tauri is built from custom protocol I believe. Wry doesn't provide any callback or method to intercept HTTP request except custom protocol unfortunately.

@prabhupant
Copy link
Author

How can I use the Tauri one? I tried this but it didn't work. I think this only works when the HTTP protocol is tauri

tauri::Builder::default()
        .setup(|app| {
            WindowBuilder::new(app, "core", WindowUrl::External(final_url))
                .on_web_resource_request(|request, response| {
                    // if request.uri().contains("beta/users") {
                        println!("Capturing the request {}", request.uri());
                    }
                )
                .user_agent(user_agent)
                .build()?;
            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");

@wusyong
Copy link
Member

wusyong commented Nov 22, 2023

I mean the tauri one is still built by wry's function. And wry can only intercept those URL belongs to custom protocol.
Wry couldn't intercept outer HTTP URL yet. It can only handle the request that defined by users.

@liesauer
Copy link

need here too, i want to intercept every requests and decides what url will be blocked when loading remote websites. i had achieved successfully a long time ago by modifying the wry, but a "official solution" will be better.

diff --git a/src/webview/mod.rs b/src/webview/mod.rs
index 03b457c..fc03cb7 100644
--- a/src/webview/mod.rs
+++ b/src/webview/mod.rs
@@ -162,6 +162,9 @@ pub struct WebViewAttributes {
   /// allow to navigate and false is not.
   pub navigation_handler: Option<Box<dyn Fn(String) -> bool>>,
 
+  // Set a request filter to decide if incoming url is allowed to request.
+  pub system_request_filter: Option<Box<dyn Fn(String) -> bool>>,
+
   /// Set a download started handler to manage incoming downloads.
   ///
   /// The closure takes two parameters - the first is a `String` representing the url being downloaded from and and the
@@ -231,6 +234,7 @@ impl Default for WebViewAttributes {
       ipc_handler: None,
       file_drop_handler: None,
       navigation_handler: None,
+      system_request_filter: None,
       download_started_handler: None,
       download_completed_handler: None,
       new_window_req_handler: None,
@@ -477,6 +481,12 @@ impl<'a> WebViewBuilder<'a> {
     self
   }
 
+  // Set a request filter to decide if incoming url is allowed to request.
+  pub fn with_system_request_filter(mut self, callback: impl Fn(String) -> bool + 'static) -> Self {
+    self.webview.system_request_filter = Some(Box::new(callback));
+    self
+  }
+
   /// Set a download started handler to manage incoming downloads.
   ///
   /// The closure takes two parameters - the first is a `String` representing the url being downloaded from and and the
diff --git a/src/webview/webview2/mod.rs b/src/webview/webview2/mod.rs
index 1e7af7a..bf04b47 100644
--- a/src/webview/webview2/mod.rs
+++ b/src/webview/webview2/mod.rs
@@ -40,7 +40,7 @@ use windows::{
 use webview2_com::{Microsoft::Web::WebView2::Win32::*, *};
 
 use crate::application::{platform::windows::WindowExtWindows, window::Window};
-use http::Request;
+use http::{Request, StatusCode};
 
 impl From<webview2_com::Error> for Error {
   fn from(err: webview2_com::Error) -> Self {
@@ -452,6 +452,17 @@ window.addEventListener('mousemove', (e) => window.chrome.webview.postMessage('_
 
     let mut custom_protocol_names = HashSet::new();
     if !attributes.custom_protocols.is_empty() {
+      // intercept all requests
+      if attributes.system_request_filter.is_some() {
+        unsafe {
+          webview.AddWebResourceRequestedFilter(
+            PCWSTR::from_raw(encode_wide("*".to_string()).as_ptr()),
+            COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL,
+          )
+        }
+        .map_err(webview2_com::Error::WindowsError)?;
+      }
+
       for (name, _) in &attributes.custom_protocols {
         // WebView2 doesn't support non-standard protocols yet, so we have to use this workaround
         // See https://github.com/MicrosoftEdge/WebView2Feedback/issues/73
@@ -465,6 +476,8 @@ window.addEventListener('mousemove', (e) => window.chrome.webview.postMessage('_
         .map_err(webview2_com::Error::WindowsError)?;
       }
 
+      let system_request_filter = attributes.system_request_filter;
+
       let custom_protocols = attributes.custom_protocols;
       let env = env.clone();
       unsafe {
@@ -595,6 +608,28 @@ window.addEventListener('mousemove', (e) => window.chrome.webview.postMessage('_
                     }
                     Err(_) => Err(E_FAIL.into()),
                   };
+                } else if let Some(system_request_filter) = &system_request_filter {
+                  let allow = system_request_filter(uri);
+
+                  if !allow {
+                    let stream = CreateStreamOnHGlobal(0, true)?;
+                    stream.SetSize(0 as u64)?;
+
+                    let body = Some(stream);
+
+                    let status_code = StatusCode::NOT_FOUND;
+
+                    let response = env.CreateWebResourceResponse(
+                      body.as_ref(),
+                      404 as i32,
+                      PCWSTR::from_raw(
+                        encode_wide(status_code.canonical_reason().unwrap_or("OK")).as_ptr(),
+                      ),
+                      PCWSTR::from_raw(encode_wide(String::default()).as_ptr()),
+                    )?;
+
+                    args.SetResponse(&response)?;
+                  }
                 }
               }

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants