Class: IntervalResponse::Multi

Inherits:
Object
  • Object
show all
Includes:
ToRackResponseTriplet
Defined in:
lib/interval_response/multi.rb

Constant Summary collapse

ALPHABET =
('0'..'9').to_a + ('a'..'z').to_a + ('A'..'Z').to_a

Constants included from ToRackResponseTriplet

ToRackResponseTriplet::CHUNK_SIZE

Instance Method Summary collapse

Methods included from ToRackResponseTriplet

#to_rack_response_triplet

Constructor Details

#initialize(interval_map, http_ranges) ⇒ Multi

Returns a new instance of Multi.



8
9
10
11
12
13
14
15
16
# File 'lib/interval_response/multi.rb', line 8

def initialize(interval_map, http_ranges)
  @interval_map = interval_map
  @http_ranges = http_ranges
  # RFC1521 says that a boundary "must be no longer than 70 characters,
  # not counting the two leading hyphens".
  # Modulo-based random is biased but it doesn't matter much for us (we do not need to
  # be extremely secure here)
  @boundary = SecureRandom.bytes(24).unpack("C*").map { |b| ALPHABET[b % ALPHABET.length] }.join
end

Instance Method Details

#content_lengthObject



34
35
36
37
38
39
40
41
42
# File 'lib/interval_response/multi.rb', line 34

def content_length
  # The Content-Length of a multipart response includes the length
  # of all the ranges of the resource, but also the lengths of the
  # multipart part headers - which we need to precompute. To do it
  # we need to run through all of our ranges and output some strings,
  # and if a lot of ranges are involved this can get expensive. So
  # memoize the envelope size (it never changes between calls)
  @envelope_size ||= compute_envelope_size
end

#eachObject



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/interval_response/multi.rb', line 18

def each
  # serve the part of the interval map
  @http_ranges.each_with_index do |http_range, range_i|
    part_header = part_header(range_i, http_range)
    entire_header_range = 0..(part_header.bytesize - 1)
    yield(part_header, entire_header_range)
    @interval_map.each_in_range(http_range) do |segment, range_in_segment|
      yield(segment, range_in_segment)
    end
  end
end

#headersObject



44
45
46
47
48
49
50
51
# File 'lib/interval_response/multi.rb', line 44

def headers
  {
    'Accept-Ranges' => 'bytes',
    'Content-Length' => content_length.to_s,
    'Content-Type' => "multipart/byte-ranges; boundary=#{@boundary}",
    'ETag' => @interval_map.etag,
  }
end

#status_codeObject



30
31
32
# File 'lib/interval_response/multi.rb', line 30

def status_code
  206
end