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            is_for_main_frame,
39            is_redirect: request.redirect_count > 0,
40        };
41
42        self.embedder_proxy
43            .send(NetToEmbedderMsg::WebResourceRequested(
44                request.target_webview_id,
45                web_resource_request,
46                sender,
47            ));
48
49        // TODO: use done_chan and run in CoreResourceThreadPool.
50        let mut accumulated_body = Vec::new();
51        while let Some(message) = receiver.recv().await {
52            match message {
53                WebResourceResponseMsg::Start(webresource_response) => {
54                    let timing = context.timing.lock().clone();
55                    let mut response_override =
56                        Response::new(webresource_response.url.into(), timing);
57                    response_override.headers = webresource_response.headers;
58                    response_override.status = HttpStatus::new(
59                        webresource_response.status_code,
60                        webresource_response.status_message,
61                    );
62                    *response = Some(response_override);
63                },
64                WebResourceResponseMsg::SendBodyData(data) => {
65                    accumulated_body.push(data);
66                },
67                WebResourceResponseMsg::FinishLoad => {
68                    if accumulated_body.is_empty() {
69                        break;
70                    }
71                    let Some(response) = response.as_mut() else {
72                        error!("Received unexpected FinishLoad message");
73                        break;
74                    };
75                    *response.body.lock() =
76                        ResponseBody::Done(accumulated_body.into_iter().flatten().collect());
77                    break;
78                },
79                WebResourceResponseMsg::CancelLoad => {
80                    *response = Some(Response::network_error(NetworkError::LoadCancelled));
81                    break;
82                },
83                WebResourceResponseMsg::DoNotIntercept => break,
84            }
85        }
86    }
87}