Skip to main content

net/
request_interceptor.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use content_security_policy::Destination;
6use embedder_traits::{GenericEmbedderProxy, WebResourceRequest, WebResourceResponseMsg};
7use log::error;
8use net_traits::NetworkError;
9use net_traits::http_status::HttpStatus;
10use net_traits::request::Request;
11use net_traits::response::{Response, ResponseBody};
12
13use crate::embedder::NetToEmbedderMsg;
14use crate::fetch::methods::FetchContext;
15
16#[derive(Clone)]
17pub struct RequestInterceptor {
18    embedder_proxy: GenericEmbedderProxy<NetToEmbedderMsg>,
19}
20
21impl RequestInterceptor {
22    pub fn new(embedder_proxy: GenericEmbedderProxy<NetToEmbedderMsg>) -> RequestInterceptor {
23        RequestInterceptor { embedder_proxy }
24    }
25
26    pub async fn intercept_request(
27        &self,
28        request: &mut Request,
29        response: &mut Option<Response>,
30        context: &FetchContext,
31    ) {
32        let (sender, mut receiver) = tokio::sync::mpsc::unbounded_channel();
33        let is_for_main_frame = matches!(request.destination, Destination::Document);
34        let web_resource_request = WebResourceRequest {
35            method: request.method.clone(),
36            url: request.url().into_url(),
37            headers: request.headers.clone(),
38            destination: request.destination,
39            referrer_url: request.referrer.to_url().map(|url| url.as_url().clone()),
40            is_for_main_frame,
41            is_redirect: request.redirect_count > 0,
42        };
43
44        self.embedder_proxy
45            .send(NetToEmbedderMsg::WebResourceRequested(
46                request.target_webview_id,
47                web_resource_request,
48                sender,
49            ));
50
51        // TODO: use done_chan and run in CoreResourceThreadPool.
52        let mut accumulated_body = Vec::new();
53        while let Some(message) = receiver.recv().await {
54            match message {
55                WebResourceResponseMsg::Start(webresource_response) => {
56                    let timing = context.timing.inner().clone();
57                    let mut response_override =
58                        Response::new(webresource_response.url.into(), timing);
59                    response_override.headers = webresource_response.headers;
60                    response_override.status = HttpStatus::new(
61                        webresource_response.status_code,
62                        webresource_response.status_message,
63                    );
64                    *response = Some(response_override);
65                },
66                WebResourceResponseMsg::SendBodyData(data) => {
67                    accumulated_body.push(data);
68                },
69                WebResourceResponseMsg::FinishLoad => {
70                    if accumulated_body.is_empty() {
71                        break;
72                    }
73                    let Some(response) = response.as_mut() else {
74                        error!("Received unexpected FinishLoad message");
75                        break;
76                    };
77                    *response.body.lock() =
78                        ResponseBody::Done(accumulated_body.into_iter().flatten().collect());
79                    break;
80                },
81                WebResourceResponseMsg::CancelLoad => {
82                    *response = Some(Response::network_error(NetworkError::LoadCancelled));
83                    break;
84                },
85                WebResourceResponseMsg::DoNotIntercept => break,
86            }
87        }
88    }
89}