|
|
@ -15,9 +15,10 @@ use async_std::io::Read; |
|
|
|
use async_std::net::{TcpListener, TcpStream}; |
|
|
|
use async_std::net::{TcpListener, TcpStream}; |
|
|
|
use async_std::prelude::*; |
|
|
|
use async_std::prelude::*; |
|
|
|
use async_std::task::{block_on, spawn}; |
|
|
|
use async_std::task::{block_on, spawn}; |
|
|
|
use http_types::content::{Accept, ContentType}; |
|
|
|
use http_types::content::ContentType; |
|
|
|
use http_types::{ |
|
|
|
use http_types::{ |
|
|
|
bail_status, headers, Error, Method, Mime, Request, Response, Result, StatusCode, |
|
|
|
bail_status, format_err_status, headers, Error, Method, Mime, Request, Response, Result, |
|
|
|
|
|
|
|
StatusCode, |
|
|
|
}; |
|
|
|
}; |
|
|
|
use oxigraph::io::{DatasetFormat, GraphFormat}; |
|
|
|
use oxigraph::io::{DatasetFormat, GraphFormat}; |
|
|
|
use oxigraph::model::{GraphName, GraphNameRef, NamedNode, NamedOrBlankNode}; |
|
|
|
use oxigraph::model::{GraphName, GraphNameRef, NamedNode, NamedOrBlankNode}; |
|
|
@ -618,20 +619,52 @@ fn content_negotiation<F>( |
|
|
|
supported: &[&str], |
|
|
|
supported: &[&str], |
|
|
|
parse: impl Fn(&str) -> Option<F>, |
|
|
|
parse: impl Fn(&str) -> Option<F>, |
|
|
|
) -> Result<F> { |
|
|
|
) -> Result<F> { |
|
|
|
if let Some(mut accept) = Accept::from_headers(request)? { |
|
|
|
let header = request |
|
|
|
let supported: Vec<Mime> = supported |
|
|
|
.header(headers::ACCEPT) |
|
|
|
|
|
|
|
.map(|h| h.last().as_str().trim()) |
|
|
|
|
|
|
|
.unwrap_or(""); |
|
|
|
|
|
|
|
let supported_mime: Vec<Mime> = supported |
|
|
|
.iter() |
|
|
|
.iter() |
|
|
|
.map(|h| Mime::from_str(h).unwrap()) |
|
|
|
.map(|h| Mime::from_str(h).unwrap()) |
|
|
|
.collect(); |
|
|
|
.collect(); |
|
|
|
parse(accept.negotiate(&supported)?.value().as_str()) |
|
|
|
|
|
|
|
|
|
|
|
if header.is_empty() { |
|
|
|
|
|
|
|
return parse(supported.first().unwrap()) |
|
|
|
|
|
|
|
.ok_or_else(|| Error::from_str(StatusCode::InternalServerError, "Unknown mime type")); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
let mut result = None; |
|
|
|
|
|
|
|
let mut result_score = 0f32; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for possible in header.split(',') { |
|
|
|
|
|
|
|
let possible = Mime::from_str(possible.trim())?; |
|
|
|
|
|
|
|
let score = if let Some(q) = possible.param("q") { |
|
|
|
|
|
|
|
f32::from_str(&q.to_string())? |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
parse(supported.first().ok_or_else(|| { |
|
|
|
1. |
|
|
|
Error::from_str( |
|
|
|
}; |
|
|
|
StatusCode::InternalServerError, |
|
|
|
if score <= result_score { |
|
|
|
"No default MIME type provided", |
|
|
|
continue; |
|
|
|
) |
|
|
|
} |
|
|
|
})?) |
|
|
|
for candidate in &supported_mime { |
|
|
|
|
|
|
|
if (possible.basetype() == candidate.basetype() || possible.basetype() == "*") |
|
|
|
|
|
|
|
&& (possible.subtype() == candidate.subtype() || possible.subtype() == "*") |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
result = Some(candidate); |
|
|
|
|
|
|
|
result_score = score; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let result = result.ok_or_else(|| { |
|
|
|
|
|
|
|
format_err_status!( |
|
|
|
|
|
|
|
406, |
|
|
|
|
|
|
|
"The available Content-Types are {}", |
|
|
|
|
|
|
|
supported.join(", ") |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
})?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parse(result.essence()) |
|
|
|
.ok_or_else(|| Error::from_str(StatusCode::InternalServerError, "Unknown mime type")) |
|
|
|
.ok_or_else(|| Error::from_str(StatusCode::InternalServerError, "Unknown mime type")) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -711,6 +744,39 @@ mod tests { |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
|
|
fn get_query_accept_star() { |
|
|
|
|
|
|
|
let mut request = Request::new( |
|
|
|
|
|
|
|
Method::Get, |
|
|
|
|
|
|
|
Url::parse("http://localhost/query?query=SELECT%20*%20WHERE%20{%20?s%20?p%20?o%20}") |
|
|
|
|
|
|
|
.unwrap(), |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
request.insert_header("Accept", "*/*"); |
|
|
|
|
|
|
|
ServerTest::new().test_status(request, StatusCode::Ok); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
|
|
fn get_query_accept_good() { |
|
|
|
|
|
|
|
let mut request = Request::new( |
|
|
|
|
|
|
|
Method::Get, |
|
|
|
|
|
|
|
Url::parse("http://localhost/query?query=SELECT%20*%20WHERE%20{%20?s%20?p%20?o%20}") |
|
|
|
|
|
|
|
.unwrap(), |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
request.insert_header("Accept", "application/sparql-results+json;charset=utf-8"); |
|
|
|
|
|
|
|
ServerTest::new().test_status(request, StatusCode::Ok); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
|
|
|
fn get_query_accept_bad() { |
|
|
|
|
|
|
|
let mut request = Request::new( |
|
|
|
|
|
|
|
Method::Get, |
|
|
|
|
|
|
|
Url::parse("http://localhost/query?query=SELECT%20*%20WHERE%20{%20?s%20?p%20?o%20}") |
|
|
|
|
|
|
|
.unwrap(), |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
request.insert_header("Accept", "application/foo"); |
|
|
|
|
|
|
|
ServerTest::new().test_status(request, StatusCode::NotAcceptable); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
#[test] |
|
|
|
fn get_bad_query() { |
|
|
|
fn get_bad_query() { |
|
|
|
ServerTest::new().test_status( |
|
|
|
ServerTest::new().test_status( |
|
|
|