mirror of https://github.com/fafhrd91/actix-web
impl eq for content encoding
This commit is contained in:
parent
de20d21703
commit
adf5fd82fe
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
/// 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
|
||||||
|
|
|
@ -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};
|
||||||
|
|
Loading…
Reference in New Issue