1515//!
1616//! [W3C Baggage]: https://w3c.github.io/baggage
1717use crate :: { Context , Key , KeyValue , StringValue } ;
18+ use std:: collections:: hash_map:: Entry ;
1819use std:: collections:: { hash_map, HashMap } ;
1920use std:: fmt;
2021use std:: sync:: OnceLock ;
2122
2223static DEFAULT_BAGGAGE : OnceLock < Baggage > = OnceLock :: new ( ) ;
2324
24- const MAX_KEY_VALUE_PAIRS : usize = 180 ;
25- const MAX_BYTES_FOR_ONE_PAIR : usize = 4096 ;
25+ const MAX_KEY_VALUE_PAIRS : usize = 64 ;
2626const MAX_LEN_OF_ALL_PAIRS : usize = 8192 ;
2727
2828/// Returns the default baggage, ensuring it is initialized only once.
@@ -49,11 +49,10 @@ fn get_default_baggage() -> &'static Baggage {
4949///
5050/// ### Limits
5151///
52- /// * Maximum number of name/value pairs: `180`.
53- /// * Maximum number of bytes per a single name/value pair: `4096`.
52+ /// * Maximum number of name/value pairs: `64`.
5453/// * Maximum total length of all name/value pairs: `8192`.
5554///
56- /// [RFC2616, Section 2.2]: https://tools.ietf .org/html/rfc2616#section-2.2
55+ /// < https://www.w3 .org/TR/baggage/#limits>
5756#[ derive( Debug , Default ) ]
5857pub struct Baggage {
5958 inner : HashMap < Key , ( StringValue , BaggageMetadata ) > ,
@@ -133,6 +132,8 @@ impl Baggage {
133132 /// Same with `insert`, if the name was not present, [`None`] will be returned.
134133 /// If the name is present, the old value and metadata will be returned.
135134 ///
135+ /// Also checks for [limits](https://w3c.github.io/baggage/#limits).
136+ ///
136137 /// # Examples
137138 ///
138139 /// ```
@@ -155,10 +156,38 @@ impl Baggage {
155156 S : Into < BaggageMetadata > ,
156157 {
157158 let ( key, value, metadata) = ( key. into ( ) , value. into ( ) , metadata. into ( ) ) ;
158- if self . insertable ( & key, & value, & metadata) {
159- self . inner . insert ( key, ( value, metadata) )
160- } else {
161- None
159+ if !key. as_str ( ) . is_ascii ( ) {
160+ return None ;
161+ }
162+ let entry_content_len =
163+ key_value_metadata_bytes_size ( key. as_str ( ) , value. as_str ( ) , metadata. as_str ( ) ) ;
164+ let entries_count = self . inner . len ( ) ;
165+ match self . inner . entry ( key) {
166+ Entry :: Occupied ( mut occupied_entry) => {
167+ let prev_content_len = key_value_metadata_bytes_size (
168+ occupied_entry. key ( ) . as_str ( ) ,
169+ occupied_entry. get ( ) . 0 . as_str ( ) ,
170+ occupied_entry. get ( ) . 1 . as_str ( ) ,
171+ ) ;
172+ let new_content_len = self . kv_content_len + entry_content_len - prev_content_len;
173+ if new_content_len > MAX_LEN_OF_ALL_PAIRS {
174+ return None ;
175+ }
176+ self . kv_content_len = new_content_len;
177+ Some ( occupied_entry. insert ( ( value, metadata) ) )
178+ }
179+ Entry :: Vacant ( vacant_entry) => {
180+ if entries_count == MAX_KEY_VALUE_PAIRS {
181+ return None ;
182+ }
183+ let new_content_len = self . kv_content_len + entry_content_len;
184+ if new_content_len > MAX_LEN_OF_ALL_PAIRS {
185+ return None ;
186+ }
187+ self . kv_content_len = new_content_len;
188+ vacant_entry. insert ( ( value, metadata) ) ;
189+ None
190+ }
162191 }
163192 }
164193
@@ -178,59 +207,10 @@ impl Baggage {
178207 self . inner . is_empty ( )
179208 }
180209
181- /// Gets an iterator over the baggage items, sorted by name .
210+ /// Gets an iterator over the baggage items, in any order .
182211 pub fn iter ( & self ) -> Iter < ' _ > {
183212 self . into_iter ( )
184213 }
185-
186- /// Determine whether the key value pair exceed one of the [limits](https://w3c.github.io/baggage/#limits).
187- /// If not, update the total length of key values
188- fn insertable ( & mut self , key : & Key , value : & StringValue , metadata : & BaggageMetadata ) -> bool {
189- if !key. as_str ( ) . is_ascii ( ) {
190- return false ;
191- }
192- let value = value. as_str ( ) ;
193- if key_value_metadata_bytes_size ( key. as_str ( ) , value, metadata. as_str ( ) )
194- < MAX_BYTES_FOR_ONE_PAIR
195- {
196- match self . inner . get ( key) {
197- None => {
198- // check total length
199- if self . kv_content_len
200- + metadata. as_str ( ) . len ( )
201- + value. len ( )
202- + key. as_str ( ) . len ( )
203- > MAX_LEN_OF_ALL_PAIRS
204- {
205- return false ;
206- }
207- // check number of pairs
208- if self . inner . len ( ) + 1 > MAX_KEY_VALUE_PAIRS {
209- return false ;
210- }
211- self . kv_content_len +=
212- metadata. as_str ( ) . len ( ) + value. len ( ) + key. as_str ( ) . len ( )
213- }
214- Some ( ( old_value, old_metadata) ) => {
215- let old_value = old_value. as_str ( ) ;
216- if self . kv_content_len - old_metadata. as_str ( ) . len ( ) - old_value. len ( )
217- + metadata. as_str ( ) . len ( )
218- + value. len ( )
219- > MAX_LEN_OF_ALL_PAIRS
220- {
221- return false ;
222- }
223- self . kv_content_len =
224- self . kv_content_len - old_metadata. as_str ( ) . len ( ) - old_value. len ( )
225- + metadata. as_str ( ) . len ( )
226- + value. len ( )
227- }
228- }
229- true
230- } else {
231- false
232- }
233- }
234214}
235215
236216/// Get the number of bytes for one key-value pair
@@ -385,13 +365,11 @@ impl BaggageExt for Context {
385365 & self ,
386366 baggage : T ,
387367 ) -> Self {
388- let mut merged: Baggage = self
389- . baggage ( )
390- . iter ( )
391- . map ( |( key, ( value, metadata) ) | {
392- KeyValueMetadata :: new ( key. clone ( ) , value. clone ( ) , metadata. clone ( ) )
393- } )
394- . collect ( ) ;
368+ let old = self . baggage ( ) ;
369+ let mut merged = Baggage {
370+ inner : old. inner . clone ( ) ,
371+ kv_content_len : old. kv_content_len ,
372+ } ;
395373 for kvm in baggage. into_iter ( ) . map ( |kv| kv. into ( ) ) {
396374 merged. insert_with_metadata ( kvm. key , kvm. value , kvm. metadata ) ;
397375 }
@@ -531,29 +509,6 @@ mod tests {
531509 assert_eq ! ( baggage. len( ) , MAX_KEY_VALUE_PAIRS )
532510 }
533511
534- #[ test]
535- fn insert_too_long_pair ( ) {
536- let pair = KeyValue :: new (
537- "test" ,
538- String :: from_utf8_lossy ( vec ! [ 12u8 ; MAX_BYTES_FOR_ONE_PAIR ] . as_slice ( ) ) . to_string ( ) ,
539- ) ;
540- let mut baggage = Baggage :: default ( ) ;
541- baggage. insert ( pair. key . clone ( ) , pair. value . clone ( ) ) ;
542- assert_eq ! (
543- baggage. len( ) ,
544- 0 ,
545- "The input pair is too long to insert into baggage"
546- ) ;
547-
548- baggage. insert ( "test" , "value" ) ;
549- baggage. insert ( pair. key . clone ( ) , pair. value ) ;
550- assert_eq ! (
551- baggage. get( pair. key) ,
552- Some ( & StringValue :: from( "value" ) ) ,
553- "If the input pair is too long, then don't replace entry with same key"
554- )
555- }
556-
557512 #[ test]
558513 fn insert_pairs_length_exceed ( ) {
559514 let mut data = vec ! [ ] ;
0 commit comments