Support CORS
This commit is contained in:
parent
83bdcecd83
commit
9794f37842
@ -14,7 +14,7 @@ crate-type = ["cdylib"]
|
|||||||
async-trait = "0.1.74"
|
async-trait = "0.1.74"
|
||||||
base64 = "0.21.5"
|
base64 = "0.21.5"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
worker = "0.0.15"
|
worker = "0.0.18"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
92
src/dav.rs
92
src/dav.rs
@ -10,9 +10,9 @@ pub struct Dav {
|
|||||||
fs: R2,
|
fs: R2,
|
||||||
}
|
}
|
||||||
|
|
||||||
type DavResponse = (u16, HashMap<String, String>, String);
|
pub type DavResponse = (u16, HashMap<String, String>, String);
|
||||||
type DavErrResponse = (u16, Option<HashMap<String, String>>, Option<String>);
|
pub type DavErrResponse = (u16, Option<HashMap<String, String>>, Option<String>);
|
||||||
type DavStreamResponse = (u16, HashMap<String, String>, ByteStream);
|
pub type DavStreamResponse = (u16, HashMap<String, String>, ByteStream);
|
||||||
|
|
||||||
pub enum DavResponseType {
|
pub enum DavResponseType {
|
||||||
DavResponse(Result<DavResponse, DavErrResponse>),
|
DavResponse(Result<DavResponse, DavErrResponse>),
|
||||||
@ -32,8 +32,16 @@ impl From<Result<DavStreamResponse, DavErrResponse>> for DavResponseType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static DAV_CLASS: &str = "1";
|
static DAV_CLASS: &str = "1";
|
||||||
static SUPPORT_METHODS: [&str; 8] = [
|
static SUPPORT_METHODS: [&str; 9] = [
|
||||||
"OPTIONS", "PROPFIND", "MKCOL", "GET", "HEAD", "PUT", "COPY", "MOVE",
|
"OPTIONS",
|
||||||
|
"PROPFIND",
|
||||||
|
"PROPPATCH",
|
||||||
|
"MKCOL",
|
||||||
|
"GET",
|
||||||
|
"HEAD",
|
||||||
|
"PUT",
|
||||||
|
"COPY",
|
||||||
|
"MOVE",
|
||||||
];
|
];
|
||||||
|
|
||||||
impl Dav {
|
impl Dav {
|
||||||
@ -61,9 +69,9 @@ impl Dav {
|
|||||||
depth: Depth,
|
depth: Depth,
|
||||||
req_body: String,
|
req_body: String,
|
||||||
) -> Result<DavResponse, DavErrResponse> {
|
) -> Result<DavResponse, DavErrResponse> {
|
||||||
if req_body.len() > 0 {
|
// if req_body.len() > 0 {
|
||||||
return Err((415, None, None));
|
// return Err((415, None, None));
|
||||||
}
|
// }
|
||||||
|
|
||||||
let mut headers = HashMap::new();
|
let mut headers = HashMap::new();
|
||||||
headers.insert(
|
headers.insert(
|
||||||
@ -78,7 +86,7 @@ impl Dav {
|
|||||||
Some(vec![("xmlns:D".to_string(), "DAV:".to_string())]),
|
Some(vec![("xmlns:D".to_string(), "DAV:".to_string())]),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
match self.fs.list(path).await {
|
match self.fs.list(path.clone()).await {
|
||||||
Ok(items) => {
|
Ok(items) => {
|
||||||
for (href, properties) in items {
|
for (href, properties) in items {
|
||||||
let mut response =
|
let mut response =
|
||||||
@ -124,7 +132,7 @@ impl Dav {
|
|||||||
|
|
||||||
Ok((207, headers, multistatus.build()))
|
Ok((207, headers, multistatus.build()))
|
||||||
}
|
}
|
||||||
Err(_) => return Err((404, None, None)),
|
Err(message) => return Err((404, None, Some(message))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Depth::Zero => {
|
Depth::Zero => {
|
||||||
@ -133,12 +141,17 @@ impl Dav {
|
|||||||
Some(vec![("xmlns:D".to_string(), "DAV:".to_string())]),
|
Some(vec![("xmlns:D".to_string(), "DAV:".to_string())]),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
match self.fs.get(path).await {
|
match self.fs.get(path.clone()).await {
|
||||||
Ok((href, properties)) => {
|
Ok((href, properties)) => {
|
||||||
let mut response = XMLBuilder::new("D:response".to_string(), None, None);
|
let response = multistatus.elem("D:response".to_string(), None, None);
|
||||||
response.elem("D:href".to_string(), None, Some(href));
|
response.elem("D:href".to_string(), None, Some(href));
|
||||||
let mut propstat = XMLBuilder::new("D:propstat".to_string(), None, None);
|
let propstat = response.elem("D:propstat".to_string(), None, None);
|
||||||
let mut prop = XMLBuilder::new("D:prop".to_string(), None, None);
|
propstat.elem(
|
||||||
|
"D:status".to_string(),
|
||||||
|
None,
|
||||||
|
Some("HTTP/1.1 200 OK".to_string()),
|
||||||
|
);
|
||||||
|
let prop = propstat.elem("D:prop".to_string(), None, None);
|
||||||
prop.elem("D:creationdate".to_string(), None, properties.creation_date);
|
prop.elem("D:creationdate".to_string(), None, properties.creation_date);
|
||||||
prop.elem("D:displayname".to_string(), None, properties.display_name);
|
prop.elem("D:displayname".to_string(), None, properties.display_name);
|
||||||
prop.elem(
|
prop.elem(
|
||||||
@ -164,28 +177,63 @@ impl Dav {
|
|||||||
None,
|
None,
|
||||||
properties.get_last_modified,
|
properties.get_last_modified,
|
||||||
);
|
);
|
||||||
propstat.add(prop);
|
|
||||||
|
Ok((207, (headers), (multistatus.build())))
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
if !path.ends_with("/") {
|
||||||
|
return Err((404, None, None));
|
||||||
|
}
|
||||||
|
let response = multistatus.elem("D:response".to_string(), None, None);
|
||||||
|
response.elem("D:href".to_string(), None, Some(path));
|
||||||
|
let propstat = response.elem("D:propstat".to_string(), None, None);
|
||||||
propstat.elem(
|
propstat.elem(
|
||||||
"D:status".to_string(),
|
"D:status".to_string(),
|
||||||
None,
|
None,
|
||||||
Some("HTTP/1.1 200 OK".to_string()),
|
Some("HTTP/1.1 200 OK".to_string()),
|
||||||
);
|
);
|
||||||
response.add(propstat);
|
propstat.elem("D:prop".to_string(), None, None);
|
||||||
multistatus.add(response);
|
|
||||||
|
|
||||||
Ok((207, (headers), (multistatus.build())))
|
Ok((207, (headers), (multistatus.build())))
|
||||||
}
|
}
|
||||||
Err(_) => return Err((404, None, None)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Depth::Infinity => return Err((400, None, None)),
|
Depth::Infinity => return Err((400, None, None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn handle_mkcol(
|
pub async fn handle_proppatch(
|
||||||
&self,
|
&self,
|
||||||
path: String,
|
path: String,
|
||||||
req_body: String,
|
req_body: String,
|
||||||
|
) -> Result<DavResponse, DavErrResponse> {
|
||||||
|
let mut headers = HashMap::new();
|
||||||
|
headers.insert(
|
||||||
|
"Content-Type".to_string(),
|
||||||
|
"application/xml; charset=utf-8".to_string(),
|
||||||
|
);
|
||||||
|
let mut multistatus = XMLBuilder::new(
|
||||||
|
"D:multistatus".to_string(),
|
||||||
|
Some(vec![("xmlns:D".to_string(), "DAV:".to_string())]),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
let response = multistatus.elem("D:response".to_string(), None, None);
|
||||||
|
response.elem("D:href".to_string(), None, Some(path));
|
||||||
|
let propstat = response.elem("D:propstat".to_string(), None, None);
|
||||||
|
let prop = propstat.elem("D:prop".to_string(), None, None);
|
||||||
|
// TODO
|
||||||
|
propstat.elem(
|
||||||
|
"D:status".to_string(),
|
||||||
|
None,
|
||||||
|
Some("HTTP/1.1 200 OK".to_string()),
|
||||||
|
);
|
||||||
|
Ok((207, HashMap::new(), multistatus.build()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_mkcol(
|
||||||
|
&self,
|
||||||
|
_: String,
|
||||||
|
req_body: String,
|
||||||
) -> Result<DavResponse, DavErrResponse> {
|
) -> Result<DavResponse, DavErrResponse> {
|
||||||
if req_body.len() > 0 {
|
if req_body.len() > 0 {
|
||||||
return Err((415, None, None));
|
return Err((415, None, None));
|
||||||
@ -233,7 +281,7 @@ impl Dav {
|
|||||||
_ => Ok((200, (headers), stream)),
|
_ => Ok((200, (headers), stream)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => return Err((404, None, None)),
|
Err(message) => return Err((404, None, Some(message))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +309,9 @@ impl Dav {
|
|||||||
.join(", ");
|
.join(", ");
|
||||||
return Ok((200, (headers), (html)));
|
return Ok((200, (headers), (html)));
|
||||||
}
|
}
|
||||||
Err(_) => return Err((404, None, None)),
|
Err(message) => {
|
||||||
|
return Err((404, None, Some(message)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
392
src/lib.rs
392
src/lib.rs
@ -1,6 +1,6 @@
|
|||||||
use crate::values::Depth;
|
use crate::values::Depth;
|
||||||
use base64;
|
use base64;
|
||||||
use dav::DavResponseType;
|
use dav::{DavErrResponse, DavResponse, DavResponseType, DavStreamResponse};
|
||||||
use r2::R2;
|
use r2::R2;
|
||||||
use values::Overwrite;
|
use values::Overwrite;
|
||||||
use worker::*;
|
use worker::*;
|
||||||
@ -11,7 +11,7 @@ mod values;
|
|||||||
mod xml;
|
mod xml;
|
||||||
|
|
||||||
#[event(fetch)]
|
#[event(fetch)]
|
||||||
async fn main(req: Request, env: Env, _: Context) -> Result<Response> {
|
async fn main(mut req: Request, env: Env, _: Context) -> Result<Response> {
|
||||||
let username = env.var("USERNAME").unwrap().to_string();
|
let username = env.var("USERNAME").unwrap().to_string();
|
||||||
let password = env.var("PASSWORD").unwrap().to_string();
|
let password = env.var("PASSWORD").unwrap().to_string();
|
||||||
let protocol = env.var("PROTOCOL").unwrap().to_string();
|
let protocol = env.var("PROTOCOL").unwrap().to_string();
|
||||||
@ -29,7 +29,103 @@ async fn main(req: Request, env: Env, _: Context) -> Result<Response> {
|
|||||||
"r2" => R2::new(env.bucket(bucket_name.as_str()).unwrap()),
|
"r2" => R2::new(env.bucket(bucket_name.as_str()).unwrap()),
|
||||||
_ => panic!("PROTOCOL {} not supported", protocol),
|
_ => panic!("PROTOCOL {} not supported", protocol),
|
||||||
});
|
});
|
||||||
worker(req, dav).await
|
|
||||||
|
let mut response = match match req.inner().method().as_str() {
|
||||||
|
"PROPFIND" => {
|
||||||
|
let request_body = req.text().await?;
|
||||||
|
console_debug!("request_body {:?}", request_body);
|
||||||
|
dav.handle_propfind(req.path(), parse_depth(&req), request_body)
|
||||||
|
.await
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
"PROPPATCH" => {
|
||||||
|
let request_body = req.text().await?;
|
||||||
|
console_debug!("request_body {:?}", request_body);
|
||||||
|
dav.handle_proppatch(req.path(), request_body).await.into()
|
||||||
|
}
|
||||||
|
"OPTIONS" => dav.handle_options().await.into(),
|
||||||
|
"MKCOL" => dav.handle_mkcol(req.path(), req.text().await?).await.into(),
|
||||||
|
"GET" => {
|
||||||
|
if req.path().ends_with("/") {
|
||||||
|
dav.handle_get_dir(req.path()).await.into()
|
||||||
|
} else {
|
||||||
|
dav.handle_get_obj(req.path(), parse_range(&req))
|
||||||
|
.await
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"HEAD" => {
|
||||||
|
if req.path().ends_with("/") {
|
||||||
|
dav.handle_head_dir(req.path()).await.into()
|
||||||
|
} else {
|
||||||
|
dav.handle_head_obj(req.path(), parse_range(&req))
|
||||||
|
.await
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"DELETE" => dav.handle_delete(req.path()).await.into(),
|
||||||
|
"PUT" => dav
|
||||||
|
.handle_put(
|
||||||
|
req.path(),
|
||||||
|
req.stream().unwrap(),
|
||||||
|
req.headers()
|
||||||
|
.get("content-length")
|
||||||
|
.unwrap()
|
||||||
|
.map_or(0, |v| v.parse::<u64>().unwrap()),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.into(),
|
||||||
|
"COPY" => dav
|
||||||
|
.handle_copy(
|
||||||
|
req.path(),
|
||||||
|
parse_destination(&req),
|
||||||
|
parse_depth(&req),
|
||||||
|
parse_overwrite(&req),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.into(),
|
||||||
|
"MOVE" => dav
|
||||||
|
.handle_move(
|
||||||
|
req.path(),
|
||||||
|
parse_destination(&req),
|
||||||
|
parse_depth(&req),
|
||||||
|
parse_overwrite(&req),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.into(),
|
||||||
|
_ => dav.handle_unsupport_method().await.into(),
|
||||||
|
} {
|
||||||
|
DavResponseType::DavResponse(r) => r.map_or_else(from_dav_err_response, from_dav_response),
|
||||||
|
DavResponseType::DavStreamResponse(r) => {
|
||||||
|
r.map_or_else(from_dav_err_response, from_dav_stream_response)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let cors = Cors::new()
|
||||||
|
.with_origins(
|
||||||
|
req.headers()
|
||||||
|
.get("origin")
|
||||||
|
.unwrap()
|
||||||
|
.map_or(vec![], |v| vec![v.to_string()]),
|
||||||
|
)
|
||||||
|
.with_methods(Method::all())
|
||||||
|
.with_allowed_headers([
|
||||||
|
"authorization",
|
||||||
|
"content-type",
|
||||||
|
"depth",
|
||||||
|
"overwrite",
|
||||||
|
"destination",
|
||||||
|
"range",
|
||||||
|
])
|
||||||
|
.with_exposed_headers([
|
||||||
|
"content-length",
|
||||||
|
"content-type",
|
||||||
|
"etag",
|
||||||
|
"last-modified",
|
||||||
|
"range",
|
||||||
|
]);
|
||||||
|
response = response.map(|response| response.with_cors(&cors).unwrap());
|
||||||
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
fn basic_authorization(
|
fn basic_authorization(
|
||||||
@ -47,208 +143,102 @@ fn basic_authorization(
|
|||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
match authorization_header {
|
if let Some(text) = authorization_header {
|
||||||
Some(text) => {
|
let a: Vec<&str> = text.split(" ").collect();
|
||||||
let a: Vec<&str> = text.split(" ").collect();
|
if a.len() != 2 || a[0] != "Basic" {
|
||||||
if a.len() != 2 || a[0] != "Basic" {
|
return basic_authorization_error_response();
|
||||||
return basic_authorization_error_response();
|
|
||||||
}
|
|
||||||
if let Ok(v) = base64::decode(a[1]) {
|
|
||||||
let v = match String::from_utf8(v) {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(_) => return basic_authorization_error_response(),
|
|
||||||
};
|
|
||||||
let v: Vec<&str> = v.split(":").collect();
|
|
||||||
if v.len() != 2 {
|
|
||||||
return basic_authorization_error_response();
|
|
||||||
}
|
|
||||||
if v[0] != username || v[1] != password {
|
|
||||||
return basic_authorization_error_response();
|
|
||||||
}
|
|
||||||
|
|
||||||
return None;
|
|
||||||
} else {
|
|
||||||
return basic_authorization_error_response();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None => {
|
if let Ok(v) = base64::decode(a[1]) {
|
||||||
|
let v = match String::from_utf8(v) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(_) => return basic_authorization_error_response(),
|
||||||
|
};
|
||||||
|
let v: Vec<&str> = v.split(":").collect();
|
||||||
|
if v.len() != 2 {
|
||||||
|
return basic_authorization_error_response();
|
||||||
|
}
|
||||||
|
if v[0] != username || v[1] != password {
|
||||||
|
return basic_authorization_error_response();
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
|
} else {
|
||||||
return basic_authorization_error_response();
|
return basic_authorization_error_response();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return basic_authorization_error_response();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn worker(mut req: Request, dav: dav::Dav) -> Result<Response> {
|
fn parse_depth(req: &Request) -> Depth {
|
||||||
let dav_response: DavResponseType = match req.inner().method().as_str() {
|
req.headers()
|
||||||
"PROPFIND" => {
|
.get("depth")
|
||||||
let depth: Depth = req
|
.unwrap()
|
||||||
.headers()
|
.map_or("infinity".to_string(), |v| v)
|
||||||
.get("depth")
|
.into()
|
||||||
.unwrap()
|
}
|
||||||
.map_or("infinity".to_string(), |v| v)
|
|
||||||
.into();
|
fn parse_range(req: &Request) -> values::Range {
|
||||||
let resource_path = req.path();
|
req.headers().get("range").unwrap().map_or(
|
||||||
dav.handle_propfind(resource_path, depth, req.text().await?)
|
values::Range {
|
||||||
.await
|
start: None,
|
||||||
.into()
|
end: None,
|
||||||
}
|
},
|
||||||
"OPTIONS" => dav.handle_options().await.into(),
|
|v| values::Range::from(v.to_string().split("bytes=").next().unwrap().to_string()),
|
||||||
"MKCOL" => {
|
)
|
||||||
let resource_path = req.path();
|
}
|
||||||
dav.handle_mkcol(resource_path, req.text().await?)
|
|
||||||
.await
|
fn parse_destination(req: &Request) -> String {
|
||||||
.into()
|
req.headers()
|
||||||
}
|
.get("destination")
|
||||||
"GET" => {
|
.unwrap()
|
||||||
let resource_path = req.path();
|
.map_or("".to_string(), |v| {
|
||||||
let range = req.headers().get("range").unwrap().map_or(
|
v.split("http://")
|
||||||
values::Range {
|
.nth(1)
|
||||||
start: None,
|
.unwrap()
|
||||||
end: None,
|
.split("/")
|
||||||
},
|
.skip(1)
|
||||||
|v| values::Range::from(v.to_string().split("bytes=").next().unwrap().to_string()),
|
.collect::<Vec<&str>>()
|
||||||
);
|
.join("/")
|
||||||
if resource_path.ends_with("/") {
|
})
|
||||||
dav.handle_get_dir(resource_path).await.into()
|
}
|
||||||
} else {
|
|
||||||
dav.handle_get_obj(resource_path, range).await.into()
|
fn parse_overwrite(req: &Request) -> Overwrite {
|
||||||
}
|
req.headers()
|
||||||
}
|
.get("overwrite")
|
||||||
"HEAD" => {
|
.unwrap()
|
||||||
let resource_path = req.path();
|
.map_or("T".to_string(), |v| v.to_string())
|
||||||
let range = req.headers().get("range").unwrap().map_or(
|
.into()
|
||||||
values::Range {
|
}
|
||||||
start: None,
|
|
||||||
end: None,
|
fn from_dav_err_response(response: DavErrResponse) -> Result<Response> {
|
||||||
},
|
let (status_code, headers, body) = response;
|
||||||
|v| values::Range::from(v.to_string().split("bytes=").next().unwrap().to_string()),
|
console_debug!("{} {:?} {:?}", status_code, headers, body);
|
||||||
);
|
Response::error(body.unwrap_or("".to_string()), status_code).map(|response| {
|
||||||
if resource_path.ends_with("/") {
|
match headers {
|
||||||
dav.handle_head_dir(resource_path).await.into()
|
Some(headers) => response.with_headers(Headers::from_iter(headers)),
|
||||||
} else {
|
None => response,
|
||||||
dav.handle_head_obj(resource_path, range).await.into()
|
}
|
||||||
}
|
.with_status(status_code)
|
||||||
}
|
})
|
||||||
"DELETE" => {
|
}
|
||||||
let resource_path = req.path();
|
|
||||||
dav.handle_delete(resource_path).await.into()
|
fn from_dav_response(response: DavResponse) -> Result<Response> {
|
||||||
}
|
let (status_code, headers, body) = response;
|
||||||
"PUT" => {
|
console_debug!("{} {:?} {:?}", status_code, headers, body);
|
||||||
let resource_path = req.path();
|
Response::from_bytes(body.into_bytes()).map(|response| {
|
||||||
let content_length = req
|
response
|
||||||
.headers()
|
.with_headers(Headers::from_iter(headers))
|
||||||
.get("content-length")
|
.with_status(status_code)
|
||||||
.unwrap()
|
})
|
||||||
.map_or(0, |v| v.parse::<u64>().unwrap());
|
}
|
||||||
println!("content-length: {}", content_length);
|
|
||||||
dav.handle_put(resource_path, req.stream().unwrap(), content_length)
|
fn from_dav_stream_response(response: DavStreamResponse) -> Result<Response> {
|
||||||
.await
|
let (status_code, headers, body) = response;
|
||||||
.into()
|
console_debug!("{} {:?} {:?}", status_code, headers, body);
|
||||||
}
|
Response::from_stream(body).map(|response| {
|
||||||
"COPY" => {
|
response
|
||||||
let resource_path = req.path();
|
.with_headers(Headers::from_iter(headers))
|
||||||
let destination =
|
.with_status(status_code)
|
||||||
req.headers()
|
})
|
||||||
.get("destination")
|
|
||||||
.unwrap()
|
|
||||||
.map_or("".to_string(), |v| {
|
|
||||||
v.split("http://")
|
|
||||||
.nth(1)
|
|
||||||
.unwrap()
|
|
||||||
.split("/")
|
|
||||||
.skip(1)
|
|
||||||
.collect::<Vec<&str>>()
|
|
||||||
.join("/")
|
|
||||||
});
|
|
||||||
let depth: Depth = req
|
|
||||||
.headers()
|
|
||||||
.get("depth")
|
|
||||||
.unwrap()
|
|
||||||
.map_or("infinity".to_string(), |v| v)
|
|
||||||
.into();
|
|
||||||
let overwrite: Overwrite = req
|
|
||||||
.headers()
|
|
||||||
.get("overwrite")
|
|
||||||
.unwrap()
|
|
||||||
.map_or("T".to_string(), |v| v.to_string())
|
|
||||||
.into();
|
|
||||||
dav.handle_copy(resource_path, destination, depth, overwrite)
|
|
||||||
.await
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
"MOVE" => {
|
|
||||||
let resource_path = req.path();
|
|
||||||
let destination =
|
|
||||||
req.headers()
|
|
||||||
.get("destination")
|
|
||||||
.unwrap()
|
|
||||||
.map_or("".to_string(), |v| {
|
|
||||||
v.split("http://")
|
|
||||||
.nth(1)
|
|
||||||
.unwrap()
|
|
||||||
.split("/")
|
|
||||||
.skip(1)
|
|
||||||
.collect::<Vec<&str>>()
|
|
||||||
.join("/")
|
|
||||||
});
|
|
||||||
let depth: Depth = req
|
|
||||||
.headers()
|
|
||||||
.get("depth")
|
|
||||||
.unwrap()
|
|
||||||
.map_or("infinity".to_string(), |v| v)
|
|
||||||
.into();
|
|
||||||
let overwrite: Overwrite = req
|
|
||||||
.headers()
|
|
||||||
.get("overwrite")
|
|
||||||
.unwrap()
|
|
||||||
.map_or("T".to_string(), |v| v.to_string())
|
|
||||||
.into();
|
|
||||||
dav.handle_move(resource_path, destination, depth, overwrite)
|
|
||||||
.await
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
_ => dav.handle_unsupport_method().await.into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
match dav_response {
|
|
||||||
DavResponseType::DavResponse(r) => r.map_or_else(
|
|
||||||
|e| {
|
|
||||||
let (status_code, headers, body) = e;
|
|
||||||
Response::error(body.unwrap_or("".to_string()), status_code).map(|response| {
|
|
||||||
match headers {
|
|
||||||
Some(headers) => response.with_headers(Headers::from_iter(headers)),
|
|
||||||
None => response,
|
|
||||||
}
|
|
||||||
.with_status(status_code)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|r| {
|
|
||||||
let (status_code, headers, body) = r;
|
|
||||||
Response::from_body(ResponseBody::Body(body.into_bytes())).map(|response| {
|
|
||||||
response
|
|
||||||
.with_headers(Headers::from_iter(headers))
|
|
||||||
.with_status(status_code)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
),
|
|
||||||
DavResponseType::DavStreamResponse(r) => r.map_or_else(
|
|
||||||
|e| {
|
|
||||||
let (status_code, headers, body) = e;
|
|
||||||
Response::error(body.unwrap_or("".to_string()), status_code).map(|response| {
|
|
||||||
match headers {
|
|
||||||
Some(headers) => response.with_headers(Headers::from_iter(headers)),
|
|
||||||
None => response,
|
|
||||||
}
|
|
||||||
.with_status(status_code)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|r| {
|
|
||||||
let (status_code, headers, body) = r;
|
|
||||||
Response::from_stream(body).map(|response| {
|
|
||||||
response
|
|
||||||
.with_headers(Headers::from_iter(headers))
|
|
||||||
.with_status(status_code)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
26
src/r2.rs
26
src/r2.rs
@ -1,5 +1,5 @@
|
|||||||
use crate::values::{DavProperties, Range};
|
use crate::values::{DavProperties, Range};
|
||||||
use worker::{Bucket, ByteStream, FixedLengthStream, Range as R2Range};
|
use worker::{console_debug, Bucket, ByteStream, FixedLengthStream, Headers, Range as R2Range};
|
||||||
|
|
||||||
pub struct R2 {
|
pub struct R2 {
|
||||||
bucket: Bucket,
|
bucket: Bucket,
|
||||||
@ -11,10 +11,9 @@ impl R2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get(&self, path: String) -> Result<(String, DavProperties), String> {
|
pub async fn get(&self, path: String) -> Result<(String, DavProperties), String> {
|
||||||
let result = self.bucket.get(path).execute().await;
|
match self.bucket.get(path).execute().await {
|
||||||
match result {
|
|
||||||
Ok(f) => f.map_or(Err("Resource not found".to_string()), |file| {
|
Ok(f) => f.map_or(Err("Resource not found".to_string()), |file| {
|
||||||
Ok((file.key(), DavProperties::from_r2(&file)))
|
Ok((file.key(), DavProperties::from(&file)))
|
||||||
}),
|
}),
|
||||||
Err(error) => Err(error.to_string()),
|
Err(error) => Err(error.to_string()),
|
||||||
}
|
}
|
||||||
@ -25,7 +24,8 @@ impl R2 {
|
|||||||
Ok(files) => {
|
Ok(files) => {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for file in files.objects() {
|
for file in files.objects() {
|
||||||
result.push((file.key(), DavProperties::from_r2(&file)))
|
console_debug!("Access {}", file.key());
|
||||||
|
result.push((file.key(), DavProperties::from(&file)))
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
@ -33,6 +33,18 @@ impl R2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn patch_metadata(&self, path: String, metadata: Headers) -> Result<(), String> {
|
||||||
|
match self.bucket.get(path).execute().await {
|
||||||
|
Ok(f) => f.map_or(Err("Resource not found".to_string()), |file| {
|
||||||
|
match file.write_http_metadata(metadata) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(error) => Err(error.to_string()),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Err(error) => Err(error.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn download(
|
pub async fn download(
|
||||||
&self,
|
&self,
|
||||||
path: String,
|
path: String,
|
||||||
@ -66,7 +78,7 @@ impl R2 {
|
|||||||
.map_or(Err("Failed to get file body stream".to_string()), |b| {
|
.map_or(Err("Failed to get file body stream".to_string()), |b| {
|
||||||
b.stream().map_or(
|
b.stream().map_or(
|
||||||
Err("Failed to get file body stream".to_string()),
|
Err("Failed to get file body stream".to_string()),
|
||||||
|stream| Ok((DavProperties::from_r2(&file), stream)),
|
|stream| Ok((DavProperties::from(&file), stream)),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
@ -93,7 +105,7 @@ impl R2 {
|
|||||||
.execute()
|
.execute()
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(file) => Ok(DavProperties::from_r2(&file)),
|
Ok(file) => Ok(DavProperties::from(&file)),
|
||||||
Err(error) => Err(error.to_string()),
|
Err(error) => Err(error.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use worker::Object;
|
use worker::{console_debug, Object};
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Hash, Eq)]
|
#[derive(Default, Debug, Clone, PartialEq, Hash, Eq)]
|
||||||
pub enum Depth {
|
pub enum Depth {
|
||||||
@ -90,9 +90,11 @@ pub struct DavProperties {
|
|||||||
pub get_last_modified: Option<String>,
|
pub get_last_modified: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DavProperties {
|
impl From<&Object> for DavProperties {
|
||||||
pub fn from_r2(file: &Object) -> DavProperties {
|
fn from(file: &Object) -> DavProperties {
|
||||||
|
console_debug!("Calling from Object for DavProperties");
|
||||||
let http_metedata = file.http_metadata();
|
let http_metedata = file.http_metadata();
|
||||||
|
console_debug!("http_metedata {:?}", http_metedata);
|
||||||
DavProperties {
|
DavProperties {
|
||||||
creation_date: Some(file.uploaded().to_string()),
|
creation_date: Some(file.uploaded().to_string()),
|
||||||
display_name: http_metedata.content_disposition,
|
display_name: http_metedata.content_disposition,
|
||||||
|
Loading…
Reference in New Issue
Block a user