Skip to main content

net/protocols/
data.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 std::future::Future;
6use std::pin::Pin;
7
8use data_url::DataUrl;
9use http::HeaderValue;
10use net_traits::http_status::HttpStatus;
11use net_traits::request::Request;
12use net_traits::response::{Response, ResponseBody};
13use net_traits::{NetworkError, ResourceFetchTiming};
14
15use crate::fetch::methods::{DoneChannel, FetchContext};
16use crate::protocols::ProtocolHandler;
17
18#[derive(Default)]
19pub struct DataProtocolHander {}
20
21impl ProtocolHandler for DataProtocolHander {
22    fn load(
23        &self,
24        request: &mut Request,
25        _done_chan: &mut DoneChannel,
26        _context: &FetchContext,
27    ) -> Pin<Box<dyn Future<Output = Response> + Send>> {
28        let url = request.current_url();
29
30        assert_eq!(url.scheme(), "data");
31
32        let response = match DataUrl::process(url.as_str()) {
33            Ok(data_url) => match data_url.decode_to_vec() {
34                Ok((bytes, _fragment_id)) => {
35                    let content_type = data_url.mime_type().to_string();
36                    let mut response =
37                        Response::new(url, ResourceFetchTiming::new(request.timing_type()));
38                    *response.body.lock() = ResponseBody::Done(bytes);
39
40                    if let Ok(content_type_header_value) = HeaderValue::from_str(&content_type) {
41                        response
42                            .headers
43                            .insert(http::header::CONTENT_TYPE, content_type_header_value);
44                    }
45
46                    response.status = HttpStatus::default();
47                    Some(response)
48                },
49                Err(_) => None,
50            },
51            Err(_) => None,
52        }
53        .unwrap_or_else(|| {
54            Response::network_error(NetworkError::ResourceLoadError(
55                "Decoding data URL failed".into(),
56            ))
57        });
58
59        Box::pin(std::future::ready(response))
60    }
61
62    fn is_fetchable(&self) -> bool {
63        true
64    }
65}