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
use rocket::{Data, State};
use formdata::{read_formdata, FilePart};
use routing::request::ConvertedHeaders;
use hyper::header::{Headers, ContentDisposition, DispositionParam};
use rocket::request::FromRequest;
use std::io::{Read, Write, copy};
use std::io::{BufReader, BufWriter};
use std::fs::{OpenOptions, File, create_dir};
use cli::{HandlerMethod, SwerveConfig};
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use rand::{Rng, StdRng};

#[post(path = "/", data = "<upload>")]
pub fn to_file(headers: ConvertedHeaders, conf: State<SwerveConfig>, upload: Data) -> Result<String, String> {
    let formdata = read_formdata(&mut upload.open(), &headers.as_hyper());
    if let Ok(data) = formdata {
        let fields = collect_fields(data.fields);
        match conf.field_handling {
            HandlerMethod::Log => println!("{:?}", fields),
            HandlerMethod::File => println!("{:?}", fields),
        }

        create_dir("uploads");

        for file in data.files {
            match conf.file_handling {
                HandlerMethod::Log => log_file(file),
                HandlerMethod::File => upload_file(file),
            }
        }
        Ok(String::from("Complete"))
    } else {
        Err(String::from("Failed"))
    }
}

fn collect_fields(fields: Vec<(String, String)>) -> HashMap<String, String> {
    let mut map = HashMap::with_capacity(fields.len());
    'collector: for (key, value) in fields {
        if value == String::from("undefined") { continue 'collector };
        map.insert(key.clone(), value.clone());
    }
    map
}

type Upload = (String, FilePart);

fn upload_file(file: Upload) {
    let (name, value) = file;
    let content_disposition = value.headers.get::<ContentDisposition>().unwrap();
    let file_name = filename_from_disposition(content_disposition);

    let mut input = File::open(value.path.clone()).unwrap();
    let mut output = OpenOptions::new()
        .write(true)
        .create(true)
        .open(PathBuf::from("uploads").join(file_name.clone().unwrap_or(String::from("upload_data"))))
        .unwrap();

    copy(&mut input, &mut output).unwrap();
    println!("File written to {}", file_name.unwrap());
}

fn log_file(file: Upload) {
    let (name, value) = file;
    println!("[UPLOAD] From field: {}. Size: {}", name, value.size.unwrap_or(0));
    for header in value.headers.iter() {
        println!("[UPLOAD] :: {}; {}", header.name(), header.value_string());
    }
}

fn filename_from_disposition(dispo: &ContentDisposition) -> Option<String> {
    for param in dispo.parameters.iter() {
        if let &DispositionParam::Filename(_, _, ref name_vec) = param {
            return Some(String::from_utf8(name_vec.to_vec()).unwrap_or(String::from("bad_filename.bin")));
        }
    }
    None
}