Class: Protocol::HTTP::Header::Range

Inherits:
Object
  • Object
show all
Defined in:
lib/protocol/http/header/range.rb

Overview

Represents a range request header.

Defined Under Namespace

Classes: ByteRange

Constant Summary collapse

ParseError =
Class.new(InvalidHeaderError)
TOKEN =
/[!#$%&'*+\-.0-9A-Z^_`a-z|~]+/
HEADER =
/\A(?<unit>#{TOKEN})=(?<ranges>.*)\z/
BYTE_RANGE =
/\A(?:(?<first>\d+)-(?<last>\d*)|-(?<suffix>\d+))\z/
OTHER_RANGE =
/\A[\x21-\x2B\x2D-\x7E]+\z/
SEPARATOR =
/\s*,\s*/

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(unit, ranges) ⇒ Range

Initialize a range header.



106
107
108
109
# File 'lib/protocol/http/header/range.rb', line 106

def initialize(unit, ranges)
  @unit = unit
  @ranges = ranges
end

Instance Attribute Details

#rangesObject (readonly)

Returns the value of attribute ranges.



115
116
117
# File 'lib/protocol/http/header/range.rb', line 115

def ranges
  @ranges
end

#The range specifiers.(rangespecifiers.) ⇒ Object (readonly)



115
# File 'lib/protocol/http/header/range.rb', line 115

attr :ranges

#The range unit.(rangeunit.) ⇒ Object (readonly)



112
# File 'lib/protocol/http/header/range.rb', line 112

attr :unit

#unitObject (readonly)

Returns the value of attribute unit.



112
113
114
# File 'lib/protocol/http/header/range.rb', line 112

def unit
  @unit
end

Class Method Details

.coerce(value) ⇒ Object

Coerce a value into a range header.



99
100
101
# File 'lib/protocol/http/header/range.rb', line 99

def self.coerce(value)
  self.parse(value.to_s)
end

.parse(value) ⇒ Object

Parse a raw range header value.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/protocol/http/header/range.rb', line 75

def self.parse(value)
  unless match = HEADER.match(value)
    raise ParseError, "Invalid range header: #{value.inspect}"
  end
  
  unit = match[:unit].downcase
  ranges = match[:ranges].split(SEPARATOR, -1)
  
  if ranges.empty? || ranges.any?(&:empty?)
    raise ParseError, "Invalid range set: #{match[:ranges].inspect}"
  end
  
  if unit == "bytes"
    ranges.map!{|range| ByteRange.parse(range)}
  elsif ranges.any?{|range| !OTHER_RANGE.match?(range)}
    raise ParseError, "Invalid range set: #{match[:ranges].inspect}"
  end
  
  return self.new(unit, ranges)
end

.trailer?Boolean

Whether this header is acceptable in HTTP trailers.

Returns:

  • (Boolean)


159
160
161
# File 'lib/protocol/http/header/range.rb', line 159

def self.trailer?
  false
end

Instance Method Details

#<<(value) ⇒ Object

Combine another raw range header value with this one.



139
140
141
142
143
144
145
146
147
148
149
# File 'lib/protocol/http/header/range.rb', line 139

def <<(value)
  other = self.class.parse(value)
  
  unless other.unit == @unit
    raise ParseError, "Cannot combine range units: #{@unit.inspect} and #{other.unit.inspect}"
  end
  
  @ranges.concat(other.ranges)
  
  return self
end

#bytes?Boolean

Whether this header contains byte ranges.

Returns:

  • (Boolean)


119
120
121
# File 'lib/protocol/http/header/range.rb', line 119

def bytes?
  @unit == "bytes"
end

#resolve(size) ⇒ Object

Resolve all byte ranges against the selected representation size.

Raises:

  • (ArgumentError)


126
127
128
129
130
131
132
133
134
135
# File 'lib/protocol/http/header/range.rb', line 126

def resolve(size)
  unless bytes?
    raise ArgumentError, "Cannot resolve #{@unit.inspect} ranges as byte ranges!"
  end
  
  size = Integer(size)
  raise ArgumentError, "Size must not be negative!" if size < 0
  
  @ranges.filter_map{|range| range.resolve(size)}
end

#to_sObject

Convert this header to its wire representation.



153
154
155
# File 'lib/protocol/http/header/range.rb', line 153

def to_s
  "#{@unit}=#{@ranges.join(",")}"
end