1
0
Fork 0
mirror of https://codeberg.org/icewind/shelve.git synced 2026-06-03 12:04:09 +02:00
This commit is contained in:
Robin Appelman 2020-01-25 23:03:11 +01:00
commit fc84fdec52
5 changed files with 180 additions and 5 deletions

View file

@ -7,7 +7,6 @@ use rocket::http::{ContentType, RawStr};
use rocket::request::FromParam;
use rocket::response::{NamedFile, Redirect, Responder};
use rocket::*;
use rocket_upload::MultipartDatas;
use rust_embed::RustEmbed;
use serde::Serialize;
use std::borrow::Cow;
@ -20,9 +19,11 @@ use std::path::PathBuf;
use std::str::FromStr;
use std::thread::{sleep, spawn, JoinHandle};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use upload::MultipartDatas;
mod expire_queue;
mod token;
mod upload;
impl<'r> FromParam<'r> for UploadId {
type Error = InvalidUploadIdError;

161
src/upload.rs Normal file
View file

@ -0,0 +1,161 @@
use std::fs::{self, File};
use std::io::{Cursor, Read, Write};
use std::path::Path;
use rocket::data::{self, FromDataSimple};
use rocket::http::Status;
use rocket::{Data, Outcome, Outcome::*, Request};
use multipart::server::Multipart;
#[derive(Debug)]
pub struct TextPart {
pub key: String,
pub value: String,
}
#[derive(Debug)]
pub struct FilePart {
pub name: String,
pub path: String,
pub filename: String,
}
#[derive(Debug)]
pub struct MultipartDatas {
pub texts: Vec<TextPart>,
pub files: Vec<FilePart>,
}
impl FilePart {
pub fn persist(&self, p: &Path) {
let s = Path::join(p, &self.filename);
fs::copy(Path::new(&self.path), &s).unwrap();
}
}
impl Drop for FilePart {
fn drop(&mut self) {
fs::remove_file(Path::new(&self.path)).unwrap();
}
}
const TMP_PATH: &str = "/tmp/rust_upload/";
impl<'t> FromDataSimple for MultipartDatas {
type Error = String;
fn from_data(request: &Request, data: Data) -> data::Outcome<Self, String> {
let ct = request
.headers()
.get_one("Content-Type")
.expect("no content-type");
let idx = ct.find("boundary=").expect("no boundary");
let boundary = &ct[(idx + "boundary=".len())..];
let mut d = Vec::new();
data.stream_to(&mut d).expect("Unable to read");
let mut mp = Multipart::with_body(Cursor::new(d), boundary);
let mut texts = Vec::new();
let mut files = Vec::new();
let mut buffer = [0u8; 4096];
let mut err_out: Option<Outcome<_, (Status, _), _>> = None;
mp.foreach_entry(|entry| {
let mut data = entry.data;
if entry.headers.filename == None {
let mut text_buffer = Vec::new();
loop {
let c = match data.read(&mut buffer) {
Ok(c) => c,
Err(err) => {
return;
}
};
if c == 0 {
break;
}
text_buffer.extend_from_slice(&buffer[..c]);
}
let text = match String::from_utf8(text_buffer) {
Ok(s) => s,
Err(_err) => {
return;
}
};
texts.push(TextPart {
key: entry.headers.name.to_string(),
value: text,
});
} else {
let filename = entry.headers.filename.clone().unwrap();
if !Path::new(TMP_PATH).exists() {
fs::create_dir_all(TMP_PATH).unwrap();
}
let target_path = Path::join(Path::new(TMP_PATH), &filename);
let mut file = match File::create(&target_path) {
Ok(f) => f,
Err(err) => {
return;
}
};
let mut sum_c = 0u64;
loop {
let c = match data.read(&mut buffer) {
Ok(c) => c,
Err(err) => {
try_delete(&target_path);
return;
}
};
if c == 0 {
break;
}
sum_c = sum_c + c as u64;
match file.write(&buffer[..c]) {
Ok(_) => (),
Err(err) => {
try_delete(&target_path);
return;
}
}
}
files.push(FilePart {
name: entry.headers.name.to_string(),
path: String::from(TMP_PATH) + &filename,
filename: entry.headers.filename.clone().unwrap(),
})
}
})
.unwrap();
if let Some(failed) = err_out {
return failed;
} else {
let v = MultipartDatas {
texts: texts,
files: files,
};
return Outcome::Success(v);
}
}
}
#[inline]
fn try_delete<P: AsRef<Path>>(path: P) {
if fs::remove_file(path.as_ref()).is_err() {}
}