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(Error)
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