@@ -28,19 +28,46 @@ def read_response_buffer
2828
2929 attr_reader :buff , :literal_size
3030
31+ def bytes_read = buff . bytesize
32+ def empty? = buff . empty?
33+ def done? = line_done? && !get_literal_size
34+ def line_done? = buff . end_with? ( CRLF )
3135 def get_literal_size ; /\{ (\d +)\} \r \n \z /n =~ buff && $1. to_i end
3236
3337 def read_line
34- buff << ( @sock . gets ( CRLF ) or throw :eof )
38+ buff << ( @sock . gets ( CRLF , read_limit ) or throw :eof )
39+ max_response_remaining! unless line_done?
3540 end
3641
3742 def read_literal
43+ # check before allocating memory for literal
44+ max_response_remaining!
3845 literal = String . new ( capacity : literal_size )
39- buff << ( @sock . read ( literal_size , literal ) or throw :eof )
46+ buff << ( @sock . read ( read_limit ( literal_size ) , literal ) or throw :eof )
4047 ensure
4148 @literal_size = nil
4249 end
4350
51+ def read_limit ( limit = nil )
52+ [ limit , max_response_remaining! ] . compact . min
53+ end
54+
55+ def max_response_size = 512 << 20 # TODO: Config#max_response_size
56+ def max_response_remaining = max_response_size &.- bytes_read
57+ def response_too_large? = max_response_size &.< min_response_size
58+ def min_response_size = bytes_read + min_response_remaining
59+
60+ def min_response_remaining
61+ empty? ? 3 : done? ? 0 : ( literal_size || 0 ) + 2
62+ end
63+
64+ def max_response_remaining!
65+ return max_response_remaining unless response_too_large?
66+ raise ResponseTooLargeError . new (
67+ max_response_size :, bytes_read :, literal_size :,
68+ )
69+ end
70+
4471 end
4572 end
4673end
0 commit comments