11# frozen_string_literal: false
2- # The HTTPHeader module defines methods for reading and writing
3- # HTTP headers.
42#
5- # It is used as a mixin by other classes, to provide hash-like
6- # access to HTTP header values. Unlike raw hash access, HTTPHeader
7- # provides access via case-insensitive keys. It also provides
8- # methods for accessing commonly-used HTTP header values in more
9- # convenient formats.
3+ # The \HTTPHeader module provides access to \HTTP headers.
4+ # The headers are a hash-like collection of key/value pairs called _fields_.
5+ #
6+ # The module is included in:
7+ #
8+ # - Net::HTTPGenericRequest (and therefore Net::HTTPRequest).
9+ # - Net::HTTPResponse.
10+ #
11+ # == About the Examples
12+ #
13+ # :include: doc/net-http/examples.rdoc
14+ #
15+ # == Fields
16+ #
17+ # A header field is a key/value pair.
18+ #
19+ # === Field Keys
20+ #
21+ # A field key may be:
22+ #
23+ # - A string: Key <tt>'Accept'</tt> is treated as if it were
24+ # <tt>'Accept'.downcase</tt>; i.e., <tt>'accept'</tt>.
25+ # - A symbol: Key <tt>:Accept</tt> is treated as if it were
26+ # <tt>:Accept.to_s.downcase</tt>; i.e., <tt>'accept'</tt>.
27+ #
28+ # Examples:
29+ #
30+ # req = Net::HTTP::Get.new(uri)
31+ # req[:accept] # => "*/*"
32+ # req['Accept'] # => "*/*"
33+ # req['ACCEPT'] # => "*/*"
34+ #
35+ # req['accept'] = 'text/html'
36+ # req[:accept] = 'text/html'
37+ # req['ACCEPT'] = 'text/html'
38+ #
39+ # === Field Values
40+ #
41+ # A field value may be returned as an array of strings or as a string:
42+ #
43+ # - These methods return field values as arrays:
44+ #
45+ # - #get_fields: Returns the array value for the given key,
46+ # or +nil+ if it does not exist.
47+ # - #to_hash: Returns a hash of all header fields:
48+ # each key is a field name; its value is the array value for the field.
49+ #
50+ # - These methods return field values as string;
51+ # the string value for a field is equivalent to
52+ # <tt>self[key.downcase.to_s].join(', '))</tt>:
53+ #
54+ # - #[]: Returns the string value for the given key,
55+ # or +nil+ if it does not exist.
56+ # - #fetch: Like #[], but accepts a default value
57+ # to be returned if the key does not exist.
58+ #
59+ # The field value may be set:
60+ #
61+ # - #[]=: Sets the value for the given key;
62+ # the given value may be a string, a symbol, an array, or a hash.
63+ # - #add_field: Adds a given value to a value for the given key
64+ # (not overwriting the existing value).
65+ # - #delete: Deletes the field for the given key.
66+ #
67+ # Example field values:
68+ #
69+ # - \String:
70+ #
71+ # req['Accept'] = 'text/html' # => "text/html"
72+ # req['Accept'] # => "text/html"
73+ # req.get_fields('Accept') # => ["text/html"]
74+ #
75+ # - \Symbol:
76+ #
77+ # req['Accept'] = :text # => :text
78+ # req['Accept'] # => "text"
79+ # req.get_fields('Accept') # => ["text"]
80+ #
81+ # - Simple array:
82+ #
83+ # req[:foo] = %w[bar baz bat]
84+ # req[:foo] # => "bar, baz, bat"
85+ # req.get_fields(:foo) # => ["bar", "baz", "bat"]
86+ #
87+ # - Simple hash:
88+ #
89+ # req[:foo] = {bar: 0, baz: 1, bat: 2}
90+ # req[:foo] # => "bar, 0, baz, 1, bat, 2"
91+ # req.get_fields(:foo) # => ["bar", "0", "baz", "1", "bat", "2"]
92+ #
93+ # - Nested:
94+ #
95+ # req[:foo] = [%w[bar baz], {bat: 0, bam: 1}]
96+ # req[:foo] # => "bar, baz, bat, 0, bam, 1"
97+ # req.get_fields(:foo) # => ["bar", "baz", "bat", "0", "bam", "1"]
98+ #
99+ # req[:foo] = {bar: %w[baz bat], bam: {bah: 0, bad: 1}}
100+ # req[:foo] # => "bar, baz, bat, bam, bah, 0, bad, 1"
101+ # req.get_fields(:foo) # => ["bar", "baz", "bat", "bam", "bah", "0", "bad", "1"]
102+ #
103+ # == Convenience Methods
104+ #
105+ # Various convenience methods retrieve values, set values, query values,
106+ # set form values, or iterate over fields.
107+ #
108+ # === Getters
109+ #
110+ # - #[]: Returns the string value for the given field.
111+ # - #content_length: Returns the integer value of field <tt>'Content-Length'</tt>.
112+ # - #content_range: Returns the Range value of field <tt>'Content-Range'</tt>.
113+ # - #content_type: Returns the string value of field <tt>'Content-Type'</tt>.
114+ # - #main_type: Returns first part of the string value of field <tt>'Content-Type'</tt>.
115+ # - #sub_type: Returns second part of the string value of field <tt>'Content-Type'</tt>.
116+ # - #range: Returns an array of Range objects of field <tt>'Range'</tt>, or +nil+.
117+ # - #range_length: Returns the integer length of the range given in field <tt>'Content-Range'</tt>.
118+ # - #type_params: Returns the string parameters for <tt>'Content-Type'</tt>.
119+ #
120+ # === Setters
121+ #
122+ # - #[]=: Sets the string or array value for the given field.
123+ # - #basic_auth: Sets the string authorization header for <tt>'Authorization'</tt>.
124+ # - #content_length=: Sets the integer length for field <tt>'Content-Length</tt>.
125+ # - #content_type=: Sets the string value for field <tt>'Content-Type'</tt>.
126+ # - #proxy_basic_auth: Sets the string authorization header for <tt>'Proxy-Authorization'</tt>.
127+ # - #range=: Sets the value for field +'Range'+.
128+ #
129+ # === Queries
130+ #
131+ # - #chunked?: Returns whether field <tt>'Transfer-Encoding'</tt> is set to <tt>'chunked'</tt>.
132+ # - #connection_close?: Returns whether field <tt>'Connection'</tt> is set to <tt>'close'</tt>.
133+ # - #connection_keep_alive?: Returns whether field <tt>'Connection'</tt> is set to <tt>'keep-alive'</tt>.
134+ # - #key?: Returns whether a given field exists.
135+ #
136+ # === Form Setters
137+ #
138+ # - #set_form: Sets an HTML form data set.
139+ # - #set_form_data: Sets header fields and a body from HTML form data.
140+ #
141+ # === Iterators
142+ #
143+ # - #each_capitalized: Passes each field capitalized-name/value pair to the block.
144+ # - #each_capitalized_name: Passes each capitalized field name to the block.
145+ # - #each_header: Passes each field name/value pair to the block.
146+ # - #each_name: Passes each field name to the block.
147+ # - #each_value: Passes each field value to the block.
10148#
11149module Net ::HTTPHeader
12150
13- def initialize_http_header ( initheader )
151+ def initialize_http_header ( initheader ) #:nodoc:
14152 @header = { }
15153 return unless initheader
16154 initheader . each do |key , value |
@@ -33,14 +171,30 @@ def size #:nodoc: obsolete
33171
34172 alias length size #:nodoc: obsolete
35173
36- # Returns the header field corresponding to the case-insensitive key.
37- # For example, a key of "Content-Type" might return "text/html"
174+ # Returns the string field value for the case-insensitive field +key+,
175+ # or +nil+ if there is no such key;
176+ # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
177+ #
178+ # req = Net::HTTP::Get.new(uri)
179+ # req['Accept'] # => "*/*"
180+ # req['Foo'] = %w[bar baz bat]
181+ # req['Foo'] # => "bar, baz, bat"
182+ # res['Nosuch'] # => nil
183+ #
38184 def []( key )
39185 a = @header [ key . downcase . to_s ] or return nil
40186 a . join ( ', ' )
41187 end
42188
43- # Sets the header field corresponding to the case-insensitive key.
189+ # Sets the value for the case-insensitive +key+ to +val+,
190+ # overwriting the previous value if the field exists;
191+ # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
192+ #
193+ # req = Net::HTTP::Get.new(uri)
194+ # req['Accept'] # => "*/*"
195+ # req['Accept'] = 'text/html'
196+ # req['Accept'] # => "text/html"
197+ #
44198 def []=( key , val )
45199 unless val
46200 @header . delete key . downcase . to_s
@@ -49,20 +203,18 @@ def []=(key, val)
49203 set_field ( key , val )
50204 end
51205
52- # [Ruby 1.8.3]
53- # Adds a value to a named header field, instead of replacing its value.
54- # Second argument +val+ must be a String.
55- # See also #[]=, #[] and #get_fields.
206+ # Adds value +val+ to the value array for field +key+ if the field exists;
207+ # creates the field with the given +key+ and +val+ if it does not exist.
208+ # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
56209 #
57- # request.add_field 'X-My-Header', 'a'
58- # p request['X-My-Header'] #=> "a"
59- # p request.get_fields('X-My-Header') #=> ["a"]
60- # request.add_field 'X-My-Header', 'b'
61- # p request['X-My-Header'] #=> "a, b"
62- # p request.get_fields('X-My-Header') #=> ["a", "b"]
63- # request.add_field 'X-My-Header', 'c'
64- # p request['X-My-Header'] #=> "a, b, c"
65- # p request.get_fields('X-My-Header') #=> ["a", "b", "c"]
210+ # req = Net::HTTP::Get.new(uri)
211+ # req.add_field('Foo', 'bar')
212+ # req['Foo'] # => "bar"
213+ # req.add_field('Foo', 'baz')
214+ # req['Foo'] # => "bar, baz"
215+ # req.add_field('Foo', %w[baz bam])
216+ # req['Foo'] # => "bar, baz, baz, bam"
217+ # req.get_fields('Foo') # => ["bar", "baz", "baz", "bam"]
66218 #
67219 def add_field ( key , val )
68220 stringified_downcased_key = key . downcase . to_s
@@ -101,41 +253,65 @@ def add_field(key, val)
101253 end
102254 end
103255
104- # [Ruby 1.8.3]
105- # Returns an array of header field strings corresponding to the
106- # case-insensitive +key+. This method allows you to get duplicated
107- # header fields without any processing. See also #[].
256+ # Returns the array field value for the given +key+,
257+ # or +nil+ if there is no such field;
258+ # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
108259 #
109- # p response.get_fields('Set-Cookie')
110- # #=> ["session=al98axx; expires=Fri, 31-Dec-1999 23:58:23",
111- # "query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"]
112- # p response['Set-Cookie']
113- # #=> "session=al98axx; expires=Fri, 31-Dec-1999 23:58:23, query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"
260+ # req = Net::HTTP::Get.new(uri)
261+ # req['Foo'] = 'bar'
262+ # req.get_fields('Foo') # => ["bar"]
263+ # req.add_field('Foo', 'baz')
264+ # req.get_fields('Foo') # => ["bar", "baz"]
265+ # req.get_fields('Nosuch') # => nil
114266 #
115267 def get_fields ( key )
116268 stringified_downcased_key = key . downcase . to_s
117269 return nil unless @header [ stringified_downcased_key ]
118270 @header [ stringified_downcased_key ] . dup
119271 end
120272
121- # Returns the header field corresponding to the case-insensitive key.
122- # Returns the default value +args+, or the result of the block, or
123- # raises an IndexError if there's no header field named +key+
124- # See Hash#fetch
273+ # :call-seq
274+ # fetch(key, default_val = nil) {|key| ... } -> object
275+ # fetch(key, default_val = nil) -> value or default_val
276+ #
277+ # With a block, returns the string value for +key+ if it exists;
278+ # otherwise returns the value of the block;
279+ # ignores the +default_val+;
280+ # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
281+ #
282+ # req = Net::HTTP::Get.new(uri)
283+ # req['Foo'] = 'bar'
284+ # req.fetch('Foo') {|key| key.capitalize } # => "bar"
285+ # req.fetch('Nosuch') {|key| key.capitalize } # => "Nosuch"
286+ #
287+ # With no block, returns the string value for +key+ if it exists;
288+ # otherwise, returns +default_val+ if it was given;
289+ # otherwise raises an exception:
290+ #
291+ # req.fetch('Foo') # => "bar"
292+ # req.fetch('Nosuch', :baz) # => :baz
293+ # req.fetch('Nosuch') # Raises KeyError.
294+ #
125295 def fetch ( key , *args , &block ) #:yield: +key+
126296 a = @header . fetch ( key . downcase . to_s , *args , &block )
127297 a . kind_of? ( Array ) ? a . join ( ', ' ) : a
128298 end
129299
130- # Iterates through the header names and values, passing in the name
131- # and value to the code block supplied.
300+ # Calls the block with each key/value pair:
132301 #
133- # Returns an enumerator if no block is given.
302+ # req = Net::HTTP::Get.new(uri)
303+ # req.each_header {|key, value| p [key, value] }
134304 #
135- # Example :
305+ # Output :
136306 #
137- # response.header.each_header {|key,value| puts "#{key} = #{value}" }
307+ # ["accept-encoding", "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"]
308+ # ["accept", "*/*"]
309+ # ["user-agent", "Ruby"]
310+ # ["host", "jsonplaceholder.typicode.com"]
311+ #
312+ # Returns an enumerator if no block is given.
138313 #
314+ # Net::HTTPHeader#each is an alias for Net::HTTPHeader#each_header.
139315 def each_header #:yield: +key+, +value+
140316 block_given? or return enum_for ( __method__ ) { @header . size }
141317 @header . each do |k , va |
@@ -145,23 +321,42 @@ def each_header #:yield: +key+, +value+
145321
146322 alias each each_header
147323
148- # Iterates through the header names in the header, passing
149- # each header name to the code block.
324+ # Calls the block with each field key:
325+ #
326+ # req = Net::HTTP::Get.new(uri)
327+ # req.each_key {|key| p key }
328+ #
329+ # Output:
330+ #
331+ # "accept-encoding"
332+ # "accept"
333+ # "user-agent"
334+ # "host"
150335 #
151336 # Returns an enumerator if no block is given.
337+ #
338+ # Net::HTTPHeader#each_name is an alias for Net::HTTPHeader#each_key.
152339 def each_name ( &block ) #:yield: +key+
153340 block_given? or return enum_for ( __method__ ) { @header . size }
154341 @header . each_key ( &block )
155342 end
156343
157344 alias each_key each_name
158345
159- # Iterates through the header names in the header, passing
160- # capitalized header names to the code block.
346+ # Calls the block with each capitalized field name:
161347 #
162- # Note that header names are capitalized systematically;
163- # capitalization may not match that used by the remote HTTP
164- # server in its response.
348+ # req = Net::HTTP::Get.new(uri)
349+ # req.each_capitalized_name {|key| p key }
350+ #
351+ # Output:
352+ #
353+ # "Accept-Encoding"
354+ # "Accept"
355+ # "User-Agent"
356+ # "Host"
357+ #
358+ # The capitalization is system-dependent;
359+ # see {Case Mapping}[https://docs.ruby-lang.org/en/master/case_mapping_rdoc.html].
165360 #
166361 # Returns an enumerator if no block is given.
167362 def each_capitalized_name #:yield: +key+
@@ -208,6 +403,8 @@ def to_hash
208403 # server in its response.
209404 #
210405 # Returns an enumerator if no block is given.
406+ #
407+ # Net::HTTPHeader#canonical_each is an alias for Net::HTTPHeader#each_capitalized.
211408 def each_capitalized
212409 block_given? or return enum_for ( __method__ ) { @header . size }
213410 @header . each do |k , v |
@@ -394,7 +591,9 @@ def type_params
394591 # Sets the content type in an HTTP header.
395592 # The +type+ should be a full HTTP content type, e.g. "text/html".
396593 # The +params+ are an optional Hash of parameters to add after the
397- # content type, e.g. {'charset' => 'iso-8859-1'}
594+ # content type, e.g. {'charset' => 'iso-8859-1'}.
595+ #
596+ # Net::HTTPHeader#content_type= is an alias for Net::HTTPHeader#set_content_type.
398597 def set_content_type ( type , params = { } )
399598 @header [ 'content-type' ] = [ type + params . map { |k , v |"; #{ k } =#{ v } " } . join ( '' ) ]
400599 end
@@ -414,6 +613,7 @@ def set_content_type(type, params = {})
414613 # http.form_data = {"q" => ["ruby", "perl"], "lang" => "en"}
415614 # http.set_form_data({"q" => "ruby", "lang" => "en"}, ';')
416615 #
616+ # Net::HTTPHeader#form_data= is an alias for Net::HTTPHeader#set_form_data.
417617 def set_form_data ( params , sep = '&' )
418618 query = URI . encode_www_form ( params )
419619 query . gsub! ( /&/ , sep ) if sep != '&'
0 commit comments