update dependencies, urlencode filename

This commit is contained in:
neri 2021-03-09 19:59:10 +01:00
parent f100450796
commit 9e38960f00
4 changed files with 1096 additions and 713 deletions

1736
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -7,19 +7,19 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
actix-web = { version = "2.0.0", default-features = false, features = [] } actix-web = "3.3.2"
sqlx = { version = "0.3.5", default-features = false, features = [ "runtime-async-std", "postgres", "chrono" ] } sqlx = { version = "0.5.1", default-features = false, features = [ "runtime-async-std-rustls", "postgres", "chrono" ] }
actix-rt = "1.1.1" env_logger = "0.8.3"
env_logger = "0.7.1" log = "0.4.14"
log = "0.4.8" actix-files = "0.5.0"
actix-files = "0.2.2" async-std = "1.9.0"
async-std = "1.6.2" actix-multipart = "0.3.0"
actix-multipart = "0.2.0" futures = "0.3.13"
futures = "0.3.5" rand = "0.8.3"
rand = "0.7.3" chrono = "0.4.19"
chrono = "0.4.13" openssl-sys = "0.9.60"
openssl-sys = "*"
htmlescape = "0.3.1" htmlescape = "0.3.1"
urlencoding = "1.1.1"
[features] [features]
vendored = ["openssl-sys/vendored"] vendored = ["openssl-sys/vendored"]

View File

@ -1,18 +1,18 @@
use async_std::{fs, path::PathBuf, sync::Receiver, task}; use async_std::{channel::Receiver, fs, path::PathBuf, task};
use chrono::{prelude::*, Duration}; use chrono::{prelude::*, Duration};
use futures::future::FutureExt; use futures::{TryStreamExt, future::FutureExt};
use sqlx::{postgres::PgPool, Cursor, Row}; use sqlx::{postgres::PgPool, Row};
pub(crate) async fn delete_old_files(receiver: Receiver<()>, db: PgPool, files_dir: PathBuf) { pub(crate) async fn delete_old_files(receiver: Receiver<()>, db: PgPool, files_dir: PathBuf) {
loop { loop {
wait_for_file_expiry(&receiver, &db).await; wait_for_file_expiry(&receiver, &db).await;
let now = Local::now().naive_local(); let now = Local::now().naive_local();
let mut cursor = sqlx::query("SELECT file_id FROM files WHERE files.valid_till < $1") let mut rows = sqlx::query("SELECT file_id FROM files WHERE files.valid_till < $1")
.bind(now) .bind(now)
.fetch(&db); .fetch(&db);
while let Some(row) = cursor.next().await.expect("could not load expired files") { while let Some(row) = rows.try_next().await.expect("could not load expired files") {
let file_id: String = row.get("file_id"); let file_id: String = row.try_get("file_id").expect("we selected this column");
let mut path = files_dir.clone(); let mut path = files_dir.clone();
path.push(&file_id); path.push(&file_id);
if path.exists().await { if path.exists().await {
@ -30,9 +30,9 @@ pub(crate) async fn delete_old_files(receiver: Receiver<()>, db: PgPool, files_d
} }
async fn wait_for_file_expiry(receiver: &Receiver<()>, db: &PgPool) { async fn wait_for_file_expiry(receiver: &Receiver<()>, db: &PgPool) {
let mut cursor = sqlx::query("SELECT MIN(valid_till) as min from files").fetch(db); let mut rows = sqlx::query("SELECT MIN(valid_till) as min from files").fetch(db);
let row = cursor let row = rows
.next() .try_next()
.await .await
.expect("could not fetch expiring files from database") .expect("could not fetch expiring files from database")
.expect("postgres min did not return any row"); .expect("postgres min did not return any row");

View File

@ -12,15 +12,16 @@ use actix_web::{
App, Error, FromRequest, HttpRequest, HttpResponse, HttpServer, App, Error, FromRequest, HttpRequest, HttpResponse, HttpServer,
}; };
use async_std::{ use async_std::{
channel::{self, Sender},
fs, fs,
path::PathBuf, path::PathBuf,
sync::{channel, Sender},
task, task,
}; };
use file_kind::FileKind; use file_kind::FileKind;
use futures::TryStreamExt;
use sqlx::{ use sqlx::{
postgres::{PgPool, PgRow}, postgres::{PgPool, PgPoolOptions, PgRow},
Cursor, Row, Row,
}; };
use std::env; use std::env;
@ -92,10 +93,11 @@ async fn upload(
kind kind
); );
expiry_watch_sender.send(()).await; expiry_watch_sender.send(()).await.unwrap();
let redirect = if kind == FileKind::BINARY && original_name.is_some() { let redirect = if kind == FileKind::BINARY && original_name.is_some() {
format!("/upload/{}/{}", file_id, original_name.as_ref().unwrap()) let encoded_name = urlencoding::encode(original_name.as_ref().unwrap());
format!("/upload/{}/{}", file_id, encoded_name)
} else { } else {
format!("/upload/{}", file_id) format!("/upload/{}", file_id)
}; };
@ -113,7 +115,8 @@ fn get_host_url(req: &web::HttpRequest) -> String {
fn get_file_url(req: &web::HttpRequest, id: &str, name: Option<&str>) -> String { fn get_file_url(req: &web::HttpRequest, id: &str, name: Option<&str>) -> String {
if let Some(name) = name { if let Some(name) = name {
format!("{}/file/{}/{}", get_host_url(req), id, name) let encoded_name = urlencoding::encode(name);
format!("{}/file/{}/{}", get_host_url(req), id, encoded_name)
} else { } else {
format!("{}/file/{}", get_host_url(req), id) format!("{}/file/{}", get_host_url(req), id)
} }
@ -135,11 +138,11 @@ async fn download(
config: web::Data<Config>, config: web::Data<Config>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
let id = req.match_info().query("id"); let id = req.match_info().query("id");
let mut cursor = sqlx::query("SELECT file_id, file_name, kind from files WHERE file_id = $1") let mut rows = sqlx::query("SELECT file_id, file_name, kind from files WHERE file_id = $1")
.bind(id) .bind(id)
.fetch(db.as_ref()); .fetch(db.as_ref());
let row: PgRow = cursor let row: PgRow = rows
.next() .try_next()
.await .await
.map_err(|_| error::ErrorInternalServerError("could not run select statement"))? .map_err(|_| error::ErrorInternalServerError("could not run select statement"))?
.ok_or_else(|| error::ErrorNotFound("file does not exist or has expired"))?; .ok_or_else(|| error::ErrorNotFound("file does not exist or has expired"))?;
@ -204,10 +207,10 @@ async fn setup_db() -> PgPool {
let conn_url = &get_db_url(); let conn_url = &get_db_url();
log::info!("Using Connection string {}", conn_url); log::info!("Using Connection string {}", conn_url);
let pool = PgPool::builder() let pool = PgPoolOptions::new()
.max_size(5) .max_connections(5)
.connect_timeout(std::time::Duration::from_secs(5)) .connect_timeout(std::time::Duration::from_secs(5))
.build(conn_url) .connect(conn_url)
.await .await
.expect("could not create db pool"); .expect("could not create db pool");
@ -224,7 +227,7 @@ struct Config {
files_dir: PathBuf, files_dir: PathBuf,
} }
#[actix_rt::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
if env::var("RUST_LOG").is_err() { if env::var("RUST_LOG").is_err() {
env::set_var("RUST_LOG", "info"); env::set_var("RUST_LOG", "info");
@ -238,7 +241,7 @@ async fn main() -> std::io::Result<()> {
fs::create_dir_all(&config.files_dir) fs::create_dir_all(&config.files_dir)
.await .await
.expect("could not create directory for storing files"); .expect("could not create directory for storing files");
let (sender, receiver) = channel(8); let (sender, receiver) = channel::bounded(8);
log::info!("omnomnom"); log::info!("omnomnom");