feat: add addressing/hashing of remote urls
parent
00bf65c596
commit
634c5a7c6a
|
@ -1,10 +1,11 @@
|
||||||
use crate::extractors::{self};
|
use crate::extractors;
|
||||||
use crate::previews::PreviewStore;
|
use crate::previews::PreviewStore;
|
||||||
use crate::util::exec::block_background;
|
use crate::util::exec::block_background;
|
||||||
use actix_files::NamedFile;
|
use actix_files::NamedFile;
|
||||||
use actix_multipart::Multipart;
|
use actix_multipart::Multipart;
|
||||||
use actix_web::error::{
|
use actix_web::error::{
|
||||||
ErrorBadRequest, ErrorInternalServerError, ErrorNotFound, ErrorUnauthorized,
|
ErrorBadRequest, ErrorInternalServerError, ErrorNotFound, ErrorUnauthorized,
|
||||||
|
ErrorUnprocessableEntity,
|
||||||
};
|
};
|
||||||
use actix_web::{delete, error, get, post, put, web, Either, Error, HttpResponse};
|
use actix_web::{delete, error, get, post, put, web, Either, Error, HttpResponse};
|
||||||
use actix_web::{http, Responder};
|
use actix_web::{http, Responder};
|
||||||
|
@ -25,7 +26,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
use tracing::{debug, info, trace};
|
use tracing::{debug, info, trace};
|
||||||
use upend::addressing::{Address, Addressable};
|
use upend::addressing::{Address, Addressable};
|
||||||
use upend::common::build;
|
use upend::common::{build, APP_USER_AGENT};
|
||||||
use upend::config::UpEndConfig;
|
use upend::config::UpEndConfig;
|
||||||
use upend::database::constants::{ADDED_ATTR, LABEL_ATTR};
|
use upend::database::constants::{ADDED_ATTR, LABEL_ATTR};
|
||||||
use upend::database::entry::{Entry, EntryValue, InvariantEntry};
|
use upend::database::entry::{Entry, EntryValue, InvariantEntry};
|
||||||
|
@ -33,7 +34,7 @@ use upend::database::hierarchies::{list_roots, resolve_path, UHierPath};
|
||||||
use upend::database::lang::Query;
|
use upend::database::lang::Query;
|
||||||
use upend::database::stores::{Blob, UpStore};
|
use upend::database::stores::{Blob, UpStore};
|
||||||
use upend::database::UpEndDatabase;
|
use upend::database::UpEndDatabase;
|
||||||
use upend::util::hash::{b58_decode, b58_encode};
|
use upend::util::hash::{b58_decode, b58_encode, hash};
|
||||||
use upend::util::jobs;
|
use upend::util::jobs;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -643,32 +644,70 @@ pub async fn delete_object(
|
||||||
// Ok(HttpResponse::Ok().finish())
|
// Ok(HttpResponse::Ok().finish())
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct GetAddressRequest {
|
|
||||||
attribute: Option<String>,
|
|
||||||
// url: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/api/address")]
|
#[get("/api/address")]
|
||||||
pub async fn get_address(
|
pub async fn get_address(
|
||||||
web::Query(query): web::Query<GetAddressRequest>,
|
web::Query(query): web::Query<HashMap<String, String>>,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let address = match query {
|
let (address, immutable) = if let Some(attribute) = query.get("attribute") {
|
||||||
GetAddressRequest {
|
(Address::Attribute(attribute.into()), true)
|
||||||
attribute: Some(attribute),
|
} else if let Some(url) = query.get("url") {
|
||||||
} => Address::Attribute(attribute),
|
(
|
||||||
_ => Err(ErrorBadRequest("Specify one of: `attribute`"))?,
|
Address::Url(Url::parse(url).map_err(ErrorBadRequest)?),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
} else if let Some(url) = query.get("url_content") {
|
||||||
|
let url = Url::parse(url).map_err(ErrorBadRequest)?;
|
||||||
|
|
||||||
|
const MAX_SIZE: usize = 128_000;
|
||||||
|
|
||||||
|
let client = reqwest::blocking::Client::builder()
|
||||||
|
.user_agent(APP_USER_AGENT.as_str())
|
||||||
|
.build()
|
||||||
|
.map_err(ErrorInternalServerError)?;
|
||||||
|
|
||||||
|
let response = client
|
||||||
|
.get(url)
|
||||||
|
.send()
|
||||||
|
.map_err(ErrorInternalServerError)?
|
||||||
|
.error_for_status()
|
||||||
|
.map_err(ErrorInternalServerError)?;
|
||||||
|
|
||||||
|
if let Some(content_length) = response.headers().get(reqwest::header::CONTENT_LENGTH) {
|
||||||
|
if let Some(content_length) = content_length
|
||||||
|
.to_str()
|
||||||
|
.ok()
|
||||||
|
.and_then(|cl| cl.parse::<usize>().ok())
|
||||||
|
{
|
||||||
|
if content_length > MAX_SIZE {
|
||||||
|
return Err(ErrorBadRequest("Error: The response is too large."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ErrorUnprocessableEntity(
|
||||||
|
"Error: Could not ascertain response size.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytes = response.bytes().map_err(ErrorInternalServerError)?;
|
||||||
|
let hash_result = hash(&bytes);
|
||||||
|
(Address::Hash(hash_result), false)
|
||||||
|
} else {
|
||||||
|
return Err(ErrorBadRequest(anyhow!(
|
||||||
|
"Specify one of: `attribute`, `url`, `url_content`."
|
||||||
|
)));
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(HttpResponse::Ok()
|
let mut response = HttpResponse::Ok();
|
||||||
.set_header(
|
if immutable {
|
||||||
|
response.set_header(
|
||||||
http::header::CACHE_CONTROL,
|
http::header::CACHE_CONTROL,
|
||||||
CacheControl(vec![
|
CacheControl(vec![
|
||||||
CacheDirective::MaxAge(2678400),
|
CacheDirective::MaxAge(2678400),
|
||||||
CacheDirective::Extension("immutable".into(), None),
|
CacheDirective::Extension("immutable".into(), None),
|
||||||
]),
|
]),
|
||||||
)
|
);
|
||||||
.json(format!("{}", address)))
|
}
|
||||||
|
Ok(response.json(format!("{}", address)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/api/all/attributes")]
|
#[get("/api/all/attributes")]
|
||||||
|
|
Loading…
Reference in New Issue