1
0
Fork 0
mirror of https://codeberg.org/icewind/shelve.git synced 2026-06-03 12:04:09 +02:00

update to rocket 0.5-rc1

This commit is contained in:
Robin Appelman 2021-07-30 13:57:30 +02:00
commit c359239d27
5 changed files with 1661 additions and 848 deletions

2499
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -6,16 +6,16 @@ edition = "2018"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
rocket = "0.4.2" rocket = "0.5.0-rc.1"
priority-queue = "0.6.0" priority-queue = "1"
hyper = "0.12" hyper = "0.14"
futures = "0.1.29" dotenv = "0.15"
dotenv = "0.15.0" err-derive = "0.3"
err-derive = "0.2.1" rand = "0.8"
rand = "0.7.2"
uuid = { version = "0.8", features = ["serde", "v4"] } uuid = { version = "0.8", features = ["serde", "v4"] }
rust-embed = "5.2.0" rust-embed = "5"
rocket_upload = "0.1.0" rocket_upload = "0.1"
serde = "1.0.104" serde = "1"
serde_json = "1.0.45" serde_json = "1"
multipart = "0.16.1" multipart = "0.18"
async-trait = "0.1"

View file

@ -1,12 +1,11 @@
#![feature(proc_macro_hygiene, decl_macro)]
use crate::expire_queue::{ExpireQueue, InvalidUploadIdError, UploadId}; use crate::expire_queue::{ExpireQueue, InvalidUploadIdError, UploadId};
use crate::token::{UploadToken, ValidTokens}; use crate::token::{UploadToken, ValidTokens};
use dotenv::dotenv; use dotenv::dotenv;
use rocket::http::{ContentType, RawStr}; use rocket::data::ToByteUnit;
use rocket::fs::NamedFile;
use rocket::request::FromParam; use rocket::request::FromParam;
use rocket::response::{NamedFile, Redirect, Responder}; use rocket::response::Redirect;
use rocket::*; use rocket::{get, launch, post, put, routes, Data, Responder, State};
use rust_embed::RustEmbed; use rust_embed::RustEmbed;
use serde::Serialize; use serde::Serialize;
use std::borrow::Cow; use std::borrow::Cow;
@ -14,7 +13,6 @@ use std::collections::HashMap;
use std::env::{self, current_dir}; use std::env::{self, current_dir};
use std::fs::{create_dir, read_dir, remove_dir_all, File}; use std::fs::{create_dir, read_dir, remove_dir_all, File};
use std::io; use std::io;
use std::io::Cursor;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use std::thread::{sleep, spawn, JoinHandle}; use std::thread::{sleep, spawn, JoinHandle};
@ -28,10 +26,8 @@ mod upload;
impl<'r> FromParam<'r> for UploadId { impl<'r> FromParam<'r> for UploadId {
type Error = InvalidUploadIdError; type Error = InvalidUploadIdError;
fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> { fn from_param(param: &'r str) -> Result<Self, Self::Error> {
let param = param.url_decode()?; UploadId::new(param)
UploadId::new(&param)
} }
} }
@ -39,23 +35,10 @@ impl<'r> FromParam<'r> for UploadId {
#[folder = "templates/"] #[folder = "templates/"]
struct Templates; struct Templates;
#[derive(Responder)]
#[response(content_type = "html")]
struct HtmlResponse(Cow<'static, [u8]>); struct HtmlResponse(Cow<'static, [u8]>);
impl<'r> Responder<'r> for HtmlResponse {
fn respond_to(self, _: &Request) -> response::Result<'r> {
match self.0 {
Cow::Borrowed(s) => Response::build()
.header(ContentType::HTML)
.sized_body(Cursor::new(s))
.ok(),
Cow::Owned(s) => Response::build()
.header(ContentType::HTML)
.sized_body(Cursor::new(s))
.ok(),
}
}
}
#[get("/")] #[get("/")]
fn home() -> HtmlResponse { fn home() -> HtmlResponse {
HtmlResponse(Templates::get("index.html").unwrap_or(Cow::Borrowed(b"Template not found"))) HtmlResponse(Templates::get("index.html").unwrap_or(Cow::Borrowed(b"Template not found")))
@ -72,13 +55,13 @@ fn now() -> u64 {
const THOUSAND_YEARS: u64 = 1000 * 356 * 24 * 60 * 60; const THOUSAND_YEARS: u64 = 1000 * 356 * 24 * 60 * 60;
#[put("/upload?<expire>&<name>", data = "<data>")] #[put("/upload?<expire>&<name>", data = "<data>")]
fn upload( async fn put_upload(
data: Data, data: Data<'_>,
expire: Option<u64>, expire: Option<u64>,
name: String, name: String,
_token: UploadToken, _token: UploadToken,
basedir: State<PathBuf>, basedir: &State<PathBuf>,
expire_queue: State<ExpireQueue>, expire_queue: &State<ExpireQueue>,
) -> io::Result<String> { ) -> io::Result<String> {
let id = UploadId::generate(now() + expire.unwrap_or(THOUSAND_YEARS)); let id = UploadId::generate(now() + expire.unwrap_or(THOUSAND_YEARS));
expire_queue.push(id); expire_queue.push(id);
@ -87,7 +70,7 @@ fn upload(
create_dir(&path)?; create_dir(&path)?;
path.push(name); path.push(name);
data.stream_to_file(path)?; data.open(2.gibibytes()).into_file(path).await?;
Ok(id.as_string()) Ok(id.as_string())
} }
@ -107,9 +90,9 @@ struct UploadData {
#[post("/upload", data = "<data>")] #[post("/upload", data = "<data>")]
fn post_upload( fn post_upload(
data: MultipartDatas, data: MultipartDatas,
accepted_tokens: State<ValidTokens>, accepted_tokens: &State<ValidTokens>,
basedir: State<PathBuf>, basedir: &State<PathBuf>,
expire_queue: State<ExpireQueue>, expire_queue: &State<ExpireQueue>,
) -> UploadResponse { ) -> UploadResponse {
let mut fields: HashMap<String, String> = data let mut fields: HashMap<String, String> = data
.texts .texts
@ -181,16 +164,17 @@ fn post_upload(
} }
#[get("/<id>/<name..>")] #[get("/<id>/<name..>")]
fn download(id: UploadId, name: PathBuf, basedir: State<PathBuf>) -> Option<NamedFile> { async fn download(id: UploadId, name: PathBuf, basedir: &State<PathBuf>) -> Option<NamedFile> {
if id.is_expired(now()) { if id.is_expired(now()) {
None None
} else { } else {
let path = basedir.join(id.as_string()).join(name); let path = basedir.join(id.as_string()).join(name);
NamedFile::open(path).ok() NamedFile::open(path).await.ok()
} }
} }
fn main() { #[launch]
fn rockert() -> _ {
dotenv().ok(); dotenv().ok();
let mut env: HashMap<_, _> = env::vars().collect(); let mut env: HashMap<_, _> = env::vars().collect();
@ -209,12 +193,11 @@ fn main() {
expire_job(basedir.clone(), expire_queue.clone()); expire_job(basedir.clone(), expire_queue.clone());
rocket::ignite() rocket::build()
.manage(tokens) .manage(tokens)
.manage(basedir.clone()) .manage(basedir.clone())
.manage(expire_queue) .manage(expire_queue)
.mount("/", routes![home, upload, post_upload, download]) .mount("/", routes![home, put_upload, post_upload, download])
.launch();
} }
fn expire_job(expire_basedir: PathBuf, expire_queue: ExpireQueue) -> JoinHandle<()> { fn expire_job(expire_basedir: PathBuf, expire_queue: ExpireQueue) -> JoinHandle<()> {

View file

@ -37,12 +37,14 @@ pub enum UploadTokenError {
Invalid, Invalid,
} }
impl<'a, 'r> FromRequest<'a, 'r> for UploadToken { #[async_trait::async_trait]
impl<'r> FromRequest<'r> for UploadToken {
type Error = UploadTokenError; type Error = UploadTokenError;
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
let accepted_tokens = request let accepted_tokens = request
.guard::<State<ValidTokens>>() .guard::<&State<ValidTokens>>()
.await
.expect("No tokens configured"); .expect("No tokens configured");
let keys: Vec<_> = request.headers().get("x-upload-token").collect(); let keys: Vec<_> = request.headers().get("x-upload-token").collect();

View file

@ -2,8 +2,8 @@ use std::fs::{self, File};
use std::io::{Cursor, Read, Write}; use std::io::{Cursor, Read, Write};
use std::path::Path; use std::path::Path;
use rocket::data::{self, FromDataSimple}; use rocket::data::{self, FromData, Outcome, ToByteUnit};
use rocket::{Data, Outcome, Request}; use rocket::{Data, Request};
use multipart::server::Multipart; use multipart::server::Multipart;
@ -41,10 +41,14 @@ impl Drop for FilePart {
const TMP_PATH: &str = "/tmp/rust_upload/"; const TMP_PATH: &str = "/tmp/rust_upload/";
impl<'t> FromDataSimple for MultipartDatas { #[async_trait::async_trait]
impl<'r> FromData<'r> for MultipartDatas {
type Error = String; type Error = String;
fn from_data(request: &Request, data: Data) -> data::Outcome<Self, String> { async fn from_data(
request: &'r Request<'_>,
data: Data<'r>,
) -> data::Outcome<'r, Self, String> {
let ct = request let ct = request
.headers() .headers()
.get_one("Content-Type") .get_one("Content-Type")
@ -53,7 +57,10 @@ impl<'t> FromDataSimple for MultipartDatas {
let boundary = &ct[(idx + "boundary=".len())..]; let boundary = &ct[(idx + "boundary=".len())..];
let mut d = Vec::new(); let mut d = Vec::new();
data.stream_to(&mut d).expect("Unable to read"); data.open(2.gibibytes())
.stream_to(&mut d)
.await
.expect("Unable to read");
let mut mp = Multipart::with_body(Cursor::new(d), boundary); let mut mp = Multipart::with_body(Cursor::new(d), boundary);
let mut texts = Vec::new(); let mut texts = Vec::new();