From 477d1cb930692d9864ab2a359aff5ec28d70dd0b Mon Sep 17 00:00:00 2001 From: Tpt Date: Fri, 9 Apr 2021 19:10:33 +0200 Subject: [PATCH] SPARQL HTTP graph store: do not normalizes URIs Bug: #92 --- server/Cargo.toml | 1 + server/src/main.rs | 72 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/server/Cargo.toml b/server/Cargo.toml index 23d0aea3..6a9900f1 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -24,6 +24,7 @@ http-types = "2" oxigraph = { version = "0.2", path="../lib", features = ["http_client"] } rand = "0.8" url = "2" +oxiri = "0.1" [dev-dependencies] tempfile = "3" diff --git a/server/src/main.rs b/server/src/main.rs index 4892c039..ef35ff51 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -28,10 +28,11 @@ use oxigraph::sparql::{Query, QueryResults, QueryResultsFormat, Update}; use oxigraph::RocksDbStore as Store; #[cfg(all(feature = "sled", not(feature = "rocksdb")))] use oxigraph::SledStore as Store; +use oxiri::Iri; use rand::random; use std::io::BufReader; use std::str::FromStr; -use url::{form_urlencoded, Url}; +use url::form_urlencoded; const MAX_SPARQL_BODY_SIZE: u64 = 1_048_576; const HTML_ROOT_PAGE: &str = include_str!("../templates/query.html"); @@ -292,11 +293,8 @@ async fn handle_request(request: Request, store: Store) -> Result { .map_err(bad_request)?; Response::new(StatusCode::NoContent) } else if let Some(format) = GraphFormat::from_media_type(content_type.essence()) { - let graph = NamedNode::new( - base_url(&request)? - .join(&format!("/store/{:x}", random::()))? - .into_string(), - )?; + let graph = + resolve_with_base(&request, &format!("/store/{:x}", random::()))?; store .load_graph( BufReader::new(SyncAsyncReader::from(request)), @@ -344,14 +342,24 @@ async fn handle_request(request: Request, store: Store) -> Result { }) } -fn base_url(request: &Request) -> Result { +fn base_url(request: &Request) -> Result { let mut url = request.url().clone(); if let Some(host) = request.host() { url.set_host(Some(host)).map_err(bad_request)?; } url.set_query(None); url.set_fragment(None); - Ok(url) + Ok(url.into_string()) +} + +fn resolve_with_base(request: &Request, url: &str) -> Result { + Ok(NamedNode::new_unchecked( + Iri::parse(base_url(request)?) + .map_err(bad_request)? + .resolve(url) + .map_err(bad_request)? + .into_inner(), + )) } fn url_query(request: &Request) -> Vec { @@ -525,16 +533,7 @@ fn store_target(request: &Request) -> Result> { "Both graph and default parameters should not be set at the same time", ); } else { - Some( - NamedNode::new( - base_url(request)? - .join(&graph) - .map_err(bad_request)? - .into_string(), - ) - .map_err(bad_request)? - .into(), - ) + Some(resolve_with_base(request, &graph)?.into()) } } else if default { Some(GraphName::DefaultGraph) @@ -542,9 +541,7 @@ fn store_target(request: &Request) -> Result> { None }) } else { - Ok(Some( - NamedNode::new(base_url(request)?.into_string())?.into(), - )) + Ok(Some(resolve_with_base(request, "")?.into())) } } @@ -697,6 +694,7 @@ mod tests { use super::*; use crate::handle_request; use async_std::task::block_on; + use http_types::Url; use tempfile::{tempdir, TempDir}; #[test] @@ -848,6 +846,38 @@ mod tests { ServerTest::new().test_status(request, StatusCode::BadRequest) } + #[test] + fn graph_store_url_normalization() { + let server = ServerTest::new(); + + // PUT + let mut request = Request::new( + Method::Put, + Url::parse("http://localhost/store?graph=http://example.com").unwrap(), + ); + request.insert_header("Content-Type", "text/turtle"); + request.set_body(" ."); + server.test_status(request, StatusCode::Created); + + // GET good URI + server.test_status( + Request::new( + Method::Get, + Url::parse("http://localhost/store?graph=http://example.com").unwrap(), + ), + StatusCode::Ok, + ); + + // GET bad URI + server.test_status( + Request::new( + Method::Get, + Url::parse("http://localhost/store?graph=http://example.com/").unwrap(), + ), + StatusCode::NotFound, + ); + } + #[test] fn graph_store_protocol() { // Tests from https://www.w3.org/2009/sparql/docs/tests/data-sparql11/http-rdf-update/