Class: IntervalResponse::Sequence
- Inherits:
-
Object
- Object
- IntervalResponse::Sequence
- Defined in:
- lib/interval_response/sequence.rb
Overview
An interval sequence represents a linear sequence of non-overlapping, joined intervals. For example, an HTTP response which consists of multiple edge included segments, or a timeline with clips joined together. Every interval contains a segment - an arbitrary object which responds to ‘#size` at time of adding to the IntervalSequence.
Defined Under Namespace
Classes: Interval
Constant Summary collapse
- MULTIPART_GENRATOR_FINGERPRINT =
'boo'
Instance Attribute Summary collapse
-
#size ⇒ Object
readonly
Returns the value of attribute size.
Instance Method Summary collapse
- #<<(segment) ⇒ Object
- #add_segment(segment, size:) ⇒ Object
- #each_in_range(from_range_in_resource) ⇒ Object
- #empty? ⇒ Boolean
-
#etag ⇒ Object
For IE resumes to work, a strong ETag must be set in the response, and a strong comparison must be performed on it.
-
#initialize(*segments) ⇒ Sequence
constructor
A new instance of Sequence.
Constructor Details
#initialize(*segments) ⇒ Sequence
14 15 16 17 18 |
# File 'lib/interval_response/sequence.rb', line 14 def initialize(*segments) @intervals = [] @size = 0 segments.each { |s| self << s } end |
Instance Attribute Details
#size ⇒ Object (readonly)
Returns the value of attribute size.
12 13 14 |
# File 'lib/interval_response/sequence.rb', line 12 def size @size end |
Instance Method Details
#<<(segment) ⇒ Object
20 21 22 23 24 25 26 27 |
# File 'lib/interval_response/sequence.rb', line 20 def <<(segment) segment_size_or_bytesize = segment.respond_to?(:bytesize) ? segment.bytesize : segment.size return self if segment_size_or_bytesize == 0 add_segment(segment, size: segment_size_or_bytesize) self self end |
#add_segment(segment, size:) ⇒ Object
29 30 31 32 |
# File 'lib/interval_response/sequence.rb', line 29 def add_segment(segment, size:) @intervals << Interval.new(segment, size, @size, @intervals.length) @size += size end |
#each_in_range(from_range_in_resource) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/interval_response/sequence.rb', line 34 def each_in_range(from_range_in_resource) # Skip empty ranges requested_range_size = (from_range_in_resource.end - from_range_in_resource.begin) + 1 return if requested_range_size < 1 # ...and if the range misses our intervals completely included_intervals = intervals_within_range(from_range_in_resource) # And normal case - walk through included intervals included_intervals.each do |interval| int_start = interval.offset int_end = interval.offset + interval.size - 1 req_start = from_range_in_resource.begin req_end = from_range_in_resource.end range_within_interval = (max(int_start, req_start) - int_start)..(min(int_end, req_end) - int_start) # Allow Sequences to be composed together if interval.segment.respond_to?(:each_in_range) interval.segment.each_in_range(range_within_interval) do |sub_segment, sub_range| yield(sub_segment, sub_range) end else yield(interval.segment, range_within_interval) end end end |
#empty? ⇒ Boolean
61 62 63 |
# File 'lib/interval_response/sequence.rb', line 61 def empty? @size == 0 end |
#etag ⇒ Object
For IE resumes to work, a strong ETag must be set in the response, and a strong comparison must be performed on it.
ETags have meaning with Range: requests, because when a client requests a range it will send the ETag back in the If-Range header. That header tells the server that “I want to have the ranges as emitted by the response representation that has output this etag”. This is done so that there is a guarantee that the same resource being requested has the same resource length (off of which the ranges get computed), and the ranges can be safely combined by the client. In practice this means that the ETag must contain some “version handle” which stays unchanged as long as the code responsible for generating the response does not change. In our case the response can change due to the following things:
-
The lengths of the segments change
-
The contents of the segments changes
-
Code that outputs the ranges themselves changes, and outputs different offsets of differently-sized resources. A resource can be differently sized since the MIME multiplart-byte-range response can have its boundary or per-part headers change, which affects the size of the MIME part headers. Even though the boundary is not a part of the resource itself, the sizes of the part headers do contribute to the envelope size - that should stay the same as long as the ETag holds.
It is important that the returned ETag is a strong ETag (not prefixed with ‘W/’) and must be enclosed in double-quotes.
See for more blogs.msdn.microsoft.com/ieinternals/2011/06/03/download-resumption-in-internet-explorer/
91 92 93 94 95 96 |
# File 'lib/interval_response/sequence.rb', line 91 def etag d = Digest::SHA1.new d << IntervalResponse::VERSION d << Marshal.dump(@intervals.map(&:size)) '"%s"' % d.hexdigest end |