@@ -356,4 +356,64 @@ def assert_deprecated_copyuid_data_warning(check: true)
356356 assert_instance_of Net ::IMAP ::CopyUIDData , response . data . code . data
357357 end
358358
359+ def deeply_nested_bodystructure ( depth )
360+ leaf = '("TEXT" "PLAIN" NIL NIL NIL "7BIT" 1 1)'
361+ depth . times . reduce ( leaf ) { |part , _ | "(#{ part } \" MIXED\" )" }
362+ end
363+
364+ def deeply_nested_thread ( depth )
365+ depth . times . reduce ( "(1)" ) { |thread , _ | "(#{ thread } (1))" }
366+ end
367+
368+ def deeply_nested_extension_value ( depth )
369+ depth . times . reduce ( "1" ) { |value , _ | "(#{ value } )" }
370+ end
371+
372+ def patch_recursion_entrypoint ( parser , method_name )
373+ return if ENV [ "TEST_RESPONSE_PARSER_STACK_LEVEL" ] == "original"
374+
375+ parser . define_singleton_method ( method_name ) do |*args , **kwargs , &block |
376+ raise SystemStackError , "stack level too deep"
377+ end
378+ end
379+
380+ test "deeply nested BODYSTRUCTURE raises ResponseParseError instead of SystemStackError" do
381+ parser = Net ::IMAP ::ResponseParser . new
382+ patch_recursion_entrypoint ( parser , :body )
383+ response = "* 1 FETCH (BODYSTRUCTURE #{ deeply_nested_bodystructure ( 6000 ) } )\r \n "
384+
385+ error = assert_raise ( Net ::IMAP ::ResponseParseError ) do
386+ parser . parse ( response )
387+ end
388+
389+ assert_equal "response recursion too deep" , error . message
390+ assert_instance_of SystemStackError , error . cause
391+ end
392+
393+ test "deeply nested THREAD raises ResponseParseError instead of SystemStackError" do
394+ parser = Net ::IMAP ::ResponseParser . new
395+ patch_recursion_entrypoint ( parser , :thread_data )
396+ response = "* THREAD #{ deeply_nested_thread ( 6000 ) } \r \n "
397+
398+ error = assert_raise ( Net ::IMAP ::ResponseParseError ) do
399+ parser . parse ( response )
400+ end
401+
402+ assert_equal "response recursion too deep" , error . message
403+ assert_instance_of SystemStackError , error . cause
404+ end
405+
406+ test "deeply nested STATUS extension raises ResponseParseError instead of SystemStackError" do
407+ parser = Net ::IMAP ::ResponseParser . new
408+ patch_recursion_entrypoint ( parser , :tagged_ext_val )
409+ response = "* STATUS INBOX (X #{ deeply_nested_extension_value ( 11_000 ) } )\r \n "
410+
411+ error = assert_raise ( Net ::IMAP ::ResponseParseError ) do
412+ parser . parse ( response )
413+ end
414+
415+ assert_equal "response recursion too deep" , error . message
416+ assert_instance_of SystemStackError , error . cause
417+ end
418+
359419end
0 commit comments