class Goliath::RackProxy::RackInput

IO-like object that conforms to the Rack specification for the request body (“rack input”). It takes a block which produces chunks of data, and makes this data retrievable through the IO#read interface. When rewindable caches the retrieved content onto disk.

Public Class Methods

new(rewindable: true, &next_chunk) click to toggle source
# File lib/goliath/rack_proxy.rb, line 112
def initialize(rewindable: true, &next_chunk)
  @next_chunk = next_chunk
  @cache      = Tempfile.new("goliath-rack_input", binmode: true) if rewindable
  @buffer     = nil
  @eof        = false
end

Public Instance Methods

close() click to toggle source

Deletes the tempfile. The close method is also part of the Rack specification.

# File lib/goliath/rack_proxy.rb, line 168
def close
  @cache.close! if @cache
end
read(length = nil, outbuf = nil) click to toggle source

Retrieves data using the IO#read semantics. If rack input is declared rewindable, writes retrieved content into a Tempfile object so that it can later be re-read.

# File lib/goliath/rack_proxy.rb, line 122
def read(length = nil, outbuf = nil)
  data = outbuf.clear if outbuf
  data = @cache.read(length, outbuf) if @cache && !@cache.eof?

  loop do
    remaining_length = length - data.bytesize if data && length

    break if remaining_length == 0

    @buffer = next_chunk or break if @buffer.nil?

    buffered_data = if remaining_length && remaining_length < @buffer.bytesize
                      @buffer.byteslice(0, remaining_length)
                    else
                      @buffer
                    end

    if data
      data << buffered_data
    else
      data = buffered_data
    end

    @cache.write(buffered_data) if @cache

    if buffered_data.bytesize < @buffer.bytesize
      @buffer = @buffer.byteslice(buffered_data.bytesize..-1)
    else
      @buffer = nil
    end

    buffered_data.clear unless data.equal?(buffered_data)
  end

  data.to_s unless length && (data.nil? || data.empty?)
end
rewind() click to toggle source

Rewinds the tempfile if rewindable. Otherwise raises Errno::ESPIPE exception, which is what other non-rewindable Ruby IO objects raise.

# File lib/goliath/rack_proxy.rb, line 161
def rewind
  raise Errno::ESPIPE if @cache.nil?
  @cache.rewind
end

Private Instance Methods

next_chunk() click to toggle source

Retrieves the next chunk by calling the block, and marks EOF when nil was returned.

# File lib/goliath/rack_proxy.rb, line 176
def next_chunk
  return if @eof
  chunk = @next_chunk.call
  @eof = true if chunk.nil?
  chunk
end