mysql_async/local_infile_handler/mod.rs
1// Copyright (c) 2017-2022 mysql_async Contributors.
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 bytes::Bytes;
10use futures_core::stream::BoxStream;
11
12use std::{
13 fmt,
14 sync::{
15 atomic::{AtomicUsize, Ordering},
16 Arc,
17 },
18};
19
20use crate::error::LocalInfileError;
21
22pub mod builtin;
23
24type BoxFuture<'a, T> = futures_core::future::BoxFuture<'a, Result<T, LocalInfileError>>;
25
26/// LOCAL INFILE data is a stream of `std::io::Result<Bytes>`.
27///
28/// The driver will send this data to the server in response to a LOCAL INFILE request.
29pub type InfileData = BoxStream<'static, std::io::Result<Bytes>>;
30
31/// Global, `Opts`-level `LOCAL INFILE` handler (see ["LOCAL INFILE Handlers"][2] section
32/// of the `README.md`).
33///
34/// **Warning:** You should be aware of [Security Considerations for LOAD DATA LOCAL][1].
35///
36/// The purpose of the handler is to emit infile data in response to a file name.
37/// This handler will be called if there is no [`LocalHandler`] installed for the connection.
38///
39/// The library will call this handler in response to a LOCAL INFILE request from the server.
40/// The server, in its turn, will emit LOCAL INFILE requests in response to a `LOAD DATA LOCAL`
41/// queries:
42///
43/// ```sql
44/// LOAD DATA LOCAL INFILE '<file name>' INTO TABLE <table>;
45/// ```
46///
47/// [1]: https://dev.mysql.com/doc/refman/8.0/en/load-data-local-security.html
48/// [2]: ../#local-infile-handlers
49pub trait GlobalHandler: Send + Sync + 'static {
50 fn handle(&self, file_name: &[u8]) -> BoxFuture<'static, InfileData>;
51}
52
53impl<T> GlobalHandler for T
54where
55 T: for<'a> Fn(&'a [u8]) -> BoxFuture<'static, InfileData>,
56 T: Send + Sync + 'static,
57{
58 fn handle(&self, file_name: &[u8]) -> BoxFuture<'static, InfileData> {
59 (self)(file_name)
60 }
61}
62
63static HANDLER_ID: AtomicUsize = AtomicUsize::new(0);
64
65#[derive(Clone)]
66pub struct GlobalHandlerObject(usize, Arc<dyn GlobalHandler>);
67
68impl GlobalHandlerObject {
69 pub(crate) fn new<T: GlobalHandler>(handler: T) -> Self {
70 Self(HANDLER_ID.fetch_add(1, Ordering::SeqCst), Arc::new(handler))
71 }
72
73 pub(crate) fn clone_inner(&self) -> Arc<dyn GlobalHandler> {
74 self.1.clone()
75 }
76}
77
78impl PartialEq for GlobalHandlerObject {
79 fn eq(&self, other: &Self) -> bool {
80 self.0 == other.0
81 }
82}
83
84impl Eq for GlobalHandlerObject {}
85
86impl fmt::Debug for GlobalHandlerObject {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 f.debug_tuple("GlobalHandlerObject").field(&"..").finish()
89 }
90}