Server: store POST: avoids arbitrary choice if the mime type matches both a graph and dataset format

pull/300/head
Tpt 2 years ago committed by Thomas Tanon
parent 38fdffc147
commit 112631a0d7
  1. 77
      server/src/main.rs

@ -1,4 +1,4 @@
use anyhow::bail; use anyhow::{anyhow, bail};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use flate2::read::MultiGzDecoder; use flate2::read::MultiGzDecoder;
use oxhttp::model::{Body, HeaderName, HeaderValue, Request, Response, Status}; use oxhttp::model::{Body, HeaderName, HeaderValue, Request, Response, Status};
@ -177,7 +177,7 @@ enum GraphOrDatasetFormat {
impl GraphOrDatasetFormat { impl GraphOrDatasetFormat {
fn from_path(path: &Path) -> anyhow::Result<Self> { fn from_path(path: &Path) -> anyhow::Result<Self> {
if let Some(ext) = path.extension().and_then(|ext| ext.to_str()) { if let Some(ext) = path.extension().and_then(|ext| ext.to_str()) {
Self::from_name(ext).map_err(|e| { Self::from_extension(ext).map_err(|e| {
e.context(format!( e.context(format!(
"Not able to guess the file format from file name extension '{}'", "Not able to guess the file format from file name extension '{}'",
ext ext
@ -191,31 +191,30 @@ impl GraphOrDatasetFormat {
} }
} }
fn from_name(name: &str) -> anyhow::Result<Self> { fn from_extension(name: &str) -> anyhow::Result<Self> {
let mut candidates = Vec::with_capacity(4); match (GraphFormat::from_extension(name), DatasetFormat::from_extension(name)) {
if let Some(f) = GraphFormat::from_extension(name) { (Some(g), Some(d)) => Err(anyhow!("The file extension '{}' can be resolved to both '{}' and '{}', not sure what to pick", name, g.file_extension(), d.file_extension())),
candidates.push(GraphOrDatasetFormat::Graph(f)); (Some(g), None) => Ok(GraphOrDatasetFormat::Graph(g)),
(None, Some(d)) => Ok(GraphOrDatasetFormat::Dataset(d)),
(None, None) =>
Err(anyhow!("The file extension '{}' is unknown", name))
} }
if let Some(f) = DatasetFormat::from_extension(name) {
candidates.push(GraphOrDatasetFormat::Dataset(f));
} }
if let Some(f) = GraphFormat::from_media_type(name) {
candidates.push(GraphOrDatasetFormat::Graph(f)); fn from_media_type(name: &str) -> anyhow::Result<Self> {
} match (
if let Some(f) = DatasetFormat::from_media_type(name) { GraphFormat::from_media_type(name),
candidates.push(GraphOrDatasetFormat::Dataset(f)); DatasetFormat::from_media_type(name),
} ) {
if candidates.is_empty() { (Some(g), Some(d)) => Err(anyhow!(
bail!("The format '{}' is unknown", name) "The media type '{}' can be resolved to both '{}' and '{}', not sure what to pick",
} else if candidates.len() == 1 { name,
Ok(candidates[0]) g.file_extension(),
} else { d.file_extension()
bail!("The format '{}' can be resolved to multiple known formats, not sure what to pick ({})", name, candidates.iter().fold(String::new(), |a, f| { )),
a + " " + match f { (Some(g), None) => Ok(GraphOrDatasetFormat::Graph(g)),
GraphOrDatasetFormat::Graph(f) => f.file_extension(), (None, Some(d)) => Ok(GraphOrDatasetFormat::Dataset(d)),
GraphOrDatasetFormat::Dataset(f) => f.file_extension(), (None, None) => Err(anyhow!("The media type '{}' is unknown", name)),
}
}).trim())
} }
} }
} }
@ -442,7 +441,8 @@ fn handle_request(request: &mut Request, store: Store) -> Result<Response, HttpE
let content_type = let content_type =
content_type(request).ok_or_else(|| bad_request("No Content-Type given"))?; content_type(request).ok_or_else(|| bad_request("No Content-Type given"))?;
if let Some(target) = store_target(request)? { if let Some(target) = store_target(request)? {
if let Some(format) = GraphFormat::from_media_type(&content_type) { let format = GraphFormat::from_media_type(&content_type)
.ok_or_else(|| unsupported_media_type(&content_type))?;
let new = assert_that_graph_exists(&store, &target).is_ok(); let new = assert_that_graph_exists(&store, &target).is_ok();
store store
.load_graph( .load_graph(
@ -459,15 +459,12 @@ fn handle_request(request: &mut Request, store: Store) -> Result<Response, HttpE
}) })
.build()) .build())
} else { } else {
Err(unsupported_media_type(&content_type)) match GraphOrDatasetFormat::from_media_type(&content_type)
} .map_err(|_| unsupported_media_type(&content_type))?
} else if let Some(format) = DatasetFormat::from_media_type(&content_type) { {
store GraphOrDatasetFormat::Graph(format) => {
.load_dataset(BufReader::new(request.body_mut()), format, None) let graph =
.map_err(bad_request)?; resolve_with_base(request, &format!("/store/{:x}", random::<u128>()))?;
Ok(Response::builder(Status::NO_CONTENT).build())
} else if let Some(format) = GraphFormat::from_media_type(&content_type) {
let graph = resolve_with_base(request, &format!("/store/{:x}", random::<u128>()))?;
store store
.load_graph(BufReader::new(request.body_mut()), format, &graph, None) .load_graph(BufReader::new(request.body_mut()), format, &graph, None)
.map_err(bad_request)?; .map_err(bad_request)?;
@ -475,8 +472,14 @@ fn handle_request(request: &mut Request, store: Store) -> Result<Response, HttpE
.with_header(HeaderName::LOCATION, graph.into_string()) .with_header(HeaderName::LOCATION, graph.into_string())
.unwrap() .unwrap()
.build()) .build())
} else { }
Err(unsupported_media_type(&content_type)) GraphOrDatasetFormat::Dataset(format) => {
store
.load_dataset(BufReader::new(request.body_mut()), format, None)
.map_err(bad_request)?;
Ok(Response::builder(Status::NO_CONTENT).build())
}
}
} }
} }
(path, "HEAD") if path.starts_with("/store") => { (path, "HEAD") if path.starts_with("/store") => {

Loading…
Cancel
Save