@@ -519,6 +519,49 @@ def flush
519519 end
520520 end
521521
522+ it "raises exceptions with a nested cause that do not look like abort exceptions" do
523+ servlet_response = org . jruby . rack . mock . fail . FailingHttpServletResponse . new
524+ # e.g. Jetty failing a stalled write: IOException caused by a TimeoutException
525+ servlet_response . setFailure java . io . IOException . new (
526+ java . util . concurrent . TimeoutException . new ( 'Idle timeout expired: 30000/30000 ms' )
527+ )
528+ begin
529+ with_swallow_client_abort do
530+ response . write_body new_response_environment ( servlet_response )
531+ end
532+ fail 'IO exception NOT raised!'
533+ rescue java . io . IOException => e
534+ expect ( e . to_s ) . to match ( /idle timeout expired/i )
535+ end
536+ end
537+
538+ it "swallows client abort exceptions nested deeper in the cause chain" do
539+ servlet_response = org . jruby . rack . mock . fail . FailingHttpServletResponse . new
540+ servlet_response . setFailure java . io . IOException . new ( 'write failed' ,
541+ java . io . IOException . new ( 'connection problem' , java . io . IOException . new ( 'Broken pipe' ) )
542+ )
543+ with_swallow_client_abort do
544+ response . write_body new_response_environment ( servlet_response )
545+ end
546+ end
547+
548+ it "raises (and does not hang) on a cyclic cause chain" do
549+ failure = java . io . IOException . new 'write failed'
550+ cause = java . io . IOException . new 'nested failure'
551+ failure . initCause cause
552+ cause . initCause failure
553+ servlet_response = org . jruby . rack . mock . fail . FailingHttpServletResponse . new
554+ servlet_response . setFailure failure
555+ begin
556+ with_swallow_client_abort do
557+ response . write_body new_response_environment ( servlet_response )
558+ end
559+ fail 'IO exception NOT raised!'
560+ rescue java . io . IOException => e
561+ expect ( e . to_s ) . to match ( /write failed/i )
562+ end
563+ end
564+
522565 private
523566
524567 def with_dechunk ( dechunk = true )
0 commit comments