1
1
//! Client header advertising available compression algorithms.
2
2
3
- use crate :: content:: EncodingProposal ;
3
+ use crate :: content:: { ContentEncoding , Encoding , EncodingProposal } ;
4
4
use crate :: headers:: { HeaderName , HeaderValue , Headers , ToHeaderValues , ACCEPT_ENCODING } ;
5
5
use crate :: utils:: sort_by_weight;
6
+ use crate :: { Error , StatusCode } ;
6
7
7
8
use std:: fmt:: { self , Debug , Write } ;
8
9
use std:: option;
@@ -71,11 +72,43 @@ impl AcceptEncoding {
71
72
self . wildcard = wildcard
72
73
}
73
74
74
- /// Sort the entries in-place.
75
+ /// Sort the header directives by weight.
76
+ ///
77
+ /// Headers with a higher `q=` value will be returned first. If two
78
+ /// directives have the same weight, the directive that was declared later
79
+ /// will be returned first.
75
80
pub fn sort ( & mut self ) {
76
81
sort_by_weight ( & mut self . entries ) ;
77
82
}
78
83
84
+ /// Determine the most suitable `Content-Type` encoding.
85
+ ///
86
+ /// # Errors
87
+ ///
88
+ /// If no suitable encoding is found, an error with the status of `406` will be returned.
89
+ pub fn negotiate ( & mut self , encodings : & [ Encoding ] ) -> crate :: Result < ContentEncoding > {
90
+ // Start by ordering the encodings.
91
+ self . sort ( ) ;
92
+
93
+ // Try and find the first encoding that matches.
94
+ for encoding in & self . entries {
95
+ if encodings. contains ( & encoding) {
96
+ return Ok ( encoding. into ( ) ) ;
97
+ }
98
+ }
99
+
100
+ // If no encoding matches and wildcard is set, send whichever encoding we got.
101
+ if self . wildcard {
102
+ if let Some ( encoding) = encodings. iter ( ) . next ( ) {
103
+ return Ok ( encoding. into ( ) ) ;
104
+ }
105
+ }
106
+
107
+ let mut err = Error :: new_adhoc ( "No suitable ContentEncoding found" ) ;
108
+ err. set_status ( StatusCode :: NotAcceptable ) ;
109
+ Err ( err)
110
+ }
111
+
79
112
/// Insert a `HeaderName` + `HeaderValue` pair into a `Headers` instance.
80
113
pub fn apply ( & self , mut headers : impl AsMut < Headers > ) {
81
114
headers. as_mut ( ) . insert ( ACCEPT_ENCODING , self . value ( ) ) ;
@@ -294,7 +327,7 @@ mod test {
294
327
}
295
328
296
329
#[ test]
297
- fn reorder_iter_based_on_weight ( ) -> crate :: Result < ( ) > {
330
+ fn reorder_based_on_weight ( ) -> crate :: Result < ( ) > {
298
331
let mut accept = AcceptEncoding :: new ( ) ;
299
332
accept. push ( EncodingProposal :: new ( Encoding :: Gzip , Some ( 0.4 ) ) ?) ;
300
333
accept. push ( EncodingProposal :: new ( Encoding :: Identity , None ) ?) ;
@@ -311,4 +344,23 @@ mod test {
311
344
assert_eq ! ( accept. next( ) . unwrap( ) , Encoding :: Identity ) ;
312
345
Ok ( ( ) )
313
346
}
347
+
348
+ #[ test]
349
+ fn reorder_based_on_weight_and_location ( ) -> crate :: Result < ( ) > {
350
+ let mut accept = AcceptEncoding :: new ( ) ;
351
+ accept. push ( EncodingProposal :: new ( Encoding :: Identity , None ) ?) ;
352
+ accept. push ( EncodingProposal :: new ( Encoding :: Gzip , None ) ?) ;
353
+ accept. push ( EncodingProposal :: new ( Encoding :: Brotli , Some ( 0.8 ) ) ?) ;
354
+
355
+ let mut headers = Response :: new ( 200 ) ;
356
+ accept. apply ( & mut headers) ;
357
+
358
+ let mut accept = AcceptEncoding :: from_headers ( headers) ?. unwrap ( ) ;
359
+ accept. sort ( ) ;
360
+ let mut accept = accept. iter ( ) ;
361
+ assert_eq ! ( accept. next( ) . unwrap( ) , Encoding :: Brotli ) ;
362
+ assert_eq ! ( accept. next( ) . unwrap( ) , Encoding :: Gzip ) ;
363
+ assert_eq ! ( accept. next( ) . unwrap( ) , Encoding :: Identity ) ;
364
+ Ok ( ( ) )
365
+ }
314
366
}
0 commit comments