-
-
Notifications
You must be signed in to change notification settings - Fork 60
/
Copy pathimport.rs
83 lines (71 loc) · 2.7 KB
/
import.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use multipart::server::Multipart;
use rocket::http::ContentType;
use rocket::http::Status;
use rocket::Data;
use rocket::State;
use rocket_contrib::json::Json;
use std::io::Read;
use std::sync::Mutex;
use aw_models::BucketsExport;
use aw_datastore::Datastore;
use crate::endpoints::{HttpErrorJson, ServerState};
fn import(datastore_mutex: &Mutex<Datastore>, import: BucketsExport) -> Result<(), HttpErrorJson> {
let datastore = endpoints_get_lock!(datastore_mutex);
for (_bucketname, bucket) in import.buckets {
match datastore.create_bucket(&bucket) {
Ok(_) => (),
Err(e) => {
let err_msg = format!("Failed to import bucket: {:?}", e);
warn!("{}", err_msg);
return Err(HttpErrorJson::new(Status::InternalServerError, err_msg));
}
}
}
Ok(())
}
#[post("/", data = "<json_data>", format = "application/json")]
pub fn bucket_import_json(
state: State<ServerState>,
json_data: Json<BucketsExport>,
) -> Result<(), HttpErrorJson> {
import(&state.datastore, json_data.into_inner())
}
// FIXME: This eats a lot of RAM (double the amount of the size of the file imported)
// In Rocket 0.5 this will likely be improved when native multipart support is added
#[post("/", data = "<data>", format = "multipart/form-data")]
pub fn bucket_import_form(
state: State<ServerState>,
cont_type: &ContentType,
data: Data,
) -> Result<(), HttpErrorJson> {
let (_, boundary) = cont_type
.params()
.find(|&(k, _)| k == "boundary")
.ok_or_else(|| {
return HttpErrorJson::new(
Status::BadRequest,
"`Content-Type: multipart/form-data` boundary param not provided".to_string(),
);
})?;
let string = process_multipart_packets(boundary, data);
let import_data: BucketsExport = serde_json::from_str(&string)
.expect("Failed to deserialize import data as JSON to bucket format");
import(&state.datastore, import_data)
}
// NOTE: this is far from a optimal way of parsing multipart packets as it doesn't check
// headers and can be used for denial-of-service attacks as we don't have a size limit and
// store everything in RAM
fn process_multipart_packets(boundary: &str, data: Data) -> String {
let mut content = String::new();
Multipart::with_body(data.open(), boundary)
.foreach_entry(|mut entry| {
let mut string = String::new();
entry
.data
.read_to_string(&mut string)
.expect("Failed to parse multipart data to utf-8");
content.push_str(&string);
})
.expect("Failed to retrieve multipart upload");
content
}