Compare commits

...

4 Commits

Author SHA1 Message Date
Yosh e0ae15c814
Merge pull request #389 from halvko/f-change-mime-negotiation
Change mime negotiation
2021-11-29 15:16:43 +01:00
Erik Funder Carstensen 752479208b Change reparse to cheap clone 2021-11-06 11:59:46 +01:00
Erik Funder Carstensen 42a4a080b0 Test new Accept negotiation behaviour 2021-11-06 00:56:44 +01:00
Erik Funder Carstensen 32d16b875d Change Accept Mime negotiation
Previously we just checked whether one of the available mime types
equaled one of the accepted mime types. This commit extends Mime with
subset functionality, describing exactly a mime being accepted by an
accept header.
2021-11-06 00:52:57 +01:00
2 changed files with 59 additions and 2 deletions

View File

@ -129,8 +129,8 @@ impl Accept {
// Try and find the first encoding that matches.
for accept in &self.entries {
if available.contains(accept) {
return Ok(accept.media_type.clone().into());
if let Some(accept) = available.iter().find(|m| m.subset_eq(accept.media_type())) {
return Ok(accept.clone().into());
}
}
@ -420,4 +420,22 @@ mod test {
assert_eq!(accept.negotiate(&[mime::XML])?, mime::XML);
Ok(())
}
#[test]
fn negotiate_missing_encoding() -> crate::Result<()> {
let mime_html = "text/html".parse::<Mime>()?;
let mut browser_accept = Accept::new();
browser_accept.push(MediaTypeProposal::new(mime_html, None)?);
let acceptable = &[mime::HTML];
let content_type = browser_accept.negotiate(acceptable);
assert!(
content_type.is_ok(),
"server is expected to return HTML content"
);
Ok(())
}
}

View File

@ -103,6 +103,45 @@ impl Mime {
.position(|(k, _)| k == &name)
.map(|pos| self.params.remove(pos).1)
}
/// Check if this mime is a subtype of another mime.
///
/// # Examples
///
/// ```
/// // All mime types are subsets of */*
/// use http_types::mime::Mime;
/// use std::str::FromStr;
///
/// assert!(Mime::from_str("text/css").unwrap().subset_eq(&Mime::from_str("*/*").unwrap()));
///
/// // A mime type is subset of itself
/// assert!(Mime::from_str("text/css").unwrap().subset_eq(&Mime::from_str("text/css").unwrap()));
///
/// // A mime type which is otherwise a subset with extra parameters is a subset of a mime type without those parameters
/// assert!(Mime::from_str("text/css;encoding=utf-8").unwrap().subset_eq(&Mime::from_str("text/css").unwrap()));
///
/// // A mime type more general than another mime type is not a subset
/// assert!(!Mime::from_str("*/css;encoding=utf-8").unwrap().subset_eq(&Mime::from_str("text/css").unwrap()));
/// ```
pub fn subset_eq(&self, other: &Mime) -> bool {
if other.basetype() != "*" && self.basetype() != other.basetype() {
return false;
}
if other.subtype() != "*" && self.subtype() != other.subtype() {
return false;
}
for (name, value) in other.params.iter() {
if !self
.param(name.clone())
.map(|v| v == value)
.unwrap_or(false)
{
return false;
}
}
true
}
}
impl Display for Mime {