15
15
//!
16
16
//! [W3C Baggage]: https://w3c.github.io/baggage
17
17
use crate :: { Context , Key , KeyValue , StringValue } ;
18
+ use std:: collections:: hash_map:: Entry ;
18
19
use std:: collections:: { hash_map, HashMap } ;
19
20
use std:: fmt;
20
21
use std:: sync:: OnceLock ;
21
22
22
23
static DEFAULT_BAGGAGE : OnceLock < Baggage > = OnceLock :: new ( ) ;
23
24
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 ;
26
26
const MAX_LEN_OF_ALL_PAIRS : usize = 8192 ;
27
27
28
28
/// Returns the default baggage, ensuring it is initialized only once.
@@ -49,11 +49,10 @@ fn get_default_baggage() -> &'static Baggage {
49
49
///
50
50
/// ### Limits
51
51
///
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`.
54
53
/// * Maximum total length of all name/value pairs: `8192`.
55
54
///
56
- /// [RFC2616, Section 2.2]: https://tools.ietf .org/html/rfc2616#section-2.2
55
+ /// < https://www.w3 .org/TR/baggage/#limits>
57
56
#[ derive( Debug , Default ) ]
58
57
pub struct Baggage {
59
58
inner : HashMap < Key , ( StringValue , BaggageMetadata ) > ,
@@ -133,6 +132,8 @@ impl Baggage {
133
132
/// Same with `insert`, if the name was not present, [`None`] will be returned.
134
133
/// If the name is present, the old value and metadata will be returned.
135
134
///
135
+ /// Also checks for [limits](https://w3c.github.io/baggage/#limits).
136
+ ///
136
137
/// # Examples
137
138
///
138
139
/// ```
@@ -155,10 +156,38 @@ impl Baggage {
155
156
S : Into < BaggageMetadata > ,
156
157
{
157
158
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
+ }
162
191
}
163
192
}
164
193
@@ -178,59 +207,10 @@ impl Baggage {
178
207
self . inner . is_empty ( )
179
208
}
180
209
181
- /// Gets an iterator over the baggage items, sorted by name .
210
+ /// Gets an iterator over the baggage items, in any order .
182
211
pub fn iter ( & self ) -> Iter < ' _ > {
183
212
self . into_iter ( )
184
213
}
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
- }
234
214
}
235
215
236
216
/// Get the number of bytes for one key-value pair
@@ -385,13 +365,11 @@ impl BaggageExt for Context {
385
365
& self ,
386
366
baggage : T ,
387
367
) -> 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
+ } ;
395
373
for kvm in baggage. into_iter ( ) . map ( |kv| kv. into ( ) ) {
396
374
merged. insert_with_metadata ( kvm. key , kvm. value , kvm. metadata ) ;
397
375
}
@@ -531,29 +509,6 @@ mod tests {
531
509
assert_eq ! ( baggage. len( ) , MAX_KEY_VALUE_PAIRS )
532
510
}
533
511
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
-
557
512
#[ test]
558
513
fn insert_pairs_length_exceed ( ) {
559
514
let mut data = vec ! [ ] ;
@@ -611,4 +566,22 @@ mod tests {
611
566
assert ! ( b. to_string( ) . contains( "bar=2;yellow" ) ) ;
612
567
assert ! ( b. to_string( ) . contains( "foo=1;red;state=on" ) ) ;
613
568
}
569
+
570
+ #[ test]
571
+ fn replace_existing_key ( ) {
572
+ let half_minus2: StringValue = ( 0 ..MAX_LEN_OF_ALL_PAIRS / 2 - 2 )
573
+ . map ( |_| 'x' )
574
+ . collect :: < String > ( )
575
+ . into ( ) ;
576
+
577
+ let mut b = Baggage :: default ( ) ;
578
+ b. insert ( "a" , half_minus2. clone ( ) ) ; // +1 for key
579
+ b. insert ( "b" , half_minus2) ; // +1 for key
580
+ b. insert ( "c" , StringValue :: from ( "." ) ) ; // total of 2 bytes
581
+ assert ! ( b. get( "a" ) . is_some( ) ) ;
582
+ assert ! ( b. get( "b" ) . is_some( ) ) ;
583
+ assert ! ( b. get( "c" ) . is_some( ) ) ;
584
+ assert ! ( b. insert( "c" , StringValue :: from( ".." ) ) . is_none( ) ) ; // exceeds MAX_LEN_OF_ALL_PAIRS
585
+ assert_eq ! ( b. insert( "c" , StringValue :: from( "!" ) ) . unwrap( ) , "." . into( ) ) ; // replaces existing
586
+ }
614
587
}
0 commit comments