Class: Dis::ResponseBody

Inherits:
Object
  • Object
show all
Defined in:
lib/dis/response_body.rb

Overview

Dis Response Body

Rack body that streams an open file and closes it once the response has been sent. The file may already be unlinked, so it is read through the open descriptor and never by path.

Streams only the given ranges when any are given, as a multipart/byteranges payload if there is more than one.

Constant Summary collapse

CHUNK_SIZE =
16_384

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file, ranges: nil, content_type: nil) ⇒ ResponseBody

Returns a new instance of ResponseBody.

Parameters:

  • file (File)

    an open, readable file

  • ranges (Array<Range>, nil) (defaults to: nil)

    byte ranges, or nil for all of it

  • content_type (String, nil) (defaults to: nil)

    content type of the parts



28
29
30
31
32
33
# File 'lib/dis/response_body.rb', line 28

def initialize(file, ranges: nil, content_type: nil)
  @file = file
  @ranges = Array(ranges)
  @content_type = content_type
  @boundary = SecureRandom.hex(16) if multipart?
end

Instance Attribute Details

#boundaryString? (readonly)

Returns the multipart boundary, when multipart.

Returns:

  • (String, nil)

    the multipart boundary, when multipart



23
24
25
# File 'lib/dis/response_body.rb', line 23

def boundary
  @boundary
end

#rangesArray<Range> (readonly)

Returns the ranges being streamed.

Returns:

  • (Array<Range>)

    the ranges being streamed



20
21
22
# File 'lib/dis/response_body.rb', line 20

def ranges
  @ranges
end

Instance Method Details

#abortvoid

This method returns an undefined value.

Releases the file. Rack's end-of-response close arrives here through ActionDispatch::Response#abort.



86
87
88
# File 'lib/dis/response_body.rb', line 86

def abort
  @file.close unless @file.closed?
end

#bodyString

Returns the contents as a binary string.

Returns:

  • (String)


58
59
60
# File 'lib/dis/response_body.rb', line 58

def body
  (+"").b.tap { |out| each { |chunk| out << chunk } }
end

#closevoid

This method returns an undefined value.

Signals that no more content will be written. This does not release the file. ActionController::Live calls it as soon as the body is assigned, long before Rack iterates it.



78
79
80
# File 'lib/dis/response_body.rb', line 78

def close
  nil
end

#each {|chunk| ... } ⇒ void

This method returns an undefined value.

Yields the contents in chunks.

Yield Parameters:

  • chunk (String)

    a chunk of the contents



66
67
68
69
70
71
# File 'lib/dis/response_body.rb', line 66

def each(&)
  return stream(0, @file.size, &) if ranges.empty?
  return stream(range.begin, range.size, &) unless multipart?

  each_part(&)
end

#lengthInteger

Returns the number of bytes that will be written.

Returns:

  • (Integer)


48
49
50
51
52
53
# File 'lib/dis/response_body.rb', line 48

def length
  return @file.size if ranges.empty?
  return multipart_length if multipart?

  range.size
end

#multipart?Boolean

Returns whether more than one range is being streamed.

Returns:

  • (Boolean)

    whether more than one range is being streamed



36
37
38
# File 'lib/dis/response_body.rb', line 36

def multipart?
  ranges.length > 1
end

#rangeRange?

Returns the range being streamed, unless multipart.

Returns:

  • (Range, nil)

    the range being streamed, unless multipart



41
42
43
# File 'lib/dis/response_body.rb', line 41

def range
  ranges.first unless multipart?
end