1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-07-01 00:44:26 +02:00

Quality / QualityItem improvements (#2486)

This commit is contained in:
Rob Ede
2021-12-05 03:38:08 +00:00
committed by GitHub
parent d89c706cd6
commit e1a2d9c606
16 changed files with 494 additions and 257 deletions

View File

@ -2,7 +2,7 @@ use std::cmp::Ordering;
use mime::Mime;
use super::{qitem, QualityItem};
use super::QualityItem;
use crate::http::header;
crate::http::header::common_header! {
@ -34,46 +34,40 @@ crate::http::header::common_header! {
/// # Examples
/// ```
/// use actix_web::HttpResponse;
/// use actix_web::http::header::{Accept, qitem};
/// use actix_web::http::header::{Accept, QualityItem};
///
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// Accept(vec![
/// qitem(mime::TEXT_HTML),
/// QualityItem::max(mime::TEXT_HTML),
/// ])
/// );
/// ```
///
/// ```
/// use actix_web::HttpResponse;
/// use actix_web::http::header::{Accept, qitem};
/// use actix_web::http::header::{Accept, QualityItem};
///
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// Accept(vec![
/// qitem(mime::APPLICATION_JSON),
/// QualityItem::max(mime::APPLICATION_JSON),
/// ])
/// );
/// ```
///
/// ```
/// use actix_web::HttpResponse;
/// use actix_web::http::header::{Accept, QualityItem, q, qitem};
/// use actix_web::http::header::{Accept, QualityItem, q};
///
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// Accept(vec![
/// qitem(mime::TEXT_HTML),
/// qitem("application/xhtml+xml".parse().unwrap()),
/// QualityItem::new(
/// mime::TEXT_XML,
/// q(900)
/// ),
/// qitem("image/webp".parse().unwrap()),
/// QualityItem::new(
/// mime::STAR_STAR,
/// q(800)
/// ),
/// QualityItem::max(mime::TEXT_HTML),
/// QualityItem::max("application/xhtml+xml".parse().unwrap()),
/// QualityItem::new(mime::TEXT_XML, q(0.9)),
/// QualityItem::max("image/webp".parse().unwrap()),
/// QualityItem::new(mime::STAR_STAR, q(0.8)),
/// ])
/// );
/// ```
@ -85,20 +79,20 @@ crate::http::header::common_header! {
test1,
vec![b"audio/*; q=0.2, audio/basic"],
Some(Accept(vec![
QualityItem::new("audio/*".parse().unwrap(), q(200)),
qitem("audio/basic".parse().unwrap()),
QualityItem::new("audio/*".parse().unwrap(), q(0.2)),
QualityItem::max("audio/basic".parse().unwrap()),
])));
crate::http::header::common_header_test!(
test2,
vec![b"text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"],
Some(Accept(vec![
QualityItem::new(mime::TEXT_PLAIN, q(500)),
qitem(mime::TEXT_HTML),
QualityItem::new(mime::TEXT_PLAIN, q(0.5)),
QualityItem::max(mime::TEXT_HTML),
QualityItem::new(
"text/x-dvi".parse().unwrap(),
q(800)),
qitem("text/x-c".parse().unwrap()),
q(0.8)),
QualityItem::max("text/x-c".parse().unwrap()),
])));
// Custom tests
@ -106,14 +100,14 @@ crate::http::header::common_header! {
test3,
vec![b"text/plain; charset=utf-8"],
Some(Accept(vec![
qitem(mime::TEXT_PLAIN_UTF_8),
QualityItem::max(mime::TEXT_PLAIN_UTF_8),
])));
crate::http::header::common_header_test!(
test4,
vec![b"text/plain; charset=utf-8; q=0.5"],
Some(Accept(vec![
QualityItem::new(mime::TEXT_PLAIN_UTF_8,
q(500)),
q(0.5)),
])));
#[test]
@ -130,27 +124,27 @@ crate::http::header::common_header! {
impl Accept {
/// Construct `Accept: */*`.
pub fn star() -> Accept {
Accept(vec![qitem(mime::STAR_STAR)])
Accept(vec![QualityItem::max(mime::STAR_STAR)])
}
/// Construct `Accept: application/json`.
pub fn json() -> Accept {
Accept(vec![qitem(mime::APPLICATION_JSON)])
Accept(vec![QualityItem::max(mime::APPLICATION_JSON)])
}
/// Construct `Accept: text/*`.
pub fn text() -> Accept {
Accept(vec![qitem(mime::TEXT_STAR)])
Accept(vec![QualityItem::max(mime::TEXT_STAR)])
}
/// Construct `Accept: image/*`.
pub fn image() -> Accept {
Accept(vec![qitem(mime::IMAGE_STAR)])
Accept(vec![QualityItem::max(mime::IMAGE_STAR)])
}
/// Construct `Accept: text/html`.
pub fn html() -> Accept {
Accept(vec![qitem(mime::TEXT_HTML)])
Accept(vec![QualityItem::max(mime::TEXT_HTML)])
}
/// Returns a sorted list of mime types from highest to lowest preference, accounting for
@ -213,10 +207,10 @@ impl Accept {
///
/// [q-factor weighting]: https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.2
pub fn preference(&self) -> Mime {
use actix_http::header::q;
use actix_http::header::Quality;
let mut max_item = None;
let mut max_pref = q(0);
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
@ -244,11 +238,11 @@ mod tests {
let test = Accept(vec![]);
assert!(test.ranked().is_empty());
let test = Accept(vec![qitem(mime::APPLICATION_JSON)]);
let test = Accept(vec![QualityItem::max(mime::APPLICATION_JSON)]);
assert_eq!(test.ranked(), vec!(mime::APPLICATION_JSON));
let test = Accept(vec![
qitem(mime::TEXT_HTML),
QualityItem::max(mime::TEXT_HTML),
"application/xhtml+xml".parse().unwrap(),
QualityItem::new("application/xml".parse().unwrap(), q(0.9)),
QualityItem::new(mime::STAR_STAR, q(0.8)),
@ -264,9 +258,9 @@ mod tests {
);
let test = Accept(vec![
qitem(mime::STAR_STAR),
qitem(mime::IMAGE_STAR),
qitem(mime::IMAGE_PNG),
QualityItem::max(mime::STAR_STAR),
QualityItem::max(mime::IMAGE_STAR),
QualityItem::max(mime::IMAGE_PNG),
]);
assert_eq!(
test.ranked(),
@ -277,7 +271,7 @@ mod tests {
#[test]
fn preference_selection() {
let test = Accept(vec![
qitem(mime::TEXT_HTML),
QualityItem::max(mime::TEXT_HTML),
"application/xhtml+xml".parse().unwrap(),
QualityItem::new("application/xml".parse().unwrap(), q(0.9)),
QualityItem::new(mime::STAR_STAR, q(0.8)),
@ -286,9 +280,9 @@ mod tests {
let test = Accept(vec![
QualityItem::new("video/*".parse().unwrap(), q(0.8)),
qitem(mime::IMAGE_PNG),
QualityItem::max(mime::IMAGE_PNG),
QualityItem::new(mime::STAR_STAR, q(0.5)),
qitem(mime::IMAGE_SVG),
QualityItem::max(mime::IMAGE_SVG),
QualityItem::new(mime::IMAGE_STAR, q(0.8)),
]);
assert_eq!(test.preference(), mime::IMAGE_PNG);

View File

@ -22,11 +22,11 @@ crate::http::header::common_header! {
/// # Examples
/// ```
/// use actix_web::HttpResponse;
/// use actix_web::http::header::{AcceptCharset, Charset, qitem};
/// use actix_web::http::header::{AcceptCharset, Charset, QualityItem};
///
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// AcceptCharset(vec![qitem(Charset::Us_Ascii)])
/// AcceptCharset(vec![QualityItem::max(Charset::Us_Ascii)])
/// );
/// ```
///
@ -37,19 +37,19 @@ crate::http::header::common_header! {
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// AcceptCharset(vec![
/// QualityItem::new(Charset::Us_Ascii, q(900)),
/// QualityItem::new(Charset::Iso_8859_10, q(200)),
/// QualityItem::new(Charset::Us_Ascii, q(0.9)),
/// QualityItem::new(Charset::Iso_8859_10, q(0.2)),
/// ])
/// );
/// ```
///
/// ```
/// use actix_web::HttpResponse;
/// use actix_web::http::header::{AcceptCharset, Charset, qitem};
/// use actix_web::http::header::{AcceptCharset, Charset, QualityItem};
///
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// AcceptCharset(vec![qitem(Charset::Ext("utf-8".to_owned()))])
/// AcceptCharset(vec![QualityItem::max(Charset::Ext("utf-8".to_owned()))])
/// );
/// ```
(AcceptCharset, ACCEPT_CHARSET) => (QualityItem<Charset>)+

View File

@ -29,36 +29,38 @@ common_header! {
/// # Examples
/// ```
/// use actix_web::HttpResponse;
/// use actix_web::http::header::{AcceptEncoding, Encoding, qitem};
/// use actix_web::http::header::{AcceptEncoding, Encoding, QualityItem};
///
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// AcceptEncoding(vec![qitem(Encoding::Chunked)])
/// AcceptEncoding(vec![QualityItem::max(Encoding::Chunked)])
/// );
/// ```
///
/// ```
/// use actix_web::HttpResponse;
/// use actix_web::http::header::{AcceptEncoding, Encoding, qitem};
/// use actix_web::http::header::{AcceptEncoding, Encoding, QualityItem};
///
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// AcceptEncoding(vec![
/// qitem(Encoding::Chunked),
/// qitem(Encoding::Gzip),
/// qitem(Encoding::Deflate),
/// QualityItem::max(Encoding::Chunked),
/// QualityItem::max(Encoding::Gzip),
/// QualityItem::max(Encoding::Deflate),
/// ])
/// );
/// ```
///
/// ```
/// use actix_web::HttpResponse;
/// use actix_web::http::header::{AcceptEncoding, Encoding, QualityItem, q, qitem};
/// use actix_web::http::header::{AcceptEncoding, Encoding, QualityItem, q};
///
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// AcceptEncoding(vec![
/// qitem(Encoding::Chunked),
/// QualityItem::new(Encoding::Gzip, q(600)),
/// QualityItem::new(Encoding::EncodingExt("*".to_owned()), q(0)),
/// QualityItem::max(Encoding::Chunked),
/// QualityItem::new(Encoding::Gzip, q(0.60)),
/// QualityItem::min(Encoding::EncodingExt("*".to_owned())),
/// ])
/// );
/// ```
@ -77,3 +79,5 @@ common_header! {
common_header_test!(test5, vec![b"gzip, identity; q=0.5, *;q=0"]);
}
}
// TODO: shortcut for EncodingExt(*) = Any

View File

@ -1,6 +1,6 @@
use language_tags::LanguageTag;
use super::{common_header, Preference, QualityItem};
use super::{common_header, Preference, Quality, QualityItem};
use crate::http::header;
common_header! {
@ -32,26 +32,26 @@ common_header! {
/// # Examples
/// ```
/// use actix_web::HttpResponse;
/// use actix_web::http::header::{AcceptLanguage, qitem};
/// use actix_web::http::header::{AcceptLanguage, QualityItem};
///
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// AcceptLanguage(vec![
/// qitem("en-US".parse().unwrap())
/// QualityItem::max("en-US".parse().unwrap())
/// ])
/// );
/// ```
///
/// ```
/// use actix_web::HttpResponse;
/// use actix_web::http::header::{AcceptLanguage, QualityItem, q, qitem};
/// use actix_web::http::header::{AcceptLanguage, QualityItem, q};
///
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// AcceptLanguage(vec![
/// qitem("da".parse().unwrap()),
/// QualityItem::new("en-GB".parse().unwrap(), q(800)),
/// QualityItem::new("en".parse().unwrap(), q(700)),
/// QualityItem::max("da".parse().unwrap()),
/// QualityItem::new("en-GB".parse().unwrap(), q(0.8)),
/// QualityItem::new("en".parse().unwrap(), q(0.7)),
/// ])
/// );
/// ```
@ -72,9 +72,9 @@ common_header! {
not_ordered_by_weight,
vec![b"en-US, en; q=0.5, fr"],
Some(AcceptLanguage(vec![
qitem("en-US".parse().unwrap()),
QualityItem::new("en".parse().unwrap(), q(500)),
qitem("fr".parse().unwrap()),
QualityItem::max("en-US".parse().unwrap()),
QualityItem::new("en".parse().unwrap(), q(0.5)),
QualityItem::max("fr".parse().unwrap()),
]))
);
@ -82,11 +82,11 @@ common_header! {
has_wildcard,
vec![b"fr-CH, fr; q=0.9, en; q=0.8, de; q=0.7, *; q=0.5"],
Some(AcceptLanguage(vec![
qitem("fr-CH".parse().unwrap()),
QualityItem::new("fr".parse().unwrap(), q(900)),
QualityItem::new("en".parse().unwrap(), q(800)),
QualityItem::new("de".parse().unwrap(), q(700)),
QualityItem::new("*".parse().unwrap(), q(500)),
QualityItem::max("fr-CH".parse().unwrap()),
QualityItem::new("fr".parse().unwrap(), q(0.9)),
QualityItem::new("en".parse().unwrap(), q(0.8)),
QualityItem::new("de".parse().unwrap(), q(0.7)),
QualityItem::new("*".parse().unwrap(), q(0.5)),
]))
);
}
@ -122,10 +122,8 @@ impl AcceptLanguage {
///
/// [q-factor weighting]: https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.2
pub fn preference(&self) -> Preference<LanguageTag> {
use actix_http::header::q;
let mut max_item = None;
let mut max_pref = q(0);
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
@ -153,15 +151,15 @@ mod tests {
let test = AcceptLanguage(vec![]);
assert!(test.ranked().is_empty());
let test = AcceptLanguage(vec![qitem("fr-CH".parse().unwrap())]);
let test = AcceptLanguage(vec![QualityItem::max("fr-CH".parse().unwrap())]);
assert_eq!(test.ranked(), vec!("fr-CH".parse().unwrap()));
let test = AcceptLanguage(vec![
QualityItem::new("fr".parse().unwrap(), q(900)),
QualityItem::new("fr-CH".parse().unwrap(), q(1000)),
QualityItem::new("en".parse().unwrap(), q(800)),
QualityItem::new("*".parse().unwrap(), q(500)),
QualityItem::new("de".parse().unwrap(), q(700)),
QualityItem::new("fr".parse().unwrap(), q(0.900)),
QualityItem::new("fr-CH".parse().unwrap(), q(1.0)),
QualityItem::new("en".parse().unwrap(), q(0.800)),
QualityItem::new("*".parse().unwrap(), q(0.500)),
QualityItem::new("de".parse().unwrap(), q(0.700)),
]);
assert_eq!(
test.ranked(),
@ -175,11 +173,11 @@ mod tests {
);
let test = AcceptLanguage(vec![
qitem("fr".parse().unwrap()),
qitem("fr-CH".parse().unwrap()),
qitem("en".parse().unwrap()),
qitem("*".parse().unwrap()),
qitem("de".parse().unwrap()),
QualityItem::max("fr".parse().unwrap()),
QualityItem::max("fr-CH".parse().unwrap()),
QualityItem::max("en".parse().unwrap()),
QualityItem::max("*".parse().unwrap()),
QualityItem::max("de".parse().unwrap()),
]);
assert_eq!(
test.ranked(),
@ -196,11 +194,11 @@ mod tests {
#[test]
fn preference_selection() {
let test = AcceptLanguage(vec![
QualityItem::new("fr".parse().unwrap(), q(900)),
QualityItem::new("fr-CH".parse().unwrap(), q(1000)),
QualityItem::new("en".parse().unwrap(), q(800)),
QualityItem::new("*".parse().unwrap(), q(500)),
QualityItem::new("de".parse().unwrap(), q(700)),
QualityItem::new("fr".parse().unwrap(), q(0.900)),
QualityItem::new("fr-CH".parse().unwrap(), q(1.0)),
QualityItem::new("en".parse().unwrap(), q(0.800)),
QualityItem::new("*".parse().unwrap(), q(0.500)),
QualityItem::new("de".parse().unwrap(), q(0.700)),
]);
assert_eq!(
test.preference(),
@ -208,11 +206,11 @@ mod tests {
);
let test = AcceptLanguage(vec![
qitem("fr".parse().unwrap()),
qitem("fr-CH".parse().unwrap()),
qitem("en".parse().unwrap()),
qitem("*".parse().unwrap()),
qitem("de".parse().unwrap()),
QualityItem::max("fr".parse().unwrap()),
QualityItem::max("fr-CH".parse().unwrap()),
QualityItem::max("en".parse().unwrap()),
QualityItem::max("*".parse().unwrap()),
QualityItem::max("de".parse().unwrap()),
]);
assert_eq!(
test.preference(),

View File

@ -23,25 +23,25 @@ common_header! {
/// # Examples
/// ```
/// use actix_web::HttpResponse;
/// use actix_web::http::header::{ContentLanguage, LanguageTag, qitem};
/// use actix_web::http::header::{ContentLanguage, LanguageTag, QualityItem};
///
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// ContentLanguage(vec![
/// qitem(LanguageTag::parse("en").unwrap()),
/// QualityItem::max(LanguageTag::parse("en").unwrap()),
/// ])
/// );
/// ```
///
/// ```
/// use actix_web::HttpResponse;
/// use actix_web::http::header::{ContentLanguage, LanguageTag, qitem};
/// use actix_web::http::header::{ContentLanguage, LanguageTag, QualityItem};
///
/// let mut builder = HttpResponse::Ok();
/// builder.insert_header(
/// ContentLanguage(vec![
/// qitem(LanguageTag::parse("da").unwrap()),
/// qitem(LanguageTag::parse("en-GB").unwrap()),
/// QualityItem::max(LanguageTag::parse("da").unwrap()),
/// QualityItem::max(LanguageTag::parse("en-GB").unwrap()),
/// ])
/// );
/// ```