Skip to content
Snippets Groups Projects
Unverified Commit 9f509c0a authored by Louis's avatar Louis :fire:
Browse files

Update versions, merge file config with cli config, file upload routing

parent 22602d57
No related branches found
No related tags found
No related merge requests found
This diff is collapsed.
...@@ -13,7 +13,7 @@ license = "GPL-3.0+" ...@@ -13,7 +13,7 @@ license = "GPL-3.0+"
categories = ["command-line-utilities", "web-programming::http-server"] categories = ["command-line-utilities", "web-programming::http-server"]
keywords = ["file-server", "executable"] keywords = ["file-server", "executable"]
exlude = [ exclude = [
".travis.yml", ".travis.yml",
"example/*", "example/*",
] ]
...@@ -26,11 +26,14 @@ lto = true ...@@ -26,11 +26,14 @@ lto = true
[dependencies] [dependencies]
rocket = "0.3.3" rocket = "0.3.8"
rocket_codegen = "0.3.3" rocket_codegen = "0.3.8"
rocket_contrib = "0.3.3" rocket_contrib = "0.3.8"
serde = "1" serde = "1"
serde_derive = "1" serde_derive = "1"
docopt = "0.8" docopt = "0.8"
formdata = "0.12.2" formdata = "0.12.2"
hyper = "0.10" hyper = "0.10"
\ No newline at end of file rand = "0.3"
rhai = "0.7"
serde_yaml = "0.7.3"
#![feature(plugin)] #![feature(plugin)]
#![plugin(rocket_codegen)] #![plugin(rocket_codegen)]
extern crate serde;
#[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_derive;
extern crate serde_yaml;
extern crate rhai;
extern crate rocket; extern crate rocket;
extern crate rocket_contrib; extern crate rocket_contrib;
extern crate formdata; extern crate formdata;
extern crate hyper; extern crate hyper;
extern crate rand;
pub mod scripting;
pub mod cli; pub mod cli;
pub mod routing; pub mod routing;
\ No newline at end of file
...@@ -6,30 +6,62 @@ extern crate alloc_system; ...@@ -6,30 +6,62 @@ extern crate alloc_system;
extern crate rocket; extern crate rocket;
extern crate docopt; extern crate docopt;
extern crate swerve; extern crate swerve;
extern crate rhai;
use std::{path, fs, process}; use rhai::Engine;
use std::{path, process, io};
use std::fs::{self, File};
use docopt::Docopt; use docopt::Docopt;
use rocket::response::NamedFile; use rocket::response::NamedFile;
use rocket::http::ContentType;
use rocket::{Response, Request};
use swerve::cli; use swerve::cli;
use swerve::routing; use swerve::routing;
use swerve::scripting;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use rocket::response::Responder;
struct TypedFile {
file: File,
content_type: Option<ContentType>,
path: PathBuf,
}
impl TypedFile {
pub fn open<P: AsRef<Path>>(path: P, content_type: Option<rocket::http::ContentType>) -> TypedFile {
let file = File::open(path.as_ref()).unwrap();
TypedFile { file, content_type, path: (*path.as_ref()).to_path_buf() }
}
}
impl rocket::response::Responder<'static> for TypedFile {
fn respond_to(self, _: &Request) -> Result<Response<'static>, rocket::http::Status> {
let mut response = Response::new();
if let Some(content_type) = self.content_type {
response.set_header(content_type);
} else {
response.set_header(ContentType::from_extension(&self.path.extension().unwrap().to_string_lossy()).unwrap());
}
response.set_streamed_body(BufReader::new(self.file));
Ok(response)
}
}
#[get("/")] #[get("/")]
fn serve_root(args: rocket::State<cli::Args>) -> Option<NamedFile> { fn serve_root(args: rocket::State<cli::Args>) -> Option<TypedFile> {
serve_files(None, args) serve_files(None, args)
} }
#[get("/<file..>")] #[get("/<file..>")]
fn serve_files(file: Option<path::PathBuf>, args: rocket::State<cli::Args>) -> Option<NamedFile> { fn serve_files(file: Option<path::PathBuf>, args: rocket::State<cli::Args>) -> Option<TypedFile> {
let stub = match file { let stub = match file {
Some(path) => path, Some(path) => path,
None => path::PathBuf::from(""), None => path::PathBuf::from(""),
}; };
let path = match args.flag_dir { let path = args.get_dir().join(stub);
Some(ref root) => path::PathBuf::from(root).join(stub),
None => stub,
};
let meta = match fs::metadata(&path) { let meta = match fs::metadata(&path) {
Ok(metadata) => metadata, Ok(metadata) => metadata,
...@@ -37,30 +69,34 @@ fn serve_files(file: Option<path::PathBuf>, args: rocket::State<cli::Args>) -> O ...@@ -37,30 +69,34 @@ fn serve_files(file: Option<path::PathBuf>, args: rocket::State<cli::Args>) -> O
}; };
if meta.is_dir() && !args.flag_no_index { if meta.is_dir() && !args.flag_no_index {
NamedFile::open(path.join("index.html")).ok() Some(TypedFile::open(path.join("index.html"), None))
} else { } else {
NamedFile::open(path).ok() if &path.extension().unwrap().to_string_lossy() == "wasm" {
Some( TypedFile::open(path, Some(ContentType::new("application", "wasm"))))
} else {
Some(TypedFile::open(path, None))
}
} }
} }
fn config_from_args(args: cli::Args) -> rocket::Config { fn config_from_args(args: cli::Args, config: cli::SwerveConfig) -> rocket::Config {
let mut builder = rocket::Config::build(rocket::config::Environment::Development); let mut builder = rocket::Config::build(rocket::config::Environment::Development);
if let Some(threads) = args.flag_threads { if let Some(threads) = args.flag_threads {
builder = builder.workers(threads); builder = builder.workers(threads);
} else { } else {
builder = builder.workers(32); builder = builder.workers(config.server.threads);
} }
if let Some(port) = args.flag_port { if let Some(port) = args.flag_port {
builder = builder.port(port); builder = builder.port(port);
} else { } else {
builder = builder.port(8200); builder = builder.port(config.server.port);
} }
if let Some(address) = args.flag_address { if let Some(address) = args.flag_address {
builder = builder.address(address); builder = builder.address(address);
} else { } else {
builder = builder.address("localhost"); builder = builder.address(config.server.address);
} }
builder.finalize().unwrap() builder.finalize().unwrap()
...@@ -76,11 +112,25 @@ fn main() { ...@@ -76,11 +112,25 @@ fn main() {
process::exit(0); process::exit(0);
} }
let config = config_from_args(args.clone()); if args.flag_license {
cli::gpl::show_license_and_exit();
}
let config_path = args.get_dir().join(".swerve/config.yml");
let swerve_config = cli::SwerveConfig::from_file(&config_path).unwrap_or_else(|e| {
println!("Error in config file {} | {}", config_path.to_string_lossy(), e);
std::process::exit(2);
});
let server_config = config_from_args(args.clone(), swerve_config.clone());
println!("{:?}", swerve_config);
let mut server = rocket::custom(config, false) let mut server = rocket::custom(server_config, false)
.manage(args.clone()) .manage(args.clone())
.mount("/upload", routes![swerve::routing::mock_upload::to_file]) .manage(swerve_config);
server = server.mount("/upload", routes![swerve::routing::mock_upload::to_file])
.mount("/", routes![serve_root, serve_files]); .mount("/", routes![serve_root, serve_files]);
if !args.flag_quiet { if !args.flag_quiet {
...@@ -93,6 +143,7 @@ fn main() { ...@@ -93,6 +143,7 @@ fn main() {
println!("{} {}", req.method(), req.uri()); println!("{} {}", req.method(), req.uri());
})); }));
} }
{
server.launch(); server.launch();
}
} }
\ No newline at end of file
use rocket::Data; use rocket::{Data, State};
use formdata::{read_formdata}; use formdata::{read_formdata};
use routing::request::ConvertedHeaders; use routing::request::ConvertedHeaders;
use hyper::header::{Headers, ContentDisposition}; use hyper::header::{Headers, ContentDisposition, DispositionParam};
use rocket::request::FromRequest; use rocket::request::FromRequest;
use std::io::{Read, Write, copy}; use std::io::{Read, Write, copy};
use std::io::{BufReader, BufWriter}; use std::io::{BufReader, BufWriter};
use std::fs::{OpenOptions, File}; 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>")] #[post(path = "/", data = "<upload>")]
pub fn to_file(headers: ConvertedHeaders, upload: Data) -> String { pub fn to_file(headers: ConvertedHeaders, conf: State<SwerveConfig>, upload: Data) -> Result<String, String> {
let formdata = read_formdata(&mut upload.open(), &headers.as_hyper()); let formdata = read_formdata(&mut upload.open(), &headers.as_hyper());
if let Ok(data) = formdata { 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 { for file in data.files {
let (fieldname, fieldvalue) = file; let (name, value) = file;
if fieldname == String::from("upload") { if name == String::from("upload") {
let mut input = File::open(fieldvalue.path.clone()).unwrap(); let content_disposition = value.headers.get::<ContentDisposition>().unwrap();
let mut output = OpenOptions::new().write(true).open("upload_data").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(); copy(&mut input, &mut output).unwrap();
println!("File written to {}", file_name.unwrap());
} }
} }
String::from("Complete") Ok(String::from("Complete"))
} else { } else {
String::from("Failed") 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
}
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
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment