Skip to content

Commit 308a1af

Browse files
committed
AcceptEncoding: sort by weight
1 parent 30889c8 commit 308a1af

File tree

3 files changed

+24
-8
lines changed

3 files changed

+24
-8
lines changed

src/content/accept_encoding.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use crate::content::EncodingProposal;
44
use crate::headers::{HeaderName, HeaderValue, Headers, ToHeaderValues, ACCEPT_ENCODING};
5+
use crate::utils::sort_by_weight;
56

67
use std::fmt::{self, Debug, Write};
78
use std::option;
@@ -70,6 +71,11 @@ impl AcceptEncoding {
7071
self.wildcard = wildcard
7172
}
7273

74+
/// Sort the entries in-place.
75+
pub fn sort(&mut self) {
76+
sort_by_weight(&mut self.entries);
77+
}
78+
7379
/// Insert a `HeaderName` + `HeaderValue` pair into a `Headers` instance.
7480
pub fn apply(&self, mut headers: impl AsMut<Headers>) {
7581
headers.as_mut().insert(ACCEPT_ENCODING, self.value());
@@ -291,21 +297,18 @@ mod test {
291297
fn reorder_iter_based_on_weight() -> crate::Result<()> {
292298
let mut accept = AcceptEncoding::new();
293299
accept.push(EncodingProposal::new(Encoding::Gzip, Some(0.4))?);
300+
accept.push(EncodingProposal::new(Encoding::Identity, None)?);
294301
accept.push(EncodingProposal::new(Encoding::Brotli, Some(0.8))?);
295302

296303
let mut headers = Response::new(200);
297304
accept.apply(&mut headers);
298305

299-
let accept = AcceptEncoding::from_headers(headers)?.unwrap();
306+
let mut accept = AcceptEncoding::from_headers(headers)?.unwrap();
307+
accept.sort();
300308
let mut accept = accept.iter();
301309
assert_eq!(accept.next().unwrap(), Encoding::Brotli);
302310
assert_eq!(accept.next().unwrap(), Encoding::Gzip);
311+
assert_eq!(accept.next().unwrap(), Encoding::Identity);
303312
Ok(())
304313
}
305314
}
306-
307-
/// Order header proposals. In the case of two proposals of equal weight we pick
308-
/// the one that was declared last.
309-
fn sort_proposals<T: PartialOrd>(props: &mut Vec<T>) {
310-
props.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Less))
311-
}

src/content/encoding_proposal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::utils::parse_weight;
66
use std::cmp::{Ordering, PartialEq};
77

88
/// A proposed `Encoding` in `AcceptEncoding`.
9-
#[derive(Debug, Clone, PartialEq)]
9+
#[derive(Debug, Clone, Copy, PartialEq)]
1010
pub struct EncodingProposal {
1111
/// The proposed encoding.
1212
encoding: Encoding,

src/utils/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ pub(crate) use date::fmt_http_date;
44
pub(crate) use date::parse_http_date;
55

66
use crate::{Error, Status, StatusCode};
7+
8+
use std::cmp::Ordering;
79
use std::str::FromStr;
810

911
/// Declares unstable items.
@@ -38,3 +40,14 @@ pub(crate) fn parse_weight(s: &str) -> crate::Result<f32> {
3840
}
3941
}
4042
}
43+
44+
/// Order proposals by weight. Try ordering by q value first. If equal or undefined,
45+
/// order by index, favoring the latest provided value.
46+
pub(crate) fn sort_by_weight<T: PartialOrd + Copy>(props: &mut Vec<T>) {
47+
let mut arr: Vec<(usize, T)> = props.iter().map(|t| *t).enumerate().collect();
48+
arr.sort_unstable_by(|a, b| match b.1.partial_cmp(&a.1) {
49+
None | Some(Ordering::Equal) => b.0.cmp(&a.0),
50+
Some(ord @ _) => ord,
51+
});
52+
*props = arr.into_iter().map(|(_, t)| t).collect::<Vec<T>>();
53+
}

0 commit comments

Comments
 (0)