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 base::generic_channel;
6use content_security_policy::Destination;
7use embedder_traits::{EmbedderMsg, EmbedderProxy, WebResourceRequest, WebResourceResponseMsg};
8use log::error;
9use net_traits::NetworkError;
10use net_traits::http_status::HttpStatus;
11use net_traits::request::Request;
12use net_traits::response::{Response, ResponseBody};
13
14use crate::fetch::methods::FetchContext;
15
16#[derive(Clone)]
17pub struct RequestInterceptor {
18    embedder_proxy: EmbedderProxy,
19}
20
21impl RequestInterceptor {
22    pub fn new(embedder_proxy: EmbedderProxy) -> RequestInterceptor {
23        RequestInterceptor { embedder_proxy }
24    }
25
26    pub fn intercept_request(
27        &self,
28        request: &mut Request,
29        response: &mut Option<Response>,
30        context: &FetchContext,
31    ) {
32        let (sender, receiver) = generic_channel::channel().unwrap();
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.send(EmbedderMsg::WebResourceRequested(
43            request.target_webview_id,
44            web_resource_request,
45            sender,
46        ));
47
48        // TODO: use done_chan and run in CoreResourceThreadPool.
49        let mut accumulated_body = Vec::new();
50        while let Ok(message) = receiver.recv() {
51            match message {
52                WebResourceResponseMsg::Start(webresource_response) => {
53                    let timing = context.timing.lock().unwrap().clone();
54                    let mut response_override =
55                        Response::new(webresource_response.url.into(), timing);
56                    response_override.headers = webresource_response.headers;
57                    response_override.status = HttpStatus::new(
58                        webresource_response.status_code,
59                        webresource_response.status_message,
60                    );
61                    *response = Some(response_override);
62                },
63                WebResourceResponseMsg::SendBodyData(data) => {
64                    accumulated_body.push(data);
65                },
66                WebResourceResponseMsg::FinishLoad => {
67                    if accumulated_body.is_empty() {
68                        break;
69                    }
70                    let Some(response) = response.as_mut() else {
71                        error!("Received unexpected FinishLoad message");
72                        break;
73                    };
74                    *response.body.lock().unwrap() =
75                        ResponseBody::Done(accumulated_body.into_iter().flatten().collect());
76                    break;
77                },
78                WebResourceResponseMsg::CancelLoad => {
79                    *response = Some(Response::network_error(NetworkError::LoadCancelled));
80                    break;
81                },
82                WebResourceResponseMsg::DoNotIntercept => break,
83            }
84        }
85    }
86}