@@ -28,17 +28,19 @@ enum BoundedSseStreamError {
2828#[ derive( Debug ) ]
2929struct SseEventSizeLimiter {
3030 max_size : usize ,
31- event_size : usize ,
31+ retained_size : usize ,
3232 line_size : usize ,
33+ line_is_comment : bool ,
3334 previous_was_cr : bool ,
3435}
3536
3637impl SseEventSizeLimiter {
3738 fn new ( max_size : usize ) -> Self {
3839 Self {
3940 max_size,
40- event_size : 0 ,
41+ retained_size : 0 ,
4142 line_size : 0 ,
43+ line_is_comment : false ,
4244 previous_was_cr : false ,
4345 }
4446 }
@@ -59,8 +61,10 @@ impl SseEventSizeLimiter {
5961 }
6062 b'\n' => self . finish_line ( ) ?,
6163 _ => {
64+ if self . line_size == 0 {
65+ self . line_is_comment = byte == b':' ;
66+ }
6267 self . line_size = self . line_size . saturating_add ( 1 ) ;
63- self . event_size = self . event_size . saturating_add ( 1 ) ;
6468 self . check_limit ( ) ?;
6569 }
6670 }
@@ -70,18 +74,21 @@ impl SseEventSizeLimiter {
7074
7175 fn finish_line ( & mut self ) -> Result < ( ) , ( ) > {
7276 if self . line_size == 0 {
73- self . event_size = 0 ;
74- } else {
77+ self . retained_size = 0 ;
78+ } else if ! self . line_is_comment {
7579 // The SSE parser inserts a newline when joining multiple data fields.
76- self . event_size = self . event_size . saturating_add ( 1 ) ;
77- self . check_limit ( ) ?;
78- self . line_size = 0 ;
80+ self . retained_size = self
81+ . retained_size
82+ . saturating_add ( self . line_size )
83+ . saturating_add ( 1 ) ;
7984 }
80- Ok ( ( ) )
85+ self . line_size = 0 ;
86+ self . line_is_comment = false ;
87+ self . check_limit ( )
8188 }
8289
8390 fn check_limit ( & self ) -> Result < ( ) , ( ) > {
84- if self . event_size > self . max_size {
91+ if self . retained_size . saturating_add ( self . line_size ) > self . max_size {
8592 Err ( ( ) )
8693 } else {
8794 Ok ( ( ) )
@@ -270,7 +277,8 @@ pub(crate) trait SseStreamReconnect {
270277 tracing:: warn!( "sse stream error: {error}" ) ;
271278 }
272279 }
273- fn map_fatal_stream_error ( & mut self , _error : SseError ) -> Option < Self :: Error > {
280+ fn map_fatal_stream_error ( & mut self , error : SseError ) -> Option < Self :: Error > {
281+ tracing:: warn!( "fatal sse stream error: {error}" ) ;
274282 None
275283 }
276284}
@@ -589,6 +597,26 @@ mod tests {
589597 assert_eq ! ( second. data. as_deref( ) , Some ( "world" ) ) ;
590598 }
591599
600+ #[ tokio:: test]
601+ async fn bounded_sse_stream_discards_completed_comment_lines_from_limit ( ) {
602+ let source = futures:: stream:: iter ( [ Ok :: < _ , std:: io:: Error > ( Bytes :: from_static (
603+ b": ping\n : ping\n : ping\n " ,
604+ ) ) ] ) ;
605+ let mut stream = bounded_sse_stream ( source, 6 ) ;
606+
607+ assert ! ( stream. next( ) . await . is_none( ) ) ;
608+ }
609+
610+ #[ tokio:: test]
611+ async fn bounded_sse_stream_comments_do_not_reset_accumulated_data ( ) {
612+ let source = futures:: stream:: iter ( [ Ok :: < _ , std:: io:: Error > ( Bytes :: from_static (
613+ b"data: a\n : ping\n data: b\n " ,
614+ ) ) ] ) ;
615+ let mut stream = bounded_sse_stream ( source, 14 ) ;
616+
617+ assert ! ( stream. next( ) . await . unwrap( ) . is_err( ) ) ;
618+ }
619+
592620 #[ tokio:: test]
593621 async fn bounded_sse_stream_counts_multiline_data_join_newlines ( ) {
594622 let source = futures:: stream:: iter ( [ Ok :: < _ , std:: io:: Error > ( Bytes :: from_static (
0 commit comments