Class: Protocol::HTTP::Headers
- Inherits:
-
Object
- Object
- Protocol::HTTP::Headers
- Defined in:
- lib/protocol/http/headers.rb
Overview
Headers are an array of key-value pairs. Some header keys represent multiple values.
Defined Under Namespace
Classes: Merged
Constant Summary collapse
- Split =
Header::Split
- Multiple =
Header::Multiple
- TRAILERS =
'trailers'
- POLICY =
{ # Headers which may only be specified once. 'content-type' => false, 'content-disposition' => false, 'content-length' => false, 'user-agent' => false, 'referer' => false, 'host' => false, 'authorization' => false, 'proxy-authorization' => false, 'if-modified-since' => false, 'if-unmodified-since' => false, 'from' => false, 'location' => false, 'max-forwards' => false, # Custom headers: 'connection' => Header::Connection, 'cache-control' => Header::CacheControl, 'vary' => Header::Vary, # Headers specifically for proxies: 'via' => Split, 'x-forwarded-for' => Split, # Cache validations: 'etag' => Header::ETag, 'if-match' => Header::ETags, 'if-none-match' => Header::ETags, # Headers which may be specified multiple times, but which can't be concatenated: 'www-authenticate' => Multiple, 'proxy-authenticate' => Multiple, # Custom headers: 'set-cookie' => Header::SetCookie, 'cookie' => Header::Cookie, }.tap{|hash| hash.default = Split}
Instance Attribute Summary collapse
-
#fields ⇒ Object
readonly
An array of ‘[key, value]` pairs.
Class Method Summary collapse
-
.[](headers) ⇒ Headers
Construct an instance from a headers Array or Hash.
Instance Method Summary collapse
- #==(other) ⇒ Object
- #[](key) ⇒ Object
-
#[]=(key, value) ⇒ Object
Append the value to the given key.
-
#add(key, value = nil) { ... } ⇒ Object
Add the specified header key value pair.
- #clear ⇒ Object
-
#delete(key) ⇒ Object
Delete all headers with the given key, and return the merged value.
- #each(&block) ⇒ Object
- #empty? ⇒ Boolean
- #extract(keys) ⇒ Object
- #flatten! ⇒ Object
- #freeze ⇒ Object
- #include?(key) ⇒ Boolean
-
#initialize(fields = [], indexed = nil) ⇒ Headers
constructor
A new instance of Headers.
- #initialize_dup(other) ⇒ Object
- #inspect ⇒ Object
- #keys ⇒ Object
- #merge(headers) ⇒ Object
- #merge!(headers) ⇒ Object
-
#set(key, value) ⇒ Object
Set the specified header key to the specified value, replacing any existing header keys with the same name.
-
#to_h ⇒ Object
A hash table of ‘policy.map(values)`.
-
#trailers(&block) ⇒ Object
Enumerate all trailers, including evaluating all deferred headers.
-
#trailers! ⇒ Object
Mark the subsequent headers as trailers.
-
#trailers? ⇒ Boolean
The trailers if there are any.
Constructor Details
#initialize(fields = [], indexed = nil) ⇒ Headers
Returns a new instance of Headers.
50 51 52 53 54 55 56 57 |
# File 'lib/protocol/http/headers.rb', line 50 def initialize(fields = [], indexed = nil) @fields = fields @indexed = indexed # Marks where trailers start in the @fields array. @tail = nil @deferred = [] end |
Instance Attribute Details
#fields ⇒ Object (readonly)
An array of ‘[key, value]` pairs.
75 76 77 |
# File 'lib/protocol/http/headers.rb', line 75 def fields @fields end |
Class Method Details
.[](headers) ⇒ Headers
Construct an instance from a headers Array or Hash. No-op if already an instance of ‘Headers`.
42 43 44 45 46 47 48 |
# File 'lib/protocol/http/headers.rb', line 42 def self.[] headers if headers.is_a?(self) headers else self.new(headers.to_a) end end |
Instance Method Details
#==(other) ⇒ Object
300 301 302 303 304 305 306 307 308 309 |
# File 'lib/protocol/http/headers.rb', line 300 def == other case other when Hash to_h == other when Headers @fields == other.fields else @fields == other end end |
#[](key) ⇒ Object
283 284 285 |
# File 'lib/protocol/http/headers.rb', line 283 def [] key to_h[key] end |
#[]=(key, value) ⇒ Object
Append the value to the given key. Some values can be appended multiple times, others can only be set once.
198 199 200 201 202 203 204 |
# File 'lib/protocol/http/headers.rb', line 198 def []= key, value if @indexed merge_into(@indexed, key.downcase, value) end @fields << [key, value] end |
#add(key, value = nil) { ... } ⇒ Object
Add the specified header key value pair.
165 166 167 168 169 170 171 172 |
# File 'lib/protocol/http/headers.rb', line 165 def add(key, value = nil, &block) if block_given? @deferred << [key, block] self[TRAILERS] = key else self[key] = value end end |
#clear ⇒ Object
67 68 69 70 71 72 |
# File 'lib/protocol/http/headers.rb', line 67 def clear @fields.clear @indexed = nil @tail = nil @deferred.clear end |
#delete(key) ⇒ Object
Delete all headers with the given key, and return the merged value.
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/protocol/http/headers.rb', line 246 def delete(key) deleted, @fields = @fields.partition do |field| field.first.downcase == key end if deleted.empty? return nil end if @indexed return @indexed.delete(key) elsif policy = POLICY[key] (key, value), *tail = deleted merged = policy.new(value) tail.each{|k,v| merged << v} return merged else key, value = deleted.last return value end end |
#each(&block) ⇒ Object
135 136 137 |
# File 'lib/protocol/http/headers.rb', line 135 def each(&block) @fields.each(&block) end |
#empty? ⇒ Boolean
131 132 133 |
# File 'lib/protocol/http/headers.rb', line 131 def empty? @fields.empty? end |
#extract(keys) ⇒ Object
147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/protocol/http/headers.rb', line 147 def extract(keys) deleted, @fields = @fields.partition do |field| keys.include?(field.first.downcase) end if @indexed keys.each do |key| @indexed.delete(key) end end return deleted end |
#flatten! ⇒ Object
87 88 89 90 91 92 93 94 95 |
# File 'lib/protocol/http/headers.rb', line 87 def flatten! unless @deferred.empty? @tail ||= @fields.size @deferred.each do |key, value| self.add(key, value.call) end end end |
#freeze ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/protocol/http/headers.rb', line 110 def freeze return if frozen? # Ensure all deferred headers are evaluated: self.flatten! # Ensure @indexed is generated: self.to_h # Remove all trailers: self.delete(TRAILERS) # No longer has stateful trailers: @tail = nil @fields.freeze @indexed.freeze super end |
#include?(key) ⇒ Boolean
139 140 141 |
# File 'lib/protocol/http/headers.rb', line 139 def include? key self[key] != nil end |
#initialize_dup(other) ⇒ Object
59 60 61 62 63 64 65 |
# File 'lib/protocol/http/headers.rb', line 59 def initialize_dup(other) super @fields = @fields.dup @indexed = @indexed.dup @deferred = @deferred.dup end |
#inspect ⇒ Object
296 297 298 |
# File 'lib/protocol/http/headers.rb', line 296 def inspect "#<#{self.class} #{@fields.inspect}>" end |
#keys ⇒ Object
143 144 145 |
# File 'lib/protocol/http/headers.rb', line 143 def keys self.to_h.keys end |
#merge(headers) ⇒ Object
191 192 193 |
# File 'lib/protocol/http/headers.rb', line 191 def merge(headers) self.dup.merge!(headers) end |
#merge!(headers) ⇒ Object
183 184 185 186 187 188 189 |
# File 'lib/protocol/http/headers.rb', line 183 def merge!(headers) headers.each do |key, value| self[key] = value end return self end |
#set(key, value) ⇒ Object
Set the specified header key to the specified value, replacing any existing header keys with the same name.
177 178 179 180 181 |
# File 'lib/protocol/http/headers.rb', line 177 def set(key, value) # TODO This could be a bit more efficient: self.delete(key) self.add(key, value) end |
#to_h ⇒ Object
A hash table of ‘policy.map(values)`
288 289 290 291 292 293 294 |
# File 'lib/protocol/http/headers.rb', line 288 def to_h @indexed ||= @fields.inject({}) do |hash, (key, value)| merge_into(hash, key.downcase, value) hash end end |
#trailers(&block) ⇒ Object
Enumerate all trailers, including evaluating all deferred headers.
98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/protocol/http/headers.rb', line 98 def trailers(&block) return nil unless self.include?(TRAILERS) return to_enum(:trailers) unless block_given? flatten! if @tail @fields.drop(@tail).each(&block) end end |
#trailers! ⇒ Object
Mark the subsequent headers as trailers.
78 79 80 |
# File 'lib/protocol/http/headers.rb', line 78 def trailers! @tail ||= @fields.size end |
#trailers? ⇒ Boolean
Returns the trailers if there are any.
83 84 85 |
# File 'lib/protocol/http/headers.rb', line 83 def trailers? @tail != nil end |