Gracefully handle HTTP 405 errors
This commit is contained in:
@@ -26,4 +26,7 @@ pub enum Error {
|
||||
/// The RDF data failed to parse.
|
||||
#[error(transparent)]
|
||||
InvalidRdfSyntax(#[from] oxigraph::io::RdfSyntaxError),
|
||||
|
||||
#[error(transparent)]
|
||||
ToStr(#[from] http::header::ToStrError),
|
||||
}
|
||||
|
||||
+50
-3
@@ -2,6 +2,7 @@ use crate::rdf_source::RdfSource;
|
||||
use crate::vocab;
|
||||
use bytes::Bytes;
|
||||
use futures::Stream;
|
||||
use http::Method;
|
||||
use oxigraph::io::{RdfFormat, RdfParser};
|
||||
use oxigraph::model::{GraphNameRef, NamedNodeRef, Quad};
|
||||
use reqwest_middleware::reqwest::{Client, Response, StatusCode, Url, header};
|
||||
@@ -34,6 +35,7 @@ pub struct ResourceRequestBuilder {
|
||||
client: ClientWithMiddleware,
|
||||
url: Url,
|
||||
follow_described_by: bool,
|
||||
validate_support: bool,
|
||||
formats: Vec<RdfFormat>,
|
||||
}
|
||||
|
||||
@@ -52,17 +54,30 @@ impl ResourceRequestBuilder {
|
||||
client,
|
||||
url,
|
||||
follow_described_by: true,
|
||||
validate_support: true,
|
||||
formats: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// If the HTTP response includes a [describedby](https://www.w3.org/TR/ldp/#link-relation-describedby) link rel, then it will be followed.
|
||||
///
|
||||
/// Default value: `true`.
|
||||
#[must_use]
|
||||
pub fn follow_described_by(mut self, value: bool) -> Self {
|
||||
self.follow_described_by = value;
|
||||
self
|
||||
}
|
||||
|
||||
/// Require the presence of a `Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"` response header.
|
||||
/// This is described in [section 4.2.1.4](https://www.w3.org/TR/ldp/#ldpr-resource) of the spec.
|
||||
///
|
||||
/// Default value: `true`.
|
||||
#[must_use]
|
||||
pub fn validate_support(mut self, value: bool) -> Self {
|
||||
self.validate_support = value;
|
||||
self
|
||||
}
|
||||
|
||||
/// Restrict the request to the given RDF format.
|
||||
///
|
||||
/// Repeated calls are additive. By default, all formats — even non-RDF formats — are accepted.
|
||||
@@ -150,19 +165,48 @@ impl ResourceRequest {
|
||||
request_builder
|
||||
}
|
||||
|
||||
fn is_method_allowed(response: &Response, method: Method) -> crate::Result<bool> {
|
||||
for header in response.headers().get_all(header::ALLOW) {
|
||||
for value in header.to_str()?.replace(" ", "").split(',') {
|
||||
if value == method {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Send the request.
|
||||
///
|
||||
/// There are two stages to this process. First, a HEAD request is made to determine whether
|
||||
/// There are two stages to this process. First, a `HEAD` request is made to determine whether
|
||||
/// the requested resource is described by an RDF graph at another location. If it is, and if
|
||||
/// the user permits it, then the URL in the
|
||||
/// [describedby](https://www.w3.org/TR/ldp/#link-relation-describedby) header is used.
|
||||
/// Otherwise, the original URL is used.
|
||||
///
|
||||
/// During the second stage, a GET request is made. No parsing occurs at this time.
|
||||
/// During the second stage, a `GET` request is made. No parsing occurs at this time.
|
||||
///
|
||||
/// If the `HEAD` method is not allowed on this URI (a violation of the LDP spec), the `Allow`
|
||||
/// header is inspected for `GET`. If absent, this method will return an error.
|
||||
pub async fn send(&self) -> crate::Result<Resource> {
|
||||
let request_builder = self.builder.client.head(self.builder.url.clone());
|
||||
let mut response = request_builder.send().await?.error_for_status()?;
|
||||
let mut response = request_builder.send().await?;
|
||||
|
||||
match response.error_for_status_ref() {
|
||||
Ok(response) => {
|
||||
if self.builder.validate_support {
|
||||
Self::ensure_ldp_support(&response)?;
|
||||
}
|
||||
}
|
||||
Err(err) if err.status() == Some(StatusCode::METHOD_NOT_ALLOWED) => {
|
||||
if !Self::is_method_allowed(&response, Method::GET)? {
|
||||
return Err(err.into());
|
||||
}
|
||||
}
|
||||
err => {
|
||||
err?;
|
||||
}
|
||||
}
|
||||
|
||||
let url_to_get;
|
||||
let described_by = Self::extract_described_by(&response);
|
||||
@@ -178,7 +222,10 @@ impl ResourceRequest {
|
||||
request_builder = self.add_media_types(request_builder);
|
||||
|
||||
response = request_builder.send().await?.error_for_status()?;
|
||||
|
||||
if self.builder.validate_support {
|
||||
Self::ensure_ldp_support(&response)?;
|
||||
}
|
||||
|
||||
let state_token = response
|
||||
.headers()
|
||||
|
||||
Reference in New Issue
Block a user