impl eq for content encoding

This commit is contained in:
Rob Ede 2021-12-09 15:36:10 +00:00
parent de20d21703
commit adf5fd82fe
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
8 changed files with 73 additions and 71 deletions

View File

@ -3,7 +3,9 @@
## Unreleased - 2021-xx-xx ## Unreleased - 2021-xx-xx
### Changes ### Changes
- `HeaderMap::get_all` now returns a `std::slice::Iter`. [#2527] - `HeaderMap::get_all` now returns a `std::slice::Iter`. [#2527]
- `impl Eq` for `header::ContentEncoding`. [#2501]
[#2501]: https://github.com/actix/actix-web/pull/2501
[#2527]: https://github.com/actix/actix-web/pull/2527 [#2527]: https://github.com/actix/actix-web/pull/2527

View File

@ -20,7 +20,7 @@ pub struct ContentEncodingParseError;
/// See [IANA HTTP Content Coding Registry]. /// See [IANA HTTP Content Coding Registry].
/// ///
/// [IANA HTTP Content Coding Registry]: https://www.iana.org/assignments/http-parameters/http-parameters.xhtml /// [IANA HTTP Content Coding Registry]: https://www.iana.org/assignments/http-parameters/http-parameters.xhtml
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive] #[non_exhaustive]
pub enum ContentEncoding { pub enum ContentEncoding {
/// Automatically select encoding based on encoding negotiation. /// Automatically select encoding based on encoding negotiation.

View File

@ -10,9 +10,7 @@ pub use crate::info::{ConnectionInfo, PeerAddr};
pub use crate::rmap::ResourceMap; pub use crate::rmap::ResourceMap;
pub use crate::service::{HttpServiceFactory, ServiceRequest, ServiceResponse, WebService}; pub use crate::service::{HttpServiceFactory, ServiceRequest, ServiceResponse, WebService};
pub use crate::types::form::UrlEncoded; pub use crate::types::{JsonBody, Readlines, UrlEncoded};
pub use crate::types::json::JsonBody;
pub use crate::types::readlines::Readlines;
pub use actix_http::{Extensions, Payload, PayloadStream, RequestHead, Response, ResponseHead}; pub use actix_http::{Extensions, Payload, PayloadStream, RequestHead, Response, ResponseHead};
pub use actix_router::{Path, ResourceDef, ResourcePath, Url}; pub use actix_router::{Path, ResourceDef, ResourcePath, Url};

View File

@ -147,6 +147,39 @@ impl Accept {
Accept(vec![QualityItem::max(mime::TEXT_HTML)]) Accept(vec![QualityItem::max(mime::TEXT_HTML)])
} }
// TODO: method for getting best content encoding based on q-factors, available from server side
// and if none are acceptable return None
/// Extracts the most preferable mime type, accounting for [q-factor weighting].
///
/// If no q-factors are provided, the first mime type is chosen. Note that items without
/// q-factors are given the maximum preference value.
///
/// As per the spec, will return [`mime::STAR_STAR`] (indicating no preference) if the contained
/// list is empty.
///
/// [q-factor weighting]: https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.2
pub fn preference(&self) -> Mime {
use actix_http::header::Quality;
let mut max_item = None;
let mut max_pref = Quality::MIN;
// uses manual max lookup loop since we want the first occurrence in the case of same
// preference but `Iterator::max_by_key` would give us the last occurrence
for pref in &self.0 {
// only change if strictly greater
// equal items, even while unsorted, still have higher preference if they appear first
if pref.quality > max_pref {
max_pref = pref.quality;
max_item = Some(pref.item.clone());
}
}
max_item.unwrap_or(mime::STAR_STAR)
}
/// Returns a sorted list of mime types from highest to lowest preference, accounting for /// Returns a sorted list of mime types from highest to lowest preference, accounting for
/// [q-factor weighting] and specificity. /// [q-factor weighting] and specificity.
/// ///
@ -196,36 +229,6 @@ impl Accept {
types.into_iter().map(|qitem| qitem.item).collect() types.into_iter().map(|qitem| qitem.item).collect()
} }
/// Extracts the most preferable mime type, accounting for [q-factor weighting].
///
/// If no q-factors are provided, the first mime type is chosen. Note that items without
/// q-factors are given the maximum preference value.
///
/// As per the spec, will return [`mime::STAR_STAR`] (indicating no preference) if the contained
/// list is empty.
///
/// [q-factor weighting]: https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.2
pub fn preference(&self) -> Mime {
use actix_http::header::Quality;
let mut max_item = None;
let mut max_pref = Quality::MIN;
// uses manual max lookup loop since we want the first occurrence in the case of same
// preference but `Iterator::max_by_key` would give us the last occurrence
for pref in &self.0 {
// only change if strictly greater
// equal items, even while unsorted, still have higher preference if they appear first
if pref.quality > max_pref {
max_pref = pref.quality;
max_item = Some(pref.item.clone());
}
}
max_item.unwrap_or(mime::STAR_STAR)
}
} }
#[cfg(test)] #[cfg(test)]
@ -239,7 +242,7 @@ mod tests {
assert!(test.ranked().is_empty()); assert!(test.ranked().is_empty());
let test = Accept(vec![QualityItem::max(mime::APPLICATION_JSON)]); let test = Accept(vec![QualityItem::max(mime::APPLICATION_JSON)]);
assert_eq!(test.ranked(), vec!(mime::APPLICATION_JSON)); assert_eq!(test.ranked(), vec![mime::APPLICATION_JSON]);
let test = Accept(vec![ let test = Accept(vec![
QualityItem::max(mime::TEXT_HTML), QualityItem::max(mime::TEXT_HTML),

View File

@ -1,8 +1,7 @@
use super::{Charset, QualityItem, ACCEPT_CHARSET}; use super::{common_header, Charset, QualityItem, ACCEPT_CHARSET};
crate::http::header::common_header! { common_header! {
/// `Accept-Charset` header, defined in /// `Accept-Charset` header, defined in [RFC 7231 §5.3.3].
/// [RFC 7231 §5.3.3](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.3)
/// ///
/// The `Accept-Charset` header field can be sent by a user agent to /// The `Accept-Charset` header field can be sent by a user agent to
/// indicate what charsets are acceptable in textual response content. /// indicate what charsets are acceptable in textual response content.
@ -52,10 +51,12 @@ crate::http::header::common_header! {
/// AcceptCharset(vec![QualityItem::max(Charset::Ext("utf-8".to_owned()))]) /// AcceptCharset(vec![QualityItem::max(Charset::Ext("utf-8".to_owned()))])
/// ); /// );
/// ``` /// ```
(AcceptCharset, ACCEPT_CHARSET) => (QualityItem<Charset>)+ ///
/// [RFC 7231 §5.3.3]: https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.3
(AcceptCharset, ACCEPT_CHARSET) => (QualityItem<Charset>)*
test_parse_and_format { test_parse_and_format {
// Test case from RFC // Test case from RFC
crate::http::header::common_header_test!(test1, vec![b"iso-8859-5, unicode-1-1;q=0.8"]); common_header_test!(test1, vec![b"iso-8859-5, unicode-1-1;q=0.8"]);
} }
} }

View File

@ -93,26 +93,6 @@ common_header! {
} }
impl AcceptLanguage { impl AcceptLanguage {
/// Returns a sorted list of languages from highest to lowest precedence, accounting
/// for [q-factor weighting].
///
/// [q-factor weighting]: https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.2
pub fn ranked(&self) -> Vec<Preference<LanguageTag>> {
if self.0.is_empty() {
return vec![];
}
let mut types = self.0.clone();
// use stable sort so items with equal q-factor retain listed order
types.sort_by(|a, b| {
// sort by q-factor descending
b.quality.cmp(&a.quality)
});
types.into_iter().map(|qitem| qitem.item).collect()
}
/// Extracts the most preferable language, accounting for [q-factor weighting]. /// Extracts the most preferable language, accounting for [q-factor weighting].
/// ///
/// If no q-factors are provided, the first language is chosen. Note that items without /// If no q-factors are provided, the first language is chosen. Note that items without
@ -139,6 +119,26 @@ impl AcceptLanguage {
max_item.unwrap_or(Preference::Any) max_item.unwrap_or(Preference::Any)
} }
/// Returns a sorted list of languages from highest to lowest precedence, accounting
/// for [q-factor weighting].
///
/// [q-factor weighting]: https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.2
pub fn ranked(&self) -> Vec<Preference<LanguageTag>> {
if self.0.is_empty() {
return vec![];
}
let mut types = self.0.clone();
// use stable sort so items with equal q-factor retain listed order
types.sort_by(|a, b| {
// sort by q-factor descending
b.quality.cmp(&a.quality)
});
types.into_iter().map(|qitem| qitem.item).collect()
}
} }
#[cfg(test)] #[cfg(test)]
@ -152,7 +152,7 @@ mod tests {
assert!(test.ranked().is_empty()); assert!(test.ranked().is_empty());
let test = AcceptLanguage(vec![QualityItem::max("fr-CH".parse().unwrap())]); let test = AcceptLanguage(vec![QualityItem::max("fr-CH".parse().unwrap())]);
assert_eq!(test.ranked(), vec!("fr-CH".parse().unwrap())); assert_eq!(test.ranked(), vec!["fr-CH".parse().unwrap()]);
let test = AcceptLanguage(vec![ let test = AcceptLanguage(vec![
QualityItem::new("fr".parse().unwrap(), q(0.900)), QualityItem::new("fr".parse().unwrap(), q(0.900)),

View File

@ -301,7 +301,6 @@ impl DispositionParam {
/// change to match local file system conventions if applicable, and do not use directory path /// change to match local file system conventions if applicable, and do not use directory path
/// information that may be present. /// information that may be present.
/// See [RFC 2183 §2.3](https://datatracker.ietf.org/doc/html/rfc2183#section-2.3). /// See [RFC 2183 §2.3](https://datatracker.ietf.org/doc/html/rfc2183#section-2.3).
// TODO: think about using private fields and smallvec
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ContentDisposition { pub struct ContentDisposition {
/// The disposition type /// The disposition type

View File

@ -1,19 +1,18 @@
//! Common extractors and responders. //! Common extractors and responders.
// TODO: review visibility
mod either; mod either;
pub(crate) mod form; mod form;
mod header; mod header;
pub(crate) mod json; mod json;
mod path; mod path;
pub(crate) mod payload; mod payload;
mod query; mod query;
pub(crate) mod readlines; mod readlines;
pub use self::either::{Either, EitherExtractError}; pub use self::either::Either;
pub use self::form::{Form, FormConfig}; pub use self::form::{Form, FormConfig, UrlEncoded};
pub use self::header::Header; pub use self::header::Header;
pub use self::json::{Json, JsonConfig}; pub use self::json::{Json, JsonBody, JsonConfig};
pub use self::path::{Path, PathConfig}; pub use self::path::{Path, PathConfig};
pub use self::payload::{Payload, PayloadConfig}; pub use self::payload::{Payload, PayloadConfig};
pub use self::query::{Query, QueryConfig}; pub use self::query::{Query, QueryConfig};