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::http_status::HttpStatus;
9use net_traits::request::Request;
10use net_traits::response::{Response, ResponseBody};
11use net_traits::{NetworkError, ResourceFetchTimingContainer};
12
13use crate::embedder::NetToEmbedderMsg;
14
15#[derive(Clone)]
16pub struct RequestInterceptor {
17    embedder_proxy: GenericEmbedderProxy<NetToEmbedderMsg>,
18}
19
20impl RequestInterceptor {
21    pub fn new(embedder_proxy: GenericEmbedderProxy<NetToEmbedderMsg>) -> RequestInterceptor {
22        RequestInterceptor { embedder_proxy }
23    }
24
25    pub(crate) async fn intercept_request(
26        &self,
27        request: &mut Request,
28        response: &mut Option<Response>,
29        timing_info: &ResourceFetchTimingContainer,
30    ) {
31        let (sender, mut receiver) = tokio::sync::mpsc::unbounded_channel();
32        let is_for_main_frame = matches!(request.destination, Destination::Document);
33        let web_resource_request = WebResourceRequest {
34            method: request.method.clone(),
35            url: request.url(),
36            headers: request.headers.clone(),
37            destination: request.destination,
38            referrer_url: request.referrer.to_url().cloned(),
39            is_for_main_frame,
40            is_redirect: request.redirect_count > 0,
41        };
42
43        self.embedder_proxy
44            .send(NetToEmbedderMsg::WebResourceRequested(
45                request.target_webview_id,
46                web_resource_request,
47                sender,
48            ));
49
50        // TODO: use done_chan and run in CoreResourceThreadPool.
51        let mut accumulated_body = Vec::new();
52        while let Some(message) = receiver.recv().await {
53            match message {
54                WebResourceResponseMsg::Start(webresource_response) => {
55                    let timing = timing_info.inner().clone();
56                    let mut response_override =
57                        Response::new(webresource_response.url.into(), timing);
58                    response_override.headers = webresource_response.headers;
59                    response_override.status = HttpStatus::new(
60                        webresource_response.status_code,
61                        webresource_response.status_message,
62                    );
63                    *response = Some(response_override);
64                },
65                WebResourceResponseMsg::SendBodyData(data) => {
66                    accumulated_body.push(data);
67                },
68                WebResourceResponseMsg::FinishLoad => {
69                    if accumulated_body.is_empty() {
70                        break;
71                    }
72                    let Some(response) = response.as_mut() else {
73                        error!("Received unexpected FinishLoad message");
74                        break;
75                    };
76                    *response.body.lock() =
77                        ResponseBody::Done(accumulated_body.into_iter().flatten().collect());
78                    break;
79                },
80                WebResourceResponseMsg::CancelLoad => {
81                    *response = Some(Response::network_error(NetworkError::LoadCancelled));
82                    break;
83                },
84                WebResourceResponseMsg::DoNotIntercept => break,
85            }
86        }
87    }
88}