@@ -116,16 +116,33 @@ impl<'a> Iterator for ParseIntoOwned<'a> {
116116
117117/// The [`application/x-www-form-urlencoded` byte serializer](
118118/// https://url.spec.whatwg.org/#concept-urlencoded-byte-serializer).
119+ /// Converts spaces (b' ') to the percent-encoded equivalent ("%20").
119120///
120121/// Return an iterator of `&str` slices.
121122pub fn byte_serialize ( input : & [ u8 ] ) -> ByteSerialize < ' _ > {
122- ByteSerialize { bytes : input }
123+ ByteSerialize {
124+ bytes : input,
125+ space_as_plus : false ,
126+ }
127+ }
128+
129+ /// The [`application/x-www-form-urlencoded` byte serializer](
130+ /// https://url.spec.whatwg.org/#concept-urlencoded-byte-serializer).
131+ /// Converts spaces (b' ') to plus signs (b'+').
132+ ///
133+ /// Return an iterator of `&str` slices.
134+ pub fn byte_serialize_space_as_plus ( input : & [ u8 ] ) -> ByteSerialize < ' _ > {
135+ ByteSerialize {
136+ bytes : input,
137+ space_as_plus : true ,
138+ }
123139}
124140
125141/// Return value of `byte_serialize()`.
126142#[ derive( Debug ) ]
127143pub struct ByteSerialize < ' a > {
128144 bytes : & ' a [ u8 ] ,
145+ space_as_plus : bool ,
129146}
130147
131148fn byte_serialized_unchanged ( byte : u8 ) -> bool {
@@ -139,7 +156,7 @@ impl<'a> Iterator for ByteSerialize<'a> {
139156 if let Some ( ( & first, tail) ) = self . bytes . split_first ( ) {
140157 if !byte_serialized_unchanged ( first) {
141158 self . bytes = tail;
142- return Some ( if first == b' ' {
159+ return Some ( if first == b' ' && self . space_as_plus {
143160 "+"
144161 } else {
145162 percent_encode_byte ( first)
@@ -337,7 +354,7 @@ impl<'a, T: Target> Serializer<'a, T> {
337354 /// .append_pair("foo", "bar & baz")
338355 /// .append_pair("saison", "Été+hiver")
339356 /// .finish();
340- /// assert_eq!(encoded, "foo=bar+%26+baz &saison=%C3%89t%C3%A9%2Bhiver");
357+ /// assert_eq!(encoded, "foo=bar%20%26%20baz &saison=%C3%89t%C3%A9%2Bhiver");
341358 /// ```
342359 ///
343360 /// Panics if called more than once.
@@ -428,3 +445,34 @@ pub(crate) fn decode_utf8_lossy(input: Cow<'_, [u8]>) -> Cow<'_, str> {
428445}
429446
430447pub type EncodingOverride < ' a > = Option < & ' a dyn Fn ( & str ) -> Cow < ' _ , [ u8 ] > > ;
448+
449+ #[ cfg( test) ]
450+ mod tests {
451+ use alloc:: string:: String ;
452+
453+ use crate :: { byte_serialize, byte_serialize_space_as_plus} ;
454+
455+ #[ test]
456+ fn byte_serializer ( ) {
457+ let in_1 = "c ool/org" ;
458+ let out_1 = "c%20ool%2Forg" ;
459+
460+ let in_2 = "a🔒nother&bu=ck?et" ;
461+ let out_2 = "a%F0%9F%94%92nother%26bu%3Dck%3Fet" ;
462+
463+ assert_eq ! ( byte_serialize( in_1. as_bytes( ) ) . collect:: <String >( ) , out_1) ;
464+ assert_eq ! ( byte_serialize( in_2. as_bytes( ) ) . collect:: <String >( ) , out_2) ;
465+ }
466+
467+ #[ test]
468+ fn byte_serializer_space_as_plus ( ) {
469+ let in_1 = "c ool/org" ;
470+ let out_1 = "c+ool%2Forg" ;
471+
472+ let in_2 = "a🔒nother&bu=ck?et " ;
473+ let out_2 = "a%F0%9F%94%92nother%26bu%3Dck%3Fet+" ;
474+
475+ assert_eq ! ( byte_serialize_space_as_plus( in_1. as_bytes( ) ) . collect:: <String >( ) , out_1) ;
476+ assert_eq ! ( byte_serialize_space_as_plus( in_2. as_bytes( ) ) . collect:: <String >( ) , out_2) ;
477+ }
478+ }
0 commit comments