class FormatParser::ReadLimiter

Is used to limit the number of reads/seeks parsers can perform

Constants

NO_LIMIT

Attributes

bytes[R]
reads[R]
seeks[R]

Public Class Methods

new(io, max_bytes: NO_LIMIT, max_reads: NO_LIMIT, max_seeks: NO_LIMIT) click to toggle source

Creates a ReadLimiter wrapper around the given IO object and sets the limits on the number of reads/writes

@param io[#seek, pos, size, read] the IO object to wrap @param max_bytes[Integer, nil] how many bytes can we read from this before an exception is raised @param max_reads[Integer, nil] how many read() calls can we perform on this before an exception is raised @param max_seeks[Integer, nil] how many seek() calls can we perform on this before an exception is raised

# File lib/read_limiter.rb, line 17
def initialize(io, max_bytes: NO_LIMIT, max_reads: NO_LIMIT, max_seeks: NO_LIMIT)
  @max_bytes = max_bytes
  @max_reads = max_reads
  @max_seeks = max_seeks

  @io = io
  @seeks = 0
  @reads = 0
  @bytes = 0
end

Public Instance Methods

pos() click to toggle source

Returns the current position/offset within the IO

@return Integer

# File lib/read_limiter.rb, line 38
def pos
  @io.pos
end
read(n_bytes) click to toggle source

Returns at most `n_bytes` of data from the IO or less if less data was available before the EOF was hit

@param n_bytes @return [String, nil] the content read from the IO or `nil` if no data was available

# File lib/read_limiter.rb, line 59
def read(n_bytes)
  @bytes += n_bytes
  @reads += 1

  if @max_bytes && @bytes > @max_bytes
    raise BudgetExceeded, 'Read bytes budget (%d) exceeded' % @max_bytes
  end

  if @max_reads && @reads > @max_reads
    raise BudgetExceeded, 'Number of read() calls exceeded (%d max)' % @max_reads
  end

  @io.read(n_bytes)
end
reset_limits!() click to toggle source

Resets all the recorded call counters so that the object can be reused for the next parser, which will have it's own limits @return void

# File lib/read_limiter.rb, line 88
def reset_limits!
  @seeks = 0
  @reads = 0
  @bytes = 0
end
seek(to) click to toggle source

Seeks the IO to the given absolute offset from the start of the file/resource

@param to offset in the IO @return Integer

# File lib/read_limiter.rb, line 46
def seek(to)
  @seeks += 1
  if @max_seeks && @seeks > @max_seeks
    raise BudgetExceeded, 'Seek budget exceeded (%d seeks performed)' % @max_seeks
  end
  @io.seek(to)
end
send_metrics(prefix) click to toggle source

Sends the metrics about the state of this ReadLimiter to a Measurometer

@param prefix the prefix to set. For example, with prefix “TIFF” the metrics will be called

`format_parser.TIFF.read_limiter.num_seeks` and so forth

@return void

# File lib/read_limiter.rb, line 79
def send_metrics(prefix)
  Measurometer.add_distribution_value('format_parser.%s.read_limiter.num_seeks' % prefix, @seeks)
  Measurometer.add_distribution_value('format_parser.%s.read_limiter.num_reads' % prefix, @reads)
  Measurometer.add_distribution_value('format_parser.%s.read_limiter.read_bytes' % prefix, @bytes)
end
size() click to toggle source

Returns the size of the resource contained in the IO

@return Integer

# File lib/read_limiter.rb, line 31
def size
  @io.size
end