mysql_async/local_infile_handler/
builtin.rs

1// Copyright (c) 2016 Anatoly Ikorsky
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9use futures_util::FutureExt;
10use tokio::fs::File;
11use tokio_util::io::ReaderStream;
12
13use std::{
14    collections::HashSet,
15    path::{Path, PathBuf},
16};
17
18use crate::{
19    error::LocalInfileError,
20    local_infile_handler::{BoxFuture, GlobalHandler},
21};
22
23/// Handles `LOCAL INFILE` requests from filesystem using an explicit whitelist of paths.
24///
25/// Example usage:
26///
27/// ```rust
28/// use mysql_async::{OptsBuilder, WhiteListFsHandler};
29///
30/// # let database_url = "mysql://root:password@127.0.0.1:3307/mysql";
31/// let mut opts = OptsBuilder::from_opts(database_url);
32/// opts.local_infile_handler(Some(WhiteListFsHandler::new(
33///     &["path/to/local_infile.txt"][..],
34/// )));
35/// ```
36#[derive(Clone, Debug)]
37pub struct WhiteListFsHandler {
38    white_list: HashSet<PathBuf>,
39}
40
41impl WhiteListFsHandler {
42    pub fn new<A, B>(white_list: B) -> WhiteListFsHandler
43    where
44        A: Into<PathBuf>,
45        B: IntoIterator<Item = A>,
46    {
47        let mut white_list_set = HashSet::new();
48        for path in white_list.into_iter() {
49            white_list_set.insert(Into::<PathBuf>::into(path));
50        }
51        WhiteListFsHandler {
52            white_list: white_list_set,
53        }
54    }
55}
56
57impl GlobalHandler for WhiteListFsHandler {
58    fn handle(&self, file_name: &[u8]) -> BoxFuture<'static, super::InfileData> {
59        let path = String::from_utf8_lossy(file_name);
60        let path = self
61            .white_list
62            .get(Path::new(&*path))
63            .cloned()
64            .ok_or_else(|| LocalInfileError::PathIsNotInTheWhiteList(path.into_owned()));
65        async move {
66            let file = File::open(path?).await?;
67            Ok(Box::pin(ReaderStream::new(file)) as super::InfileData)
68        }
69        .boxed()
70    }
71}