@@ -959,6 +959,7 @@ pub mod stream {
959959 output : OutputQueue < 1024 > ,
960960 finished : bool ,
961961 finalized : bool ,
962+ failed : bool ,
962963 }
963964
964965 impl < W , A , const PAD : bool > Decoder < W , A , PAD >
@@ -976,6 +977,7 @@ pub mod stream {
976977 output : OutputQueue :: new ( ) ,
977978 finished : false ,
978979 finalized : false ,
980+ failed : false ,
979981 }
980982 }
981983
@@ -1075,11 +1077,21 @@ pub mod stream {
10751077 self . finalized
10761078 }
10771079
1080+ /// Returns whether this decoder has rejected malformed Base64 input.
1081+ ///
1082+ /// Once this returns `true`, later writes, flushes, and finalization
1083+ /// attempts return an error. The unchecked [`Self::into_inner`] method
1084+ /// can still be used for explicit recovery of the wrapped writer.
1085+ #[ must_use]
1086+ pub const fn is_failed ( & self ) -> bool {
1087+ self . failed
1088+ }
1089+
10781090 /// Returns whether [`Self::try_into_inner`] can recover the wrapped
10791091 /// writer without discarding pending encoded input.
10801092 #[ must_use]
10811093 pub const fn can_into_inner ( & self ) -> bool {
1082- !self . has_pending_input ( ) && !self . has_buffered_output ( )
1094+ !self . is_failed ( ) && ! self . has_pending_input ( ) && !self . has_buffered_output ( )
10831095 }
10841096
10851097 /// Consumes the decoder without flushing pending input.
@@ -1165,6 +1177,7 @@ pub mod stream {
11651177 . field ( "can_into_inner" , & self . can_into_inner ( ) )
11661178 . field ( "terminal_padding" , & self . finished )
11671179 . field ( "finalized" , & self . finalized )
1180+ . field ( "failed" , & self . failed )
11681181 . finish ( )
11691182 }
11701183 }
@@ -1184,6 +1197,9 @@ pub mod stream {
11841197 /// the caller still owns the decoder for diagnostics or explicit
11851198 /// recovery.
11861199 pub fn try_finish ( & mut self ) -> io:: Result < ( ) > {
1200+ if self . failed {
1201+ return Err ( stream_decoder_failed_error ( ) ) ;
1202+ }
11871203 if !self . finalized {
11881204 self . queue_pending_final ( ) ?;
11891205 self . finalized = true ;
@@ -1208,7 +1224,10 @@ pub mod stream {
12081224 let mut decoded = [ 0u8 ; 3 ] ;
12091225 let result = self . queue_decoded_temp ( & pending[ ..pending_len] , & mut decoded) ;
12101226 crate :: wipe_bytes ( & mut pending) ;
1211- result?;
1227+ if let Err ( err) = result {
1228+ self . clear_pending ( ) ;
1229+ return Err ( err) ;
1230+ }
12121231 self . clear_pending ( ) ;
12131232 Ok ( ( ) )
12141233 }
@@ -1229,6 +1248,7 @@ pub mod stream {
12291248 Ok ( written) => written,
12301249 Err ( err) => {
12311250 crate :: wipe_bytes ( decoded) ;
1251+ self . failed = true ;
12321252 return Err ( decode_error_to_io ( err) ) ;
12331253 }
12341254 } ;
@@ -1275,6 +1295,9 @@ pub mod stream {
12751295 A : Alphabet ,
12761296 {
12771297 fn write ( & mut self , input : & [ u8 ] ) -> io:: Result < usize > {
1298+ if self . failed {
1299+ return Err ( stream_decoder_failed_error ( ) ) ;
1300+ }
12781301 if input. is_empty ( ) {
12791302 self . drain_output ( ) ?;
12801303 return Ok ( 0 ) ;
@@ -1287,6 +1310,7 @@ pub mod stream {
12871310 ) ) ;
12881311 }
12891312 if self . finished {
1313+ self . failed = true ;
12901314 return Err ( trailing_input_after_padding_error ( ) ) ;
12911315 }
12921316
@@ -1305,7 +1329,10 @@ pub mod stream {
13051329 quad[ self . pending_len ..] . copy_from_slice ( & input[ ..needed] ) ;
13061330 let result = self . queue_full_quad ( quad) ;
13071331 crate :: wipe_bytes ( & mut quad) ;
1308- result?;
1332+ if let Err ( err) = result {
1333+ self . clear_pending ( ) ;
1334+ return Err ( err) ;
1335+ }
13091336 self . clear_pending ( ) ;
13101337 consumed += needed;
13111338 return Ok ( consumed) ;
@@ -1330,6 +1357,9 @@ pub mod stream {
13301357 }
13311358
13321359 fn flush ( & mut self ) -> io:: Result < ( ) > {
1360+ if self . failed {
1361+ return Err ( stream_decoder_failed_error ( ) ) ;
1362+ }
13331363 self . drain_output ( ) ?;
13341364 self . inner_mut ( ) . flush ( )
13351365 }
@@ -1346,6 +1376,13 @@ pub mod stream {
13461376 )
13471377 }
13481378
1379+ fn stream_decoder_failed_error ( ) -> io:: Error {
1380+ io:: Error :: new (
1381+ io:: ErrorKind :: InvalidInput ,
1382+ "base64 stream decoder is failed after malformed input" ,
1383+ )
1384+ }
1385+
13491386 /// A streaming Base64 decoder for `std::io::Read`.
13501387 ///
13511388 /// For padded engines, this reader stops at the terminal padded Base64
@@ -1363,6 +1400,7 @@ pub mod stream {
13631400 output : OutputQueue < 3 > ,
13641401 finished : bool ,
13651402 terminal_seen : bool ,
1403+ failed : bool ,
13661404 }
13671405
13681406 impl < R , A , const PAD : bool > DecoderReader < R , A , PAD >
@@ -1380,6 +1418,7 @@ pub mod stream {
13801418 output : OutputQueue :: new ( ) ,
13811419 finished : false ,
13821420 terminal_seen : false ,
1421+ failed : false ,
13831422 }
13841423 }
13851424
@@ -1489,11 +1528,22 @@ pub mod stream {
14891528 self . finished && self . output . is_empty ( )
14901529 }
14911530
1531+ /// Returns whether this decoder reader has rejected malformed Base64
1532+ /// input.
1533+ ///
1534+ /// Once this returns `true`, later reads return an error. The unchecked
1535+ /// [`Self::into_inner`] method can still be used for explicit recovery
1536+ /// of the wrapped reader.
1537+ #[ must_use]
1538+ pub const fn is_failed ( & self ) -> bool {
1539+ self . failed
1540+ }
1541+
14921542 /// Returns whether [`Self::try_into_inner`] can recover the wrapped
14931543 /// reader without discarding buffered decoded output.
14941544 #[ must_use]
14951545 pub const fn can_into_inner ( & self ) -> bool {
1496- self . is_finished ( )
1546+ ! self . is_failed ( ) && self . is_finished ( )
14971547 }
14981548
14991549 /// Consumes the decoder reader and returns the wrapped reader.
@@ -1575,6 +1625,7 @@ pub mod stream {
15751625 . field ( "can_into_inner" , & self . can_into_inner ( ) )
15761626 . field ( "finished" , & self . finished )
15771627 . field ( "terminal_padding" , & self . terminal_seen )
1628+ . field ( "failed" , & self . failed )
15781629 . finish ( )
15791630 }
15801631 }
@@ -1588,6 +1639,9 @@ pub mod stream {
15881639 if output. is_empty ( ) {
15891640 return Ok ( 0 ) ;
15901641 }
1642+ if self . failed {
1643+ return Err ( stream_decoder_failed_error ( ) ) ;
1644+ }
15911645
15921646 while self . output . is_empty ( ) && !self . finished {
15931647 self . fill_output ( ) ?;
@@ -1603,6 +1657,9 @@ pub mod stream {
16031657 A : Alphabet ,
16041658 {
16051659 fn fill_output ( & mut self ) -> io:: Result < ( ) > {
1660+ if self . failed {
1661+ return Err ( stream_decoder_failed_error ( ) ) ;
1662+ }
16061663 if self . terminal_seen {
16071664 self . finished = true ;
16081665 return Ok ( ( ) ) ;
@@ -1656,6 +1713,7 @@ pub mod stream {
16561713 Ok ( written) => written,
16571714 Err ( err) => {
16581715 crate :: wipe_bytes ( & mut decoded) ;
1716+ self . failed = true ;
16591717 return Err ( decode_error_to_io ( err) ) ;
16601718 }
16611719 } ;
0 commit comments