1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
# frozen_string_literal: true
module HTTPX
class Headers
class << self
def new(headers = nil)
return headers if headers.is_a?(self)
super
end
end
def initialize(headers = nil)
if headers.nil? || headers.empty?
@headers = headers.to_h
return
end
@headers = {}
headers.each do |field, value|
field = downcased(field)
value = array_value(value)
current = @headers[field]
if current.nil?
@headers[field] = value
else
current.concat(value)
end
end
end
# cloned initialization
def initialize_clone(orig, **kwargs)
super
@headers = orig.instance_variable_get(:@headers).clone(**kwargs)
end
# dupped initialization
def initialize_dup(orig)
super
@headers = orig.instance_variable_get(:@headers).transform_values(&:dup)
end
# freezes the headers hash
def freeze
@headers.each_value(&:freeze).freeze
super
end
# merges headers with another header-quack.
# the merge rule is, if the header already exists,
# ignore what the +other+ headers has. Otherwise, set
#
def merge(other)
headers = dup
other.each do |field, value|
headers[downcased(field)] = value
end
headers
end
# returns the comma-separated values of the header field
# identified by +field+, or nil otherwise.
#
def [](field)
a = @headers[downcased(field)] || return
a.join(", ")
end
# sets +value+ (if not nil) as single value for the +field+ header.
#
def []=(field, value)
return unless value
@headers[downcased(field)] = array_value(value)
end
# deletes all values associated with +field+ header.
#
def delete(field)
canonical = downcased(field)
@headers.delete(canonical) if @headers.key?(canonical)
end
# adds additional +value+ to the existing, for header +field+.
#
def add(field, value)
(@headers[downcased(field)] ||= []) << String(value)
end
# helper to be used when adding an header field as a value to another field
#
# h2_headers.add_header("vary", "accept-encoding")
# h2_headers["vary"] #=> "accept-encoding"
# h1_headers.add_header("vary", "accept-encoding")
# h1_headers["vary"] #=> "Accept-Encoding"
#
alias_method :add_header, :add
# returns the enumerable headers store in pairs of header field + the values in
# the comma-separated string format
#
def each(extra_headers = nil)
return enum_for(__method__, extra_headers) { @headers.size } unless block_given?
@headers.each do |field, value|
yield(field, value.join(", ")) unless value.empty?
end
extra_headers.each do |field, value|
yield(field, value) unless value.empty?
end if extra_headers
end
def ==(other)
other == to_hash
end
def empty?
@headers.empty?
end
# the headers store in Hash format
def to_hash
Hash[to_a]
end
alias_method :to_h, :to_hash
# the headers store in array of pairs format
def to_a
Array(each)
end
# headers as string
def to_s
@headers.to_s
end
# :nocov:
def inspect
"#<#{self.class}:#{object_id} " \
"#{to_hash.inspect}>"
end
# :nocov:
# this is internal API and doesn't abide to other public API
# guarantees, like downcasing strings.
# Please do not use this outside of core!
#
def key?(downcased_key)
@headers.key?(downcased_key)
end
# returns the values for the +field+ header in array format.
# This method is more internal, and for this reason doesn't try
# to "correct" the user input, i.e. it doesn't downcase the key.
#
def get(field)
@headers[field] || EMPTY
end
private
def array_value(value)
Array(value)
end
def downcased(field)
String(field).downcase
end
end
end
|