Blossom: Implement HEAD/PUT /upload

This commit is contained in:
Mike Dilger 2024-11-18 08:37:15 +13:00
parent da91fcb271
commit 46605fae2d
No known key found for this signature in database
GPG Key ID: 47581A78D4329BA4

View File

@ -3,15 +3,16 @@ use crate::filestore::HashOutput;
use crate::globals::GLOBALS;
use http::header::{
ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_METHODS, ACCESS_CONTROL_ALLOW_ORIGIN,
ACCESS_CONTROL_REQUEST_HEADERS, ACCESS_CONTROL_REQUEST_METHOD, ALLOW, CONTENT_LENGTH, ORIGIN,
WWW_AUTHENTICATE,
ACCESS_CONTROL_REQUEST_HEADERS, ACCESS_CONTROL_REQUEST_METHOD, ALLOW, CONTENT_LENGTH,
CONTENT_TYPE, ORIGIN, WWW_AUTHENTICATE,
};
use http::{Method, StatusCode};
//ACCEPT, AUTHORIZATION, CONTENT_TYPE, DATE, ETAG, ORIGIN
//ACCEPT, AUTHORIZATION, DATE, ETAG, ORIGIN
use http_body_util::combinators::BoxBody;
use http_body_util::{BodyExt, Empty};
use http_body_util::{BodyExt, Empty, Full};
use hyper::body::{Bytes, Incoming};
use hyper::{Request, Response};
use serde::{Deserialize, Serialize};
mod auth;
use auth::{verify_auth, AuthVerb};
@ -162,9 +163,77 @@ pub async fn handle_upload(
return options_response(request, "OPTIONS, HEAD, PUT");
}
let _auth_data = verify_auth(&request)?;
let auth_data = verify_auth(&request)?;
if auth_data.verb != Some(AuthVerb::Upload) {
return Err(
ChorusError::BlossomAuthFailure("Upload was not authorized".to_string()).into(),
);
}
unimplemented!()
match request.method() {
&Method::HEAD => Ok(Response::builder()
.header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
.header(CONTENT_LENGTH, "0")
.status(StatusCode::NOT_IMPLEMENTED)
.body(Empty::new().map_err(|e| e.into()).boxed())?),
&Method::PUT => {
let expected_hash = auth_data.hash.map(|bytes| HashOutput::from_bytes(bytes));
if expected_hash.is_none() {
return Err(ChorusError::BlossomAuthFailure(
"Put requires an expected hash value x tag in the authorization event"
.to_string(),
)
.into());
}
let uri = request.uri().to_owned();
let (size, hash) = GLOBALS
.filestore
.get()
.unwrap()
.store(
request.into_body().map_err(|e| e.into()).boxed(),
expected_hash,
)
.await?;
let uri = {
let mut parts = GLOBALS.config.read().uri_parts(uri, true)?;
parts.path_and_query = Some(http::uri::PathAndQuery::from_maybe_shared(format!(
"/{}",
hash
))?);
http::Uri::from_parts(parts)?
};
let blob_descriptor = BlobDescriptor {
url: format!("{}", uri),
sha256: format!("{}", hash),
size,
uploaded: pocket_types::Time::now().as_u64(),
};
let descriptor_json_string = serde_json::to_string(&blob_descriptor)?;
let body_bytes = descriptor_json_string.into_bytes();
let len = body_bytes.len();
let body = Full::new(Bytes::from(body_bytes))
.map_err(|e| e.into())
.boxed();
Ok(Response::builder()
.header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
.header(CONTENT_LENGTH, format!("{}", len))
.header(CONTENT_TYPE, "application/json")
.status(StatusCode::OK)
.body(body)?)
}
_ => Ok(Response::builder()
.header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
.header(CONTENT_LENGTH, "0")
.status(StatusCode::METHOD_NOT_ALLOWED)
.body(Empty::new().map_err(|e| e.into()).boxed())?),
}
}
pub async fn handle_list(
@ -190,3 +259,12 @@ pub async fn handle_mirror(
unimplemented!()
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BlobDescriptor {
pub url: String,
pub sha256: String,
pub size: u64,
// type: String
pub uploaded: u64,
}