Class: Goliath::RackProxy::RackInput

Inherits:
Object
  • Object
show all
Defined in:
lib/goliath/rack_proxy.rb

Overview

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.

Instance Method Summary collapse

Constructor Details

#initialize(rewindable: true, &next_chunk) ⇒ RackInput

Returns a new instance of RackInput.



112
113
114
115
116
117
# 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

Instance Method Details

#closeObject

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



168
169
170
# File 'lib/goliath/rack_proxy.rb', line 168

def close
  @cache.close! if @cache
end

#read(length = nil, outbuf = nil) ⇒ Object

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.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# 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

#rewindObject

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

Raises:

  • (Errno::ESPIPE)


161
162
163
164
# File 'lib/goliath/rack_proxy.rb', line 161

def rewind
  raise Errno::ESPIPE if @cache.nil?
  @cache.rewind
end