Server: simplifies error related code

pull/300/head
Tpt 2 years ago committed by Thomas Tanon
parent 7f89baad87
commit 3f7ff6843d
  1. 467
      server/src/main.rs

@ -6,7 +6,7 @@ use oxhttp::Server;
use oxigraph::io::{DatasetFormat, DatasetSerializer, GraphFormat, GraphSerializer}; use oxigraph::io::{DatasetFormat, DatasetSerializer, GraphFormat, GraphSerializer};
use oxigraph::model::{GraphName, GraphNameRef, IriParseError, NamedNode, NamedOrBlankNode}; use oxigraph::model::{GraphName, GraphNameRef, IriParseError, NamedNode, NamedOrBlankNode};
use oxigraph::sparql::{Query, QueryResults, Update}; use oxigraph::sparql::{Query, QueryResults, Update};
use oxigraph::store::{BulkLoader, Store}; use oxigraph::store::{BulkLoader, LoaderError, Store};
use oxiri::Iri; use oxiri::Iri;
use rand::random; use rand::random;
use rayon_core::ThreadPoolBuilder; use rayon_core::ThreadPoolBuilder;
@ -137,7 +137,10 @@ pub fn main() -> anyhow::Result<()> {
Ok(()) Ok(())
} }
Command::Serve { bind } => { Command::Serve { bind } => {
let mut server = Server::new(move |request| handle_request(request, store.clone())); let mut server = Server::new(move |request| {
handle_request(request, store.clone())
.unwrap_or_else(|(status, message)| error(status, message))
});
server.set_global_timeout(HTTP_TIMEOUT); server.set_global_timeout(HTTP_TIMEOUT);
server server
.set_server_name(concat!("Oxigraph/", env!("CARGO_PKG_VERSION"))) .set_server_name(concat!("Oxigraph/", env!("CARGO_PKG_VERSION")))
@ -154,7 +157,7 @@ fn bulk_load(
reader: impl Read, reader: impl Read,
format: GraphOrDatasetFormat, format: GraphOrDatasetFormat,
base_iri: Option<&str>, base_iri: Option<&str>,
) -> anyhow::Result<()> { ) -> Result<(), LoaderError> {
let reader = BufReader::new(reader); let reader = BufReader::new(reader);
match format { match format {
GraphOrDatasetFormat::Graph(format) => { GraphOrDatasetFormat::Graph(format) => {
@ -217,24 +220,26 @@ impl GraphOrDatasetFormat {
} }
} }
fn handle_request(request: &mut Request, store: Store) -> Response { type HttpError = (Status, String);
fn handle_request(request: &mut Request, store: Store) -> Result<Response, HttpError> {
match (request.url().path(), request.method().as_ref()) { match (request.url().path(), request.method().as_ref()) {
("/", "HEAD") => Response::builder(Status::OK) ("/", "HEAD") => Ok(Response::builder(Status::OK)
.with_header(HeaderName::CONTENT_TYPE, "text_html") .with_header(HeaderName::CONTENT_TYPE, "text_html")
.unwrap() .unwrap()
.build(), .build()),
("/", "GET") => Response::builder(Status::OK) ("/", "GET") => Ok(Response::builder(Status::OK)
.with_header(HeaderName::CONTENT_TYPE, "text_html") .with_header(HeaderName::CONTENT_TYPE, "text_html")
.unwrap() .unwrap()
.with_body(HTML_ROOT_PAGE), .with_body(HTML_ROOT_PAGE)),
("/logo.svg", "HEAD") => Response::builder(Status::OK) ("/logo.svg", "HEAD") => Ok(Response::builder(Status::OK)
.with_header(HeaderName::CONTENT_TYPE, "image/svg+xml") .with_header(HeaderName::CONTENT_TYPE, "image/svg+xml")
.unwrap() .unwrap()
.build(), .build()),
("/logo.svg", "GET") => Response::builder(Status::OK) ("/logo.svg", "GET") => Ok(Response::builder(Status::OK)
.with_header(HeaderName::CONTENT_TYPE, "image/svg+xml") .with_header(HeaderName::CONTENT_TYPE, "image/svg+xml")
.unwrap() .unwrap()
.with_body(LOGO), .with_body(LOGO)),
("/query", "GET") => { ("/query", "GET") => {
configure_and_evaluate_sparql_query(store, &[url_query(request)], None, request) configure_and_evaluate_sparql_query(store, &[url_query(request)], None, request)
} }
@ -242,13 +247,11 @@ fn handle_request(request: &mut Request, store: Store) -> Response {
if let Some(content_type) = content_type(request) { if let Some(content_type) = content_type(request) {
if content_type == "application/sparql-query" { if content_type == "application/sparql-query" {
let mut buffer = String::new(); let mut buffer = String::new();
if let Err(e) = request request
.body_mut() .body_mut()
.take(MAX_SPARQL_BODY_SIZE) .take(MAX_SPARQL_BODY_SIZE)
.read_to_string(&mut buffer) .read_to_string(&mut buffer)
{ .map_err(bad_request)?;
return bad_request(e);
}
configure_and_evaluate_sparql_query( configure_and_evaluate_sparql_query(
store, store,
&[url_query(request)], &[url_query(request)],
@ -257,13 +260,11 @@ fn handle_request(request: &mut Request, store: Store) -> Response {
) )
} else if content_type == "application/x-www-form-urlencoded" { } else if content_type == "application/x-www-form-urlencoded" {
let mut buffer = Vec::new(); let mut buffer = Vec::new();
if let Err(e) = request request
.body_mut() .body_mut()
.take(MAX_SPARQL_BODY_SIZE) .take(MAX_SPARQL_BODY_SIZE)
.read_to_end(&mut buffer) .read_to_end(&mut buffer)
{ .map_err(bad_request)?;
return bad_request(e);
}
configure_and_evaluate_sparql_query( configure_and_evaluate_sparql_query(
store, store,
&[url_query(request), &buffer], &[url_query(request), &buffer],
@ -271,23 +272,21 @@ fn handle_request(request: &mut Request, store: Store) -> Response {
request, request,
) )
} else { } else {
unsupported_media_type(&content_type) Err(unsupported_media_type(&content_type))
} }
} else { } else {
bad_request("No Content-Type given") Err(bad_request("No Content-Type given"))
} }
} }
("/update", "POST") => { ("/update", "POST") => {
if let Some(content_type) = content_type(request) { if let Some(content_type) = content_type(request) {
if content_type == "application/sparql-update" { if content_type == "application/sparql-update" {
let mut buffer = String::new(); let mut buffer = String::new();
if let Err(e) = request request
.body_mut() .body_mut()
.take(MAX_SPARQL_BODY_SIZE) .take(MAX_SPARQL_BODY_SIZE)
.read_to_string(&mut buffer) .read_to_string(&mut buffer)
{ .map_err(bad_request)?;
return bad_request(e);
}
configure_and_evaluate_sparql_update( configure_and_evaluate_sparql_update(
store, store,
&[url_query(request)], &[url_query(request)],
@ -296,13 +295,11 @@ fn handle_request(request: &mut Request, store: Store) -> Response {
) )
} else if content_type == "application/x-www-form-urlencoded" { } else if content_type == "application/x-www-form-urlencoded" {
let mut buffer = Vec::new(); let mut buffer = Vec::new();
if let Err(e) = request request
.body_mut() .body_mut()
.take(MAX_SPARQL_BODY_SIZE) .take(MAX_SPARQL_BODY_SIZE)
.read_to_end(&mut buffer) .read_to_end(&mut buffer)
{ .map_err(bad_request)?;
return bad_request(e);
}
configure_and_evaluate_sparql_update( configure_and_evaluate_sparql_update(
store, store,
&[url_query(request), &buffer], &[url_query(request), &buffer],
@ -310,33 +307,26 @@ fn handle_request(request: &mut Request, store: Store) -> Response {
request, request,
) )
} else { } else {
unsupported_media_type(&content_type) return Err(unsupported_media_type(&content_type));
} }
} else { } else {
bad_request("No Content-Type given") Err(bad_request("No Content-Type given"))
} }
} }
(path, "GET") if path.starts_with("/store") => { (path, "GET") if path.starts_with("/store") => {
if let Some(target) = match store_target(request) { if let Some(target) = store_target(request)? {
Ok(target) => target,
Err(error) => return error,
} {
if !match &target { if !match &target {
NamedGraphName::DefaultGraph => true, NamedGraphName::DefaultGraph => true,
NamedGraphName::NamedNode(target) => match store.contains_named_graph(target) { NamedGraphName::NamedNode(target) => store
Ok(r) => r, .contains_named_graph(target)
Err(e) => return internal_server_error(e), .map_err(internal_server_error)?,
},
} { } {
return error( return Err((
Status::NOT_FOUND, Status::NOT_FOUND,
format!("The graph {} does not exists", GraphName::from(target)), format!("The graph {} does not exists", GraphName::from(target)),
); ));
} }
let format = match graph_content_negotiation(request) { let format = graph_content_negotiation(request)?;
Ok(format) => format,
Err(response) => return response,
};
let triples = store.quads_for_pattern( let triples = store.quads_for_pattern(
None, None,
None, None,
@ -362,10 +352,7 @@ fn handle_request(request: &mut Request, store: Store) -> Response {
format.media_type(), format.media_type(),
) )
} else { } else {
let format = match dataset_content_negotiation(request) { let format = dataset_content_negotiation(request)?;
Ok(format) => format,
Err(response) => return response,
};
ReadForWrite::build_response( ReadForWrite::build_response(
move |w| { move |w| {
Ok(( Ok((
@ -388,198 +375,164 @@ fn handle_request(request: &mut Request, store: Store) -> Response {
} }
(path, "PUT") if path.starts_with("/store") => { (path, "PUT") if path.starts_with("/store") => {
if let Some(content_type) = content_type(request) { if let Some(content_type) = content_type(request) {
if let Some(target) = match store_target(request) { if let Some(target) = store_target(request)? {
Ok(target) => target,
Err(error) => return error,
} {
if let Some(format) = GraphFormat::from_media_type(&content_type) { if let Some(format) = GraphFormat::from_media_type(&content_type) {
let new = !match &target { let new = !match &target {
NamedGraphName::NamedNode(target) => { NamedGraphName::NamedNode(target) => {
if match store.contains_named_graph(target) { if store
Ok(r) => r, .contains_named_graph(target)
Err(e) => return internal_server_error(e), .map_err(internal_server_error)?
} { {
if let Err(e) = store.clear_graph(target) { store.clear_graph(target).map_err(internal_server_error)?;
return internal_server_error(e);
}
true true
} else { } else {
if let Err(e) = store.insert_named_graph(target) { store
return internal_server_error(e); .insert_named_graph(target)
} .map_err(internal_server_error)?;
false false
} }
} }
NamedGraphName::DefaultGraph => { NamedGraphName::DefaultGraph => {
if let Err(e) = store.clear_graph(GraphNameRef::DefaultGraph) { store
return internal_server_error(e); .clear_graph(GraphNameRef::DefaultGraph)
} .map_err(internal_server_error)?;
true true
} }
}; };
if let Err(e) = store.load_graph( store
BufReader::new(request.body_mut()), .load_graph(
format, BufReader::new(request.body_mut()),
GraphName::from(target).as_ref(), format,
None, GraphName::from(target).as_ref(),
) { None,
return bad_request(e); )
} .map_err(bad_request)?;
Response::builder(if new { Ok(Response::builder(if new {
Status::CREATED Status::CREATED
} else { } else {
Status::NO_CONTENT Status::NO_CONTENT
}) })
.build() .build())
} else { } else {
unsupported_media_type(&content_type) Err(unsupported_media_type(&content_type))
} }
} else if let Some(format) = DatasetFormat::from_media_type(&content_type) { } else if let Some(format) = DatasetFormat::from_media_type(&content_type) {
if let Err(e) = store.clear() { store.clear().map_err(internal_server_error)?;
return internal_server_error(e); store
} .load_dataset(BufReader::new(request.body_mut()), format, None)
if let Err(e) = .map_err(internal_server_error)?;
store.load_dataset(BufReader::new(request.body_mut()), format, None) Ok(Response::builder(Status::NO_CONTENT).build())
{
return internal_server_error(e);
}
Response::builder(Status::NO_CONTENT).build()
} else { } else {
unsupported_media_type(&content_type) Err(unsupported_media_type(&content_type))
} }
} else { } else {
bad_request("No Content-Type given") Err(bad_request("No Content-Type given"))
} }
} }
(path, "DELETE") if path.starts_with("/store") => { (path, "DELETE") if path.starts_with("/store") => {
if let Some(target) = match store_target(request) { if let Some(target) = store_target(request)? {
Ok(target) => target,
Err(error) => return error,
} {
match target { match target {
NamedGraphName::DefaultGraph => { NamedGraphName::DefaultGraph => store
if let Err(e) = store.clear_graph(GraphNameRef::DefaultGraph) { .clear_graph(GraphNameRef::DefaultGraph)
return internal_server_error(e); .map_err(internal_server_error)?,
}
}
NamedGraphName::NamedNode(target) => { NamedGraphName::NamedNode(target) => {
if match store.contains_named_graph(&target) { if store
Ok(r) => r, .contains_named_graph(&target)
Err(e) => return internal_server_error(e), .map_err(internal_server_error)?
} { {
if let Err(e) = store.remove_named_graph(&target) { store
return internal_server_error(e); .remove_named_graph(&target)
} .map_err(internal_server_error)?;
} else { } else {
return error( return Err((
Status::NOT_FOUND, Status::NOT_FOUND,
format!("The graph {} does not exists", target), format!("The graph {} does not exists", target),
); ));
} }
} }
} }
} else if let Err(e) = store.clear() { } else {
return internal_server_error(e); store.clear().map_err(internal_server_error)?;
} }
Response::builder(Status::NO_CONTENT).build() Ok(Response::builder(Status::NO_CONTENT).build())
} }
(path, "POST") if path.starts_with("/store") => { (path, "POST") if path.starts_with("/store") => {
if let Some(content_type) = content_type(request) { if let Some(content_type) = content_type(request) {
if let Some(target) = match store_target(request) { if let Some(target) = store_target(request)? {
Ok(target) => target,
Err(error) => return error,
} {
if let Some(format) = GraphFormat::from_media_type(&content_type) { if let Some(format) = GraphFormat::from_media_type(&content_type) {
let new = !match &target { let new = !match &target {
NamedGraphName::NamedNode(target) => { NamedGraphName::NamedNode(target) => store
match store.contains_named_graph(target) { .contains_named_graph(target)
Ok(r) => r, .map_err(internal_server_error)?,
Err(e) => return internal_server_error(e),
}
}
NamedGraphName::DefaultGraph => true, NamedGraphName::DefaultGraph => true,
}; };
if let Err(e) = store.load_graph( store
BufReader::new(request.body_mut()), .load_graph(
format, BufReader::new(request.body_mut()),
GraphName::from(target).as_ref(), format,
None, GraphName::from(target).as_ref(),
) { None,
return bad_request(e); )
} .map_err(bad_request)?;
Response::builder(if new { Ok(Response::builder(if new {
Status::CREATED Status::CREATED
} else { } else {
Status::NO_CONTENT Status::NO_CONTENT
}) })
.build() .build())
} else { } else {
unsupported_media_type(&content_type) Err(unsupported_media_type(&content_type))
} }
} else if let Some(format) = DatasetFormat::from_media_type(&content_type) { } else if let Some(format) = DatasetFormat::from_media_type(&content_type) {
if let Err(e) = store
store.load_dataset(BufReader::new(request.body_mut()), format, None) .load_dataset(BufReader::new(request.body_mut()), format, None)
{ .map_err(bad_request)?;
return bad_request(e); Ok(Response::builder(Status::NO_CONTENT).build())
}
Response::builder(Status::NO_CONTENT).build()
} else if let Some(format) = GraphFormat::from_media_type(&content_type) { } else if let Some(format) = GraphFormat::from_media_type(&content_type) {
let graph = let graph =
match resolve_with_base(request, &format!("/store/{:x}", random::<u128>())) resolve_with_base(request, &format!("/store/{:x}", random::<u128>()))?;
{ store
Ok(graph) => graph, .load_graph(BufReader::new(request.body_mut()), format, &graph, None)
Err(e) => return e, .map_err(bad_request)?;
}; Ok(Response::builder(Status::CREATED)
if let Err(e) =
store.load_graph(BufReader::new(request.body_mut()), format, &graph, None)
{
return bad_request(e);
}
Response::builder(Status::CREATED)
.with_header(HeaderName::LOCATION, graph.into_string()) .with_header(HeaderName::LOCATION, graph.into_string())
.unwrap() .unwrap()
.build() .build())
} else { } else {
unsupported_media_type(&content_type) Err(unsupported_media_type(&content_type))
} }
} else { } else {
bad_request("No Content-Type given") Err(bad_request("No Content-Type given"))
} }
} }
(path, "HEAD") if path.starts_with("/store") => { (path, "HEAD") if path.starts_with("/store") => {
if let Some(target) = match store_target(request) { if let Some(target) = store_target(request)? {
Ok(target) => target,
Err(error) => return error,
} {
if !match &target { if !match &target {
NamedGraphName::DefaultGraph => true, NamedGraphName::DefaultGraph => true,
NamedGraphName::NamedNode(target) => match store.contains_named_graph(target) { NamedGraphName::NamedNode(target) => store
Ok(r) => r, .contains_named_graph(target)
Err(e) => return internal_server_error(e), .map_err(internal_server_error)?,
},
} { } {
return error( return Err((
Status::NOT_FOUND, Status::NOT_FOUND,
format!("The graph {} does not exists", GraphName::from(target)), format!("The graph {} does not exists", GraphName::from(target)),
); ));
} }
Response::builder(Status::OK).build()
} else {
Response::builder(Status::OK).build()
} }
Ok(Response::builder(Status::OK).build())
} }
_ => error( _ => Err((
Status::NOT_FOUND, Status::NOT_FOUND,
format!( format!(
"{} {} is not supported by this server", "{} {} is not supported by this server",
request.method(), request.method(),
request.url().path() request.url().path()
), ),
), )),
} }
} }
fn base_url(request: &Request) -> Result<String, Response> { fn base_url(request: &Request) -> Result<String, HttpError> {
let mut url = request.url().clone(); let mut url = request.url().clone();
if let Some(host) = request.url().host_str() { if let Some(host) = request.url().host_str() {
url.set_host(Some(host)).map_err(bad_request)?; url.set_host(Some(host)).map_err(bad_request)?;
@ -589,7 +542,7 @@ fn base_url(request: &Request) -> Result<String, Response> {
Ok(url.into()) Ok(url.into())
} }
fn resolve_with_base(request: &Request, url: &str) -> Result<NamedNode, Response> { fn resolve_with_base(request: &Request, url: &str) -> Result<NamedNode, HttpError> {
Ok(NamedNode::new_unchecked( Ok(NamedNode::new_unchecked(
Iri::parse(base_url(request)?) Iri::parse(base_url(request)?)
.map_err(bad_request)? .map_err(bad_request)?
@ -608,7 +561,7 @@ fn configure_and_evaluate_sparql_query(
encoded: &[&[u8]], encoded: &[&[u8]],
mut query: Option<String>, mut query: Option<String>,
request: &Request, request: &Request,
) -> Response { ) -> Result<Response, HttpError> {
let mut default_graph_uris = Vec::new(); let mut default_graph_uris = Vec::new();
let mut named_graph_uris = Vec::new(); let mut named_graph_uris = Vec::new();
let mut use_default_graph_as_union = false; let mut use_default_graph_as_union = false;
@ -617,7 +570,7 @@ fn configure_and_evaluate_sparql_query(
match k.as_ref() { match k.as_ref() {
"query" => { "query" => {
if query.is_some() { if query.is_some() {
return bad_request("Multiple query parameters provided"); return Err(bad_request("Multiple query parameters provided"));
} }
query = Some(v.into_owned()) query = Some(v.into_owned())
} }
@ -638,7 +591,7 @@ fn configure_and_evaluate_sparql_query(
request, request,
) )
} else { } else {
bad_request("You should set the 'query' parameter") Err(bad_request("You should set the 'query' parameter"))
} }
} }
@ -649,58 +602,37 @@ fn evaluate_sparql_query(
default_graph_uris: Vec<String>, default_graph_uris: Vec<String>,
named_graph_uris: Vec<String>, named_graph_uris: Vec<String>,
request: &Request, request: &Request,
) -> Response { ) -> Result<Response, HttpError> {
let mut query = match Query::parse( let mut query = Query::parse(&query, Some(&base_url(request)?)).map_err(bad_request)?;
&query,
Some(&match base_url(request) {
Ok(url) => url,
Err(r) => return r,
}),
) {
Ok(query) => query,
Err(e) => return bad_request(e),
};
if use_default_graph_as_union { if use_default_graph_as_union {
if !default_graph_uris.is_empty() || !named_graph_uris.is_empty() { if !default_graph_uris.is_empty() || !named_graph_uris.is_empty() {
return bad_request( return Err(bad_request(
"default-graph-uri or named-graph-uri and union-default-graph should not be set at the same time" "default-graph-uri or named-graph-uri and union-default-graph should not be set at the same time"
); ));
} }
query.dataset_mut().set_default_graph_as_union() query.dataset_mut().set_default_graph_as_union()
} else if !default_graph_uris.is_empty() || !named_graph_uris.is_empty() { } else if !default_graph_uris.is_empty() || !named_graph_uris.is_empty() {
query.dataset_mut().set_default_graph( query.dataset_mut().set_default_graph(
match default_graph_uris default_graph_uris
.into_iter() .into_iter()
.map(|e| Ok(NamedNode::new(e)?.into())) .map(|e| Ok(NamedNode::new(e)?.into()))
.collect::<Result<Vec<GraphName>, IriParseError>>() .collect::<Result<Vec<GraphName>, IriParseError>>()
{ .map_err(bad_request)?,
Ok(default_graph_uris) => default_graph_uris,
Err(e) => return bad_request(e),
},
); );
query.dataset_mut().set_available_named_graphs( query.dataset_mut().set_available_named_graphs(
match named_graph_uris named_graph_uris
.into_iter() .into_iter()
.map(|e| Ok(NamedNode::new(e)?.into())) .map(|e| Ok(NamedNode::new(e)?.into()))
.collect::<Result<Vec<NamedOrBlankNode>, IriParseError>>() .collect::<Result<Vec<NamedOrBlankNode>, IriParseError>>()
{ .map_err(bad_request)?,
Ok(named_graph_uris) => named_graph_uris,
Err(e) => return bad_request(e),
},
); );
} }
let results = match store.query(query) { let results = store.query(query).map_err(internal_server_error)?;
Ok(results) => results,
Err(e) => return internal_server_error(e),
};
match results { match results {
QueryResults::Solutions(solutions) => { QueryResults::Solutions(solutions) => {
let format = match query_results_content_negotiation(request) { let format = query_results_content_negotiation(request)?;
Ok(format) => format,
Err(response) => return response,
};
ReadForWrite::build_response( ReadForWrite::build_response(
move |w| { move |w| {
Ok(( Ok((
@ -722,26 +654,18 @@ fn evaluate_sparql_query(
) )
} }
QueryResults::Boolean(result) => { QueryResults::Boolean(result) => {
let format = match query_results_content_negotiation(request) { let format = query_results_content_negotiation(request)?;
Ok(format) => format,
Err(response) => return response,
};
let mut body = Vec::new(); let mut body = Vec::new();
if let Err(e) = QueryResultsSerializer::from_format(format)
QueryResultsSerializer::from_format(format).write_boolean_result(&mut body, result) .write_boolean_result(&mut body, result)
{ .map_err(internal_server_error)?;
return internal_server_error(e); Ok(Response::builder(Status::OK)
}
Response::builder(Status::OK)
.with_header(HeaderName::CONTENT_TYPE, format.media_type()) .with_header(HeaderName::CONTENT_TYPE, format.media_type())
.unwrap() .unwrap()
.with_body(body) .with_body(body))
} }
QueryResults::Graph(triples) => { QueryResults::Graph(triples) => {
let format = match graph_content_negotiation(request) { let format = graph_content_negotiation(request)?;
Ok(format) => format,
Err(response) => return response,
};
ReadForWrite::build_response( ReadForWrite::build_response(
move |w| { move |w| {
Ok(( Ok((
@ -769,7 +693,7 @@ fn configure_and_evaluate_sparql_update(
encoded: &[&[u8]], encoded: &[&[u8]],
mut update: Option<String>, mut update: Option<String>,
request: &Request, request: &Request,
) -> Response { ) -> Result<Response, HttpError> {
let mut use_default_graph_as_union = false; let mut use_default_graph_as_union = false;
let mut default_graph_uris = Vec::new(); let mut default_graph_uris = Vec::new();
let mut named_graph_uris = Vec::new(); let mut named_graph_uris = Vec::new();
@ -778,7 +702,7 @@ fn configure_and_evaluate_sparql_update(
match k.as_ref() { match k.as_ref() {
"update" => { "update" => {
if update.is_some() { if update.is_some() {
return bad_request("Multiple update parameters provided"); return Err(bad_request("Multiple update parameters provided"));
} }
update = Some(v.into_owned()) update = Some(v.into_owned())
} }
@ -799,7 +723,7 @@ fn configure_and_evaluate_sparql_update(
request, request,
) )
} else { } else {
bad_request("You should set the 'update' parameter") Err(bad_request("You should set the 'update' parameter"))
} }
} }
@ -810,69 +734,50 @@ fn evaluate_sparql_update(
default_graph_uris: Vec<String>, default_graph_uris: Vec<String>,
named_graph_uris: Vec<String>, named_graph_uris: Vec<String>,
request: &Request, request: &Request,
) -> Response { ) -> Result<Response, HttpError> {
let mut update = match Update::parse( let mut update =
&update, Update::parse(&update, Some(base_url(request)?.as_str())).map_err(bad_request)?;
Some(
match base_url(request) {
Ok(url) => url,
Err(e) => return e,
}
.as_str(),
),
) {
Ok(update) => update,
Err(e) => return bad_request(e),
};
if use_default_graph_as_union { if use_default_graph_as_union {
if !default_graph_uris.is_empty() || !named_graph_uris.is_empty() { if !default_graph_uris.is_empty() || !named_graph_uris.is_empty() {
return bad_request( return Err(bad_request(
"using-graph-uri or using-named-graph-uri and using-union-graph should not be set at the same time" "using-graph-uri or using-named-graph-uri and using-union-graph should not be set at the same time"
); ));
} }
for using in update.using_datasets_mut() { for using in update.using_datasets_mut() {
if !using.is_default_dataset() { if !using.is_default_dataset() {
return bad_request( return Err(bad_request(
"using-union-graph must not be used with a SPARQL UPDATE containing USING", "using-union-graph must not be used with a SPARQL UPDATE containing USING",
); ));
} }
using.set_default_graph_as_union(); using.set_default_graph_as_union();
} }
} else if !default_graph_uris.is_empty() || !named_graph_uris.is_empty() { } else if !default_graph_uris.is_empty() || !named_graph_uris.is_empty() {
let default_graph_uris = match default_graph_uris let default_graph_uris = default_graph_uris
.into_iter() .into_iter()
.map(|e| Ok(NamedNode::new(e)?.into())) .map(|e| Ok(NamedNode::new(e)?.into()))
.collect::<Result<Vec<GraphName>, IriParseError>>() .collect::<Result<Vec<GraphName>, IriParseError>>()
{ .map_err(bad_request)?;
Ok(default_graph_uris) => default_graph_uris, let named_graph_uris = named_graph_uris
Err(e) => return bad_request(e),
};
let named_graph_uris = match named_graph_uris
.into_iter() .into_iter()
.map(|e| Ok(NamedNode::new(e)?.into())) .map(|e| Ok(NamedNode::new(e)?.into()))
.collect::<Result<Vec<NamedOrBlankNode>, IriParseError>>() .collect::<Result<Vec<NamedOrBlankNode>, IriParseError>>()
{ .map_err(bad_request)?;
Ok(named_graph_uris) => named_graph_uris,
Err(e) => return bad_request(e),
};
for using in update.using_datasets_mut() { for using in update.using_datasets_mut() {
if !using.is_default_dataset() { if !using.is_default_dataset() {
return bad_request( return Err(bad_request(
"using-graph-uri and using-named-graph-uri must not be used with a SPARQL UPDATE containing USING", "using-graph-uri and using-named-graph-uri must not be used with a SPARQL UPDATE containing USING",
); ));
} }
using.set_default_graph(default_graph_uris.clone()); using.set_default_graph(default_graph_uris.clone());
using.set_available_named_graphs(named_graph_uris.clone()); using.set_available_named_graphs(named_graph_uris.clone());
} }
} }
if let Err(e) = store.update(update) { store.update(update).map_err(internal_server_error)?;
return internal_server_error(e); Ok(Response::builder(Status::NO_CONTENT).build())
}
Response::builder(Status::NO_CONTENT).build()
} }
fn store_target(request: &Request) -> Result<Option<NamedGraphName>, Response> { fn store_target(request: &Request) -> Result<Option<NamedGraphName>, HttpError> {
if request.url().path() == "/store" { if request.url().path() == "/store" {
let mut graph = None; let mut graph = None;
let mut default = false; let mut default = false;
@ -922,7 +827,7 @@ impl From<NamedGraphName> for GraphName {
} }
} }
fn graph_content_negotiation(request: &Request) -> Result<GraphFormat, Response> { fn graph_content_negotiation(request: &Request) -> Result<GraphFormat, HttpError> {
content_negotiation( content_negotiation(
request, request,
&[ &[
@ -934,7 +839,7 @@ fn graph_content_negotiation(request: &Request) -> Result<GraphFormat, Response>
) )
} }
fn dataset_content_negotiation(request: &Request) -> Result<DatasetFormat, Response> { fn dataset_content_negotiation(request: &Request) -> Result<DatasetFormat, HttpError> {
content_negotiation( content_negotiation(
request, request,
&[ &[
@ -945,7 +850,7 @@ fn dataset_content_negotiation(request: &Request) -> Result<DatasetFormat, Respo
) )
} }
fn query_results_content_negotiation(request: &Request) -> Result<QueryResultsFormat, Response> { fn query_results_content_negotiation(request: &Request) -> Result<QueryResultsFormat, HttpError> {
content_negotiation( content_negotiation(
request, request,
&[ &[
@ -962,7 +867,7 @@ fn content_negotiation<F>(
request: &Request, request: &Request,
supported: &[&str], supported: &[&str],
parse: impl Fn(&str) -> Option<F>, parse: impl Fn(&str) -> Option<F>,
) -> Result<F, Response> { ) -> Result<F, HttpError> {
let default = HeaderValue::default(); let default = HeaderValue::default();
let header = request let header = request
.header(&HeaderName::ACCEPT) .header(&HeaderName::ACCEPT)
@ -1015,13 +920,13 @@ fn content_negotiation<F>(
} }
let result = result.ok_or_else(|| { let result = result.ok_or_else(|| {
error( (
Status::NOT_ACCEPTABLE, Status::NOT_ACCEPTABLE,
format!("The available Content-Types are {}", supported.join(", "),), format!("The available Content-Types are {}", supported.join(", "),),
) )
})?; })?;
parse(result).ok_or_else(|| error(Status::INTERNAL_SERVER_ERROR, "Unknown media type")) parse(result).ok_or_else(|| internal_server_error("Unknown media type"))
} }
fn content_type(request: &Request) -> Option<String> { fn content_type(request: &Request) -> Option<String> {
@ -1042,20 +947,20 @@ fn error(status: Status, message: impl fmt::Display) -> Response {
.with_body(message.to_string()) .with_body(message.to_string())
} }
fn bad_request(message: impl fmt::Display) -> Response { fn bad_request(message: impl fmt::Display) -> HttpError {
error(Status::BAD_REQUEST, message) (Status::BAD_REQUEST, message.to_string())
} }
fn unsupported_media_type(content_type: &str) -> Response { fn unsupported_media_type(content_type: &str) -> HttpError {
error( (
Status::UNSUPPORTED_MEDIA_TYPE, Status::UNSUPPORTED_MEDIA_TYPE,
format!("No supported content Content-Type given: {}", content_type), format!("No supported content Content-Type given: {}", content_type),
) )
} }
fn internal_server_error(message: impl fmt::Display) -> Response { fn internal_server_error(message: impl fmt::Display) -> HttpError {
eprintln!("Internal server error: {}", message); eprintln!("Internal server error: {}", message);
error(Status::INTERNAL_SERVER_ERROR, message) (Status::INTERNAL_SERVER_ERROR, message.to_string())
} }
/// Hacky tool to allow implementing read on top of a write loop /// Hacky tool to allow implementing read on top of a write loop
@ -1071,22 +976,21 @@ impl<O: 'static, U: (Fn(O) -> io::Result<Option<O>>) + 'static> ReadForWrite<O,
initial_state_builder: impl FnOnce(ReadForWriteWriter) -> io::Result<O>, initial_state_builder: impl FnOnce(ReadForWriteWriter) -> io::Result<O>,
add_more_data: U, add_more_data: U,
content_type: &'static str, content_type: &'static str,
) -> Response { ) -> Result<Response, HttpError> {
let buffer = Rc::new(RefCell::new(Vec::new())); let buffer = Rc::new(RefCell::new(Vec::new()));
match initial_state_builder(ReadForWriteWriter { let state = initial_state_builder(ReadForWriteWriter {
buffer: buffer.clone(), buffer: buffer.clone(),
}) { })
Ok(state) => Response::builder(Status::OK) .map_err(internal_server_error)?;
.with_header(HeaderName::CONTENT_TYPE, content_type) Ok(Response::builder(Status::OK)
.unwrap() .with_header(HeaderName::CONTENT_TYPE, content_type)
.with_body(Body::from_read(Self { .unwrap()
buffer, .with_body(Body::from_read(Self {
position: 0, buffer,
add_more_data, position: 0,
state: Some(state), add_more_data,
})), state: Some(state),
Err(e) => internal_server_error(e), })))
}
} }
} }
@ -1798,6 +1702,7 @@ mod tests {
fn exec(&self, mut request: Request) -> Response { fn exec(&self, mut request: Request) -> Response {
handle_request(&mut request, self.store.clone()) handle_request(&mut request, self.store.clone())
.unwrap_or_else(|(status, message)| error(status, message))
} }
fn test_status(&self, request: Request, expected_status: Status) { fn test_status(&self, request: Request, expected_status: Status) {

Loading…
Cancel
Save