Compare commits
2 Commits
09df915296
...
5b7faf556f
Author | SHA1 | Date |
---|---|---|
Savanni D'Gerinel | 5b7faf556f | |
Savanni D'Gerinel | f2bbb4e720 |
|
@ -7,3 +7,4 @@ result
|
||||||
file-service/*.sqlite
|
file-service/*.sqlite
|
||||||
file-service/*.sqlite-shm
|
file-service/*.sqlite-shm
|
||||||
file-service/*.sqlite-wal
|
file-service/*.sqlite-wal
|
||||||
|
file-service/var
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
use build_html::Html;
|
use build_html::Html;
|
||||||
|
use bytes::Buf;
|
||||||
|
use cookie::time::error::Format;
|
||||||
|
use file_service::WriteFileError;
|
||||||
|
use futures_util::StreamExt;
|
||||||
use http::{Error, StatusCode};
|
use http::{Error, StatusCode};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use warp::http::Response;
|
use std::io::Read;
|
||||||
|
use warp::{filters::multipart::FormData, http::Response, multipart::Part};
|
||||||
|
|
||||||
use crate::{pages, App, AuthToken, FileId, FileInfo, ReadFileError, SessionToken};
|
use crate::{pages, App, AuthToken, FileId, FileInfo, ReadFileError, SessionToken};
|
||||||
|
|
||||||
|
@ -98,13 +103,30 @@ pub async fn handle_auth(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_upload(
|
pub async fn handle_upload(
|
||||||
_app: App,
|
app: App,
|
||||||
_token: SessionToken,
|
token: SessionToken,
|
||||||
|
form: FormData,
|
||||||
) -> Result<http::Response<String>, Error> {
|
) -> Result<http::Response<String>, Error> {
|
||||||
println!("handle_upload");
|
match app.validate_session(token).await {
|
||||||
Response::builder()
|
Ok(Some(_)) => match process_file_upload(app, form).await {
|
||||||
.status(StatusCode::NOT_IMPLEMENTED)
|
Ok(_) => Response::builder()
|
||||||
.body("".to_owned())
|
.header("location", "/")
|
||||||
|
.status(StatusCode::SEE_OTHER)
|
||||||
|
.body("".to_owned()),
|
||||||
|
Err(UploadError::FilenameMissing) => Response::builder()
|
||||||
|
.status(StatusCode::BAD_REQUEST)
|
||||||
|
.body("filename is required for all files".to_owned()),
|
||||||
|
Err(UploadError::WriteFileError(err)) => Response::builder()
|
||||||
|
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
.body(format!("could not write to the file system: {:?}", err)),
|
||||||
|
Err(UploadError::WarpError(err)) => Response::builder()
|
||||||
|
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
.body(format!("error with the app framework: {:?}", err)),
|
||||||
|
},
|
||||||
|
_ => Response::builder()
|
||||||
|
.status(StatusCode::UNAUTHORIZED)
|
||||||
|
.body("".to_owned()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serve_file<F>(
|
fn serve_file<F>(
|
||||||
|
@ -132,3 +154,102 @@ where
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn collect_multipart(
|
||||||
|
mut stream: warp::filters::multipart::FormData,
|
||||||
|
) -> Result<Vec<(Option<String>, Option<String>, Vec<u8>)>, warp::Error> {
|
||||||
|
let mut content: Vec<(Option<String>, Option<String>, Vec<u8>)> = Vec::new();
|
||||||
|
|
||||||
|
while let Some(part) = stream.next().await {
|
||||||
|
match part {
|
||||||
|
Ok(part) => content.push(collect_content(part).await.unwrap()),
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn collect_content(
|
||||||
|
mut part: Part,
|
||||||
|
) -> Result<(Option<String>, Option<String>, Vec<u8>), String> {
|
||||||
|
let mut content: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
|
while let Some(Ok(data)) = part.data().await {
|
||||||
|
let mut reader = data.reader();
|
||||||
|
reader.read_to_end(&mut content).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
part.content_type().map(|s| s.to_owned()),
|
||||||
|
part.filename().map(|s| s.to_owned()),
|
||||||
|
content,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
async fn handle_upload(
|
||||||
|
form: warp::filters::multipart::FormData,
|
||||||
|
app: App,
|
||||||
|
) -> warp::http::Result<warp::http::Response<String>> {
|
||||||
|
let files = collect_multipart(form).await;
|
||||||
|
match files {
|
||||||
|
Ok(files) => {
|
||||||
|
for (_, filename, content) in files {
|
||||||
|
match filename {
|
||||||
|
Some(filename) => {
|
||||||
|
app.add_file(filename, content).unwrap();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return warp::http::Response::builder()
|
||||||
|
.status(StatusCode::BAD_REQUEST)
|
||||||
|
.body("".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_err) => {
|
||||||
|
return warp::http::Response::builder()
|
||||||
|
.status(StatusCode::BAD_REQUEST)
|
||||||
|
.body("".to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// println!("file length: {:?}", files.map(|f| f.len()));
|
||||||
|
warp::http::Response::builder()
|
||||||
|
.header("location", "/")
|
||||||
|
.status(StatusCode::SEE_OTHER)
|
||||||
|
.body("".to_owned())
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum UploadError {
|
||||||
|
FilenameMissing,
|
||||||
|
WriteFileError(WriteFileError),
|
||||||
|
WarpError(warp::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<WriteFileError> for UploadError {
|
||||||
|
fn from(err: WriteFileError) -> Self {
|
||||||
|
Self::WriteFileError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<warp::Error> for UploadError {
|
||||||
|
fn from(err: warp::Error) -> Self {
|
||||||
|
Self::WarpError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn process_file_upload(app: App, form: FormData) -> Result<(), UploadError> {
|
||||||
|
let files = collect_multipart(form).await?;
|
||||||
|
for (_, filename, content) in files {
|
||||||
|
match filename {
|
||||||
|
Some(filename) => {
|
||||||
|
app.add_file(filename, content).await?;
|
||||||
|
}
|
||||||
|
None => return Err(UploadError::FilenameMissing),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -42,75 +42,12 @@ async fn authenticate_user(app: App, auth_token: String) -> Result<Username, war
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
async fn collect_content(
|
|
||||||
mut part: Part,
|
|
||||||
) -> Result<(Option<String>, Option<String>, Vec<u8>), String> {
|
|
||||||
let mut content: Vec<u8> = Vec::new();
|
|
||||||
|
|
||||||
while let Some(Ok(data)) = part.data().await {
|
|
||||||
let mut reader = data.reader();
|
|
||||||
reader.read_to_end(&mut content).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((
|
|
||||||
part.content_type().map(|s| s.to_owned()),
|
|
||||||
part.filename().map(|s| s.to_owned()),
|
|
||||||
content,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
async fn collect_multipart(
|
|
||||||
mut stream: warp::filters::multipart::FormData,
|
|
||||||
) -> Result<Vec<(Option<String>, Option<String>, Vec<u8>)>, warp::Error> {
|
|
||||||
let mut content: Vec<(Option<String>, Option<String>, Vec<u8>)> = Vec::new();
|
|
||||||
|
|
||||||
while let Some(part) = stream.next().await {
|
|
||||||
match part {
|
|
||||||
Ok(part) => content.push(collect_content(part).await.unwrap()),
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(content)
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
async fn handle_upload(
|
|
||||||
form: warp::filters::multipart::FormData,
|
|
||||||
app: App,
|
|
||||||
) -> warp::http::Result<warp::http::Response<String>> {
|
|
||||||
let files = collect_multipart(form).await;
|
|
||||||
match files {
|
|
||||||
Ok(files) => {
|
|
||||||
for (_, filename, content) in files {
|
|
||||||
match filename {
|
|
||||||
Some(filename) => {
|
|
||||||
app.add_file(filename, content).unwrap();
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
return warp::http::Response::builder()
|
|
||||||
.status(StatusCode::BAD_REQUEST)
|
|
||||||
.body("".to_owned())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_err) => {
|
|
||||||
return warp::http::Response::builder()
|
|
||||||
.status(StatusCode::BAD_REQUEST)
|
|
||||||
.body("".to_owned())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// println!("file length: {:?}", files.map(|f| f.len()));
|
|
||||||
warp::http::Response::builder()
|
|
||||||
.header("location", "/")
|
|
||||||
.status(StatusCode::SEE_OTHER)
|
|
||||||
.body("".to_owned())
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -159,26 +96,25 @@ fn with_app(app: App) -> impl Filter<Extract = (App,), Error = Infallible> + Clo
|
||||||
warp::any().map(move || app.clone())
|
warp::any().map(move || app.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_cookies(cookie_str: &str) -> Result<HashMap<String, String>, cookie::ParseError> {
|
||||||
|
Cookie::split_parse(cookie_str)
|
||||||
|
.map(|c| c.map(|c| (c.name().to_owned(), c.value().to_owned())))
|
||||||
|
.collect::<Result<HashMap<String, String>, cookie::ParseError>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_session_token(cookies: HashMap<String, String>) -> Option<SessionToken> {
|
||||||
|
cookies
|
||||||
|
.get("session")
|
||||||
|
.cloned()
|
||||||
|
.and_then(|session| Some(SessionToken::from(session)))
|
||||||
|
}
|
||||||
|
|
||||||
fn maybe_with_session() -> impl Filter<Extract = (Option<SessionToken>,), Error = Rejection> + Copy
|
fn maybe_with_session() -> impl Filter<Extract = (Option<SessionToken>,), Error = Rejection> + Copy
|
||||||
{
|
{
|
||||||
warp::any()
|
warp::any()
|
||||||
.and(warp::header::optional::<String>("cookie"))
|
.and(warp::header::optional::<String>("cookie"))
|
||||||
.map(|cookies| match cookies {
|
.map(|cookie_str: Option<String>| match cookie_str {
|
||||||
Some(cookies) => {
|
Some(cookie_str) => parse_cookies(&cookie_str).ok().and_then(get_session_token),
|
||||||
let c = Cookie::split_parse(cookies)
|
|
||||||
.collect::<Result<Vec<Cookie>, cookie::ParseError>>();
|
|
||||||
match c {
|
|
||||||
Ok(cookies) => {
|
|
||||||
for c in cookies {
|
|
||||||
if c.name() == "session" {
|
|
||||||
return Some(SessionToken::from(c.value()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Err(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => None,
|
None => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -186,7 +122,12 @@ fn maybe_with_session() -> impl Filter<Extract = (Option<SessionToken>,), Error
|
||||||
fn with_session() -> impl Filter<Extract = (SessionToken,), Error = Rejection> + Copy {
|
fn with_session() -> impl Filter<Extract = (SessionToken,), Error = Rejection> + Copy {
|
||||||
warp::any()
|
warp::any()
|
||||||
.and(warp::header::<String>("cookie"))
|
.and(warp::header::<String>("cookie"))
|
||||||
.map(|token: String| SessionToken::from(token))
|
.and_then(|cookie_str: String| async move {
|
||||||
|
match parse_cookies(&cookie_str).ok().and_then(get_session_token) {
|
||||||
|
Some(session_token) => Ok(session_token),
|
||||||
|
None => Err(warp::reject()),
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
@ -200,13 +141,6 @@ pub async fn main() {
|
||||||
|
|
||||||
let app = App::new(authdb, store);
|
let app = App::new(authdb, store);
|
||||||
|
|
||||||
/*
|
|
||||||
let with_app = {
|
|
||||||
let app = app.clone();
|
|
||||||
warp::any().map(move || app.clone())
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
let log = warp::log("file_service");
|
let log = warp::log("file_service");
|
||||||
let root = warp::path!()
|
let root = warp::path!()
|
||||||
.and(warp::get())
|
.and(warp::get())
|
||||||
|
@ -220,10 +154,11 @@ pub async fn main() {
|
||||||
.and(warp::filters::body::form())
|
.and(warp::filters::body::form())
|
||||||
.then(handle_auth);
|
.then(handle_auth);
|
||||||
|
|
||||||
let upload_handler = warp::path!("upload")
|
let upload_via_form = warp::path!("upload")
|
||||||
.and(warp::post())
|
.and(warp::post())
|
||||||
.and(with_app(app.clone()))
|
.and(with_app(app.clone()))
|
||||||
.and(with_session())
|
.and(with_session())
|
||||||
|
.and(warp::multipart::form())
|
||||||
.then(handle_upload);
|
.then(handle_upload);
|
||||||
|
|
||||||
let thumbnail = warp::path!(String / "tn")
|
let thumbnail = warp::path!(String / "tn")
|
||||||
|
@ -239,13 +174,11 @@ pub async fn main() {
|
||||||
.then(move |id, old_etags, app: App| file(app, id, old_etags));
|
.then(move |id, old_etags, app: App| file(app, id, old_etags));
|
||||||
|
|
||||||
let server = warp::serve(
|
let server = warp::serve(
|
||||||
root.or(auth).with(log), /*
|
root.or(auth)
|
||||||
root.or(auth)
|
.or(upload_via_form)
|
||||||
.or(thumbnail)
|
.or(thumbnail)
|
||||||
.or(file)
|
.or(file)
|
||||||
.or(upload_handler)
|
.with(log),
|
||||||
.with(log),
|
|
||||||
*/
|
|
||||||
);
|
);
|
||||||
|
|
||||||
server
|
server
|
||||||
|
|
Loading…
Reference in New Issue