Class: Protocol::HTTP::Headers

Inherits:
Object
  • Object
show all
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
MERGE_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,
  
  'connection' => Header::Connection,
  
  # Headers specifically for proxies:
  'via' => Split,
  'x-forwarded-for' => Split,
  
  # 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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fields = nil, indexed = nil) ⇒ Headers



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/protocol/http/headers.rb', line 39

def initialize(fields = nil, indexed = nil)
  if fields
    @fields = fields.dup
  else
    @fields = []
  end
  
  if indexed
    @indexed = indexed.dup
  else
    @indexed = nil
  end
end

Instance Attribute Details

#fieldsObject (readonly)

An array of ‘[key, value]` pairs.



63
64
65
# File 'lib/protocol/http/headers.rb', line 63

def fields
  @fields
end

Class Method Details

.[](hash) ⇒ Object



35
36
37
# File 'lib/protocol/http/headers.rb', line 35

def self.[] hash
  self.new(hash.to_a)
end

Instance Method Details

#==(other) ⇒ Object



219
220
221
222
223
224
225
226
227
228
# File 'lib/protocol/http/headers.rb', line 219

def == other
  case other
  when Hash
    to_h == other
  when Headers
    @fields == other.fields
  else
    @fields == other
  end
end

#[](key) ⇒ Object



202
203
204
# File 'lib/protocol/http/headers.rb', line 202

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.



125
126
127
128
129
130
131
# File 'lib/protocol/http/headers.rb', line 125

def []= key, value
  if @indexed
    merge_into(@indexed, key.downcase, value)
  end
  
  @fields << [key, value]
end

#add(key, value) ⇒ Object



106
107
108
# File 'lib/protocol/http/headers.rb', line 106

def add(key, value)
  self[key] = value
end

#clearObject



57
58
59
60
# File 'lib/protocol/http/headers.rb', line 57

def clear
  @fields.clear
  @indexed = nil
end

#delete(key) ⇒ Object

Delete all headers with the given key, and return the merged value.



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/protocol/http/headers.rb', line 165

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 = MERGE_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

#dupObject



53
54
55
# File 'lib/protocol/http/headers.rb', line 53

def dup
  self.class.new(@fields, @indexed)
end

#each(&block) ⇒ Object



81
82
83
# File 'lib/protocol/http/headers.rb', line 81

def each(&block)
  @fields.each(&block)
end

#empty?Boolean



77
78
79
# File 'lib/protocol/http/headers.rb', line 77

def empty?
  @fields.empty?
end

#extract(keys) ⇒ Object Also known as: slice!



89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/protocol/http/headers.rb', line 89

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

#freezeObject



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/protocol/http/headers.rb', line 65

def freeze
  return if frozen?
  
  # Ensure @indexed is generated:
  self.to_h
  
  @fields.freeze
  @indexed.freeze
  
  super
end

#include?(key) ⇒ Boolean



85
86
87
# File 'lib/protocol/http/headers.rb', line 85

def include? key
  self[key] != nil
end

#inspectObject



215
216
217
# File 'lib/protocol/http/headers.rb', line 215

def inspect
  "#<#{self.class} #{@fields.inspect}>"
end

#merge(headers) ⇒ Object



118
119
120
# File 'lib/protocol/http/headers.rb', line 118

def merge(headers)
  self.dup.merge!(headers)
end

#merge!(headers) ⇒ Object



110
111
112
113
114
115
116
# File 'lib/protocol/http/headers.rb', line 110

def merge!(headers)
  headers.each do |key, value|
    self[key] = value
  end
  
  return self
end

#to_hObject

A hash table of ‘policy.map(values)`



207
208
209
210
211
212
213
# File 'lib/protocol/http/headers.rb', line 207

def to_h
  @indexed ||= @fields.inject({}) do |hash, (key, value)|
    merge_into(hash, key.downcase, value)
    
    hash
  end
end