Skip to content

Commit 5849e4e

Browse files
Merge pull request #79 from BurdetteLamar/header_doc
Expands class doc. Treats methods: #[] #[]= #add_field #get_fields #fetch #each_header #each_name #each_capitalized_name
2 parents f70889c + 86b0514 commit 5849e4e

File tree

1 file changed

+250
-50
lines changed

1 file changed

+250
-50
lines changed

lib/net/http/header.rb

Lines changed: 250 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,154 @@
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
#
11149
module 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

Comments
 (0)