net-http 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,186 @@
1
1
  # frozen_string_literal: false
2
- # The HTTPHeader module defines methods for reading and writing
3
- # HTTP headers.
4
2
  #
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
+ #
5
+ # The module is included in:
6
+ #
7
+ # - Net::HTTPGenericRequest (and therefore Net::HTTPRequest).
8
+ # - Net::HTTPResponse.
9
+ #
10
+ # The headers are a hash-like collection of key/value pairs called _fields_.
11
+ #
12
+ # == Request and Response Fields
13
+ #
14
+ # Headers may be included in:
15
+ #
16
+ # - A Net::HTTPRequest object:
17
+ # the object's headers will be sent with the request.
18
+ # Any fields may be defined in the request;
19
+ # see {Setters}[rdoc-ref:Net::HTTPHeader@Setters].
20
+ # - A Net::HTTPResponse object:
21
+ # the objects headers are usually those returned from the host.
22
+ # Fields may be retrieved from the object;
23
+ # see {Getters}[rdoc-ref:Net::HTTPHeader@Getters]
24
+ # and {Iterators}[rdoc-ref:Net::HTTPHeader@Iterators].
25
+ #
26
+ # Exactly which fields should be sent or expected depends on the host;
27
+ # see:
28
+ #
29
+ # - {Request fields}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields].
30
+ # - {Response fields}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Response_fields].
31
+ #
32
+ # == About the Examples
33
+ #
34
+ # :include: doc/net-http/examples.rdoc
35
+ #
36
+ # == Fields
37
+ #
38
+ # A header field is a key/value pair.
39
+ #
40
+ # === Field Keys
41
+ #
42
+ # A field key may be:
43
+ #
44
+ # - A string: Key <tt>'Accept'</tt> is treated as if it were
45
+ # <tt>'Accept'.downcase</tt>; i.e., <tt>'accept'</tt>.
46
+ # - A symbol: Key <tt>:Accept</tt> is treated as if it were
47
+ # <tt>:Accept.to_s.downcase</tt>; i.e., <tt>'accept'</tt>.
48
+ #
49
+ # Examples:
50
+ #
51
+ # req = Net::HTTP::Get.new(uri)
52
+ # req[:accept] # => "*/*"
53
+ # req['Accept'] # => "*/*"
54
+ # req['ACCEPT'] # => "*/*"
55
+ #
56
+ # req['accept'] = 'text/html'
57
+ # req[:accept] = 'text/html'
58
+ # req['ACCEPT'] = 'text/html'
59
+ #
60
+ # === Field Values
61
+ #
62
+ # A field value may be returned as an array of strings or as a string:
63
+ #
64
+ # - These methods return field values as arrays:
65
+ #
66
+ # - #get_fields: Returns the array value for the given key,
67
+ # or +nil+ if it does not exist.
68
+ # - #to_hash: Returns a hash of all header fields:
69
+ # each key is a field name; its value is the array value for the field.
70
+ #
71
+ # - These methods return field values as string;
72
+ # the string value for a field is equivalent to
73
+ # <tt>self[key.downcase.to_s].join(', '))</tt>:
74
+ #
75
+ # - #[]: Returns the string value for the given key,
76
+ # or +nil+ if it does not exist.
77
+ # - #fetch: Like #[], but accepts a default value
78
+ # to be returned if the key does not exist.
79
+ #
80
+ # The field value may be set:
81
+ #
82
+ # - #[]=: Sets the value for the given key;
83
+ # the given value may be a string, a symbol, an array, or a hash.
84
+ # - #add_field: Adds a given value to a value for the given key
85
+ # (not overwriting the existing value).
86
+ # - #delete: Deletes the field for the given key.
87
+ #
88
+ # Example field values:
89
+ #
90
+ # - \String:
91
+ #
92
+ # req['Accept'] = 'text/html' # => "text/html"
93
+ # req['Accept'] # => "text/html"
94
+ # req.get_fields('Accept') # => ["text/html"]
95
+ #
96
+ # - \Symbol:
97
+ #
98
+ # req['Accept'] = :text # => :text
99
+ # req['Accept'] # => "text"
100
+ # req.get_fields('Accept') # => ["text"]
101
+ #
102
+ # - Simple array:
103
+ #
104
+ # req[:foo] = %w[bar baz bat]
105
+ # req[:foo] # => "bar, baz, bat"
106
+ # req.get_fields(:foo) # => ["bar", "baz", "bat"]
107
+ #
108
+ # - Simple hash:
109
+ #
110
+ # req[:foo] = {bar: 0, baz: 1, bat: 2}
111
+ # req[:foo] # => "bar, 0, baz, 1, bat, 2"
112
+ # req.get_fields(:foo) # => ["bar", "0", "baz", "1", "bat", "2"]
113
+ #
114
+ # - Nested:
115
+ #
116
+ # req[:foo] = [%w[bar baz], {bat: 0, bam: 1}]
117
+ # req[:foo] # => "bar, baz, bat, 0, bam, 1"
118
+ # req.get_fields(:foo) # => ["bar", "baz", "bat", "0", "bam", "1"]
119
+ #
120
+ # req[:foo] = {bar: %w[baz bat], bam: {bah: 0, bad: 1}}
121
+ # req[:foo] # => "bar, baz, bat, bam, bah, 0, bad, 1"
122
+ # req.get_fields(:foo) # => ["bar", "baz", "bat", "bam", "bah", "0", "bad", "1"]
123
+ #
124
+ # == Convenience Methods
125
+ #
126
+ # Various convenience methods retrieve values, set values, query values,
127
+ # set form values, or iterate over fields.
128
+ #
129
+ # === Setters
130
+ #
131
+ # \Method #[]= can set any field, but does little to validate the new value;
132
+ # some of the other setter methods provide some validation:
133
+ #
134
+ # - #[]=: Sets the string or array value for the given key.
135
+ # - #add_field: Creates or adds to the array value for the given key.
136
+ # - #basic_auth: Sets the string authorization header for <tt>'Authorization'</tt>.
137
+ # - #content_length=: Sets the integer length for field <tt>'Content-Length</tt>.
138
+ # - #content_type=: Sets the string value for field <tt>'Content-Type'</tt>.
139
+ # - #proxy_basic_auth: Sets the string authorization header for <tt>'Proxy-Authorization'</tt>.
140
+ # - #set_range: Sets the value for field <tt>'Range'</tt>.
141
+ #
142
+ # === Form Setters
143
+ #
144
+ # - #set_form: Sets an HTML form data set.
145
+ # - #set_form_data: Sets header fields and a body from HTML form data.
146
+ #
147
+ # === Getters
148
+ #
149
+ # \Method #[] can retrieve the value of any field that exists,
150
+ # but always as a string;
151
+ # some of the other getter methods return something different
152
+ # from the simple string value:
153
+ #
154
+ # - #[]: Returns the string field value for the given key.
155
+ # - #content_length: Returns the integer value of field <tt>'Content-Length'</tt>.
156
+ # - #content_range: Returns the Range value of field <tt>'Content-Range'</tt>.
157
+ # - #content_type: Returns the string value of field <tt>'Content-Type'</tt>.
158
+ # - #fetch: Returns the string field value for the given key.
159
+ # - #get_fields: Returns the array field value for the given +key+.
160
+ # - #main_type: Returns first part of the string value of field <tt>'Content-Type'</tt>.
161
+ # - #sub_type: Returns second part of the string value of field <tt>'Content-Type'</tt>.
162
+ # - #range: Returns an array of Range objects of field <tt>'Range'</tt>, or +nil+.
163
+ # - #range_length: Returns the integer length of the range given in field <tt>'Content-Range'</tt>.
164
+ # - #type_params: Returns the string parameters for <tt>'Content-Type'</tt>.
165
+ #
166
+ # === Queries
167
+ #
168
+ # - #chunked?: Returns whether field <tt>'Transfer-Encoding'</tt> is set to <tt>'chunked'</tt>.
169
+ # - #connection_close?: Returns whether field <tt>'Connection'</tt> is set to <tt>'close'</tt>.
170
+ # - #connection_keep_alive?: Returns whether field <tt>'Connection'</tt> is set to <tt>'keep-alive'</tt>.
171
+ # - #key?: Returns whether a given key exists.
172
+ #
173
+ # === Iterators
174
+ #
175
+ # - #each_capitalized: Passes each field capitalized-name/value pair to the block.
176
+ # - #each_capitalized_name: Passes each capitalized field name to the block.
177
+ # - #each_header: Passes each field name/value pair to the block.
178
+ # - #each_name: Passes each field name to the block.
179
+ # - #each_value: Passes each string field value to the block.
10
180
  #
11
181
  module Net::HTTPHeader
12
182
 
13
- def initialize_http_header(initheader)
183
+ def initialize_http_header(initheader) #:nodoc:
14
184
  @header = {}
15
185
  return unless initheader
16
186
  initheader.each do |key, value|
@@ -33,14 +203,32 @@ module Net::HTTPHeader
33
203
 
34
204
  alias length size #:nodoc: obsolete
35
205
 
36
- # Returns the header field corresponding to the case-insensitive key.
37
- # For example, a key of "Content-Type" might return "text/html"
206
+ # Returns the string field value for the case-insensitive field +key+,
207
+ # or +nil+ if there is no such key;
208
+ # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
209
+ #
210
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
211
+ # res['Connection'] # => "keep-alive"
212
+ # res['Nosuch'] # => nil
213
+ #
214
+ # Note that some field values may be retrieved via convenience methods;
215
+ # see {Getters}[rdoc-ref:Net::HTTPHeader@Getters].
38
216
  def [](key)
39
217
  a = @header[key.downcase.to_s] or return nil
40
218
  a.join(', ')
41
219
  end
42
220
 
43
- # Sets the header field corresponding to the case-insensitive key.
221
+ # Sets the value for the case-insensitive +key+ to +val+,
222
+ # overwriting the previous value if the field exists;
223
+ # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
224
+ #
225
+ # req = Net::HTTP::Get.new(uri)
226
+ # req['Accept'] # => "*/*"
227
+ # req['Accept'] = 'text/html'
228
+ # req['Accept'] # => "text/html"
229
+ #
230
+ # Note that some field values may be set via convenience methods;
231
+ # see {Setters}[rdoc-ref:Net::HTTPHeader@Setters].
44
232
  def []=(key, val)
45
233
  unless val
46
234
  @header.delete key.downcase.to_s
@@ -49,20 +237,18 @@ module Net::HTTPHeader
49
237
  set_field(key, val)
50
238
  end
51
239
 
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.
240
+ # Adds value +val+ to the value array for field +key+ if the field exists;
241
+ # creates the field with the given +key+ and +val+ if it does not exist.
242
+ # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
56
243
  #
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"]
244
+ # req = Net::HTTP::Get.new(uri)
245
+ # req.add_field('Foo', 'bar')
246
+ # req['Foo'] # => "bar"
247
+ # req.add_field('Foo', 'baz')
248
+ # req['Foo'] # => "bar, baz"
249
+ # req.add_field('Foo', %w[baz bam])
250
+ # req['Foo'] # => "bar, baz, baz, bam"
251
+ # req.get_fields('Foo') # => ["bar", "baz", "baz", "bam"]
66
252
  #
67
253
  def add_field(key, val)
68
254
  stringified_downcased_key = key.downcase.to_s
@@ -101,16 +287,13 @@ module Net::HTTPHeader
101
287
  end
102
288
  end
103
289
 
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 #[].
290
+ # Returns the array field value for the given +key+,
291
+ # or +nil+ if there is no such field;
292
+ # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
108
293
  #
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"
294
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
295
+ # res.get_fields('Connection') # => ["keep-alive"]
296
+ # res.get_fields('Nosuch') # => nil
114
297
  #
115
298
  def get_fields(key)
116
299
  stringified_downcased_key = key.downcase.to_s
@@ -118,24 +301,58 @@ module Net::HTTPHeader
118
301
  @header[stringified_downcased_key].dup
119
302
  end
120
303
 
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
304
+ # call-seq:
305
+ # fetch(key, default_val = nil) {|key| ... } -> object
306
+ # fetch(key, default_val = nil) -> value or default_val
307
+ #
308
+ # With a block, returns the string value for +key+ if it exists;
309
+ # otherwise returns the value of the block;
310
+ # ignores the +default_val+;
311
+ # see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
312
+ #
313
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
314
+ #
315
+ # # Field exists; block not called.
316
+ # res.fetch('Connection') do |value|
317
+ # fail 'Cannot happen'
318
+ # end # => "keep-alive"
319
+ #
320
+ # # Field does not exist; block called.
321
+ # res.fetch('Nosuch') do |value|
322
+ # value.downcase
323
+ # end # => "nosuch"
324
+ #
325
+ # With no block, returns the string value for +key+ if it exists;
326
+ # otherwise, returns +default_val+ if it was given;
327
+ # otherwise raises an exception:
328
+ #
329
+ # res.fetch('Connection', 'Foo') # => "keep-alive"
330
+ # res.fetch('Nosuch', 'Foo') # => "Foo"
331
+ # res.fetch('Nosuch') # Raises KeyError.
332
+ #
125
333
  def fetch(key, *args, &block) #:yield: +key+
126
334
  a = @header.fetch(key.downcase.to_s, *args, &block)
127
335
  a.kind_of?(Array) ? a.join(', ') : a
128
336
  end
129
337
 
130
- # Iterates through the header names and values, passing in the name
131
- # and value to the code block supplied.
338
+ # Calls the block with each key/value pair:
132
339
  #
133
- # Returns an enumerator if no block is given.
340
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
341
+ # res.each_header do |key, value|
342
+ # p [key, value] if key.start_with?('c')
343
+ # end
134
344
  #
135
- # Example:
345
+ # Output:
136
346
  #
137
- # response.header.each_header {|key,value| puts "#{key} = #{value}" }
347
+ # ["content-type", "application/json; charset=utf-8"]
348
+ # ["connection", "keep-alive"]
349
+ # ["cache-control", "max-age=43200"]
350
+ # ["cf-cache-status", "HIT"]
351
+ # ["cf-ray", "771d17e9bc542cf5-ORD"]
352
+ #
353
+ # Returns an enumerator if no block is given.
138
354
  #
355
+ # Net::HTTPHeader#each is an alias for Net::HTTPHeader#each_header.
139
356
  def each_header #:yield: +key+, +value+
140
357
  block_given? or return enum_for(__method__) { @header.size }
141
358
  @header.each do |k,va|
@@ -145,10 +362,24 @@ module Net::HTTPHeader
145
362
 
146
363
  alias each each_header
147
364
 
148
- # Iterates through the header names in the header, passing
149
- # each header name to the code block.
365
+ # Calls the block with each field key:
366
+ #
367
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
368
+ # res.each_key do |key|
369
+ # p key if key.start_with?('c')
370
+ # end
371
+ #
372
+ # Output:
373
+ #
374
+ # "content-type"
375
+ # "connection"
376
+ # "cache-control"
377
+ # "cf-cache-status"
378
+ # "cf-ray"
150
379
  #
151
380
  # Returns an enumerator if no block is given.
381
+ #
382
+ # Net::HTTPHeader#each_name is an alias for Net::HTTPHeader#each_key.
152
383
  def each_name(&block) #:yield: +key+
153
384
  block_given? or return enum_for(__method__) { @header.size }
154
385
  @header.each_key(&block)
@@ -156,12 +387,23 @@ module Net::HTTPHeader
156
387
 
157
388
  alias each_key each_name
158
389
 
159
- # Iterates through the header names in the header, passing
160
- # capitalized header names to the code block.
390
+ # Calls the block with each capitalized field name:
391
+ #
392
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
393
+ # res.each_capitalized_name do |key|
394
+ # p key if key.start_with?('C')
395
+ # end
396
+ #
397
+ # Output:
398
+ #
399
+ # "Content-Type"
400
+ # "Connection"
401
+ # "Cache-Control"
402
+ # "Cf-Cache-Status"
403
+ # "Cf-Ray"
161
404
  #
162
- # Note that header names are capitalized systematically;
163
- # capitalization may not match that used by the remote HTTP
164
- # server in its response.
405
+ # The capitalization is system-dependent;
406
+ # see {Case Mapping}[https://docs.ruby-lang.org/en/master/case_mapping_rdoc.html].
165
407
  #
166
408
  # Returns an enumerator if no block is given.
167
409
  def each_capitalized_name #:yield: +key+
@@ -171,8 +413,18 @@ module Net::HTTPHeader
171
413
  end
172
414
  end
173
415
 
174
- # Iterates through header values, passing each value to the
175
- # code block.
416
+ # Calls the block with each string field value:
417
+ #
418
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
419
+ # res.each_value do |value|
420
+ # p value if value.start_with?('c')
421
+ # end
422
+ #
423
+ # Output:
424
+ #
425
+ # "chunked"
426
+ # "cf-q-config;dur=6.0000002122251e-06"
427
+ # "cloudflare"
176
428
  #
177
429
  # Returns an enumerator if no block is given.
178
430
  def each_value #:yield: +value+
@@ -182,32 +434,45 @@ module Net::HTTPHeader
182
434
  end
183
435
  end
184
436
 
185
- # Removes a header field, specified by case-insensitive key.
437
+ # Removes the header for the given case-insensitive +key+
438
+ # (see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]);
439
+ # returns the deleted value, or +nil+ if no such field exists:
440
+ #
441
+ # req = Net::HTTP::Get.new(uri)
442
+ # req.delete('Accept') # => ["*/*"]
443
+ # req.delete('Nosuch') # => nil
444
+ #
186
445
  def delete(key)
187
446
  @header.delete(key.downcase.to_s)
188
447
  end
189
448
 
190
- # true if +key+ header exists.
449
+ # Returns +true+ if the field for the case-insensitive +key+ exists, +false+ otherwise:
450
+ #
451
+ # req = Net::HTTP::Get.new(uri)
452
+ # req.key?('Accept') # => true
453
+ # req.key?('Nosuch') # => false
454
+ #
191
455
  def key?(key)
192
456
  @header.key?(key.downcase.to_s)
193
457
  end
194
458
 
195
- # Returns a Hash consisting of header names and array of values.
196
- # e.g.
197
- # {"cache-control" => ["private"],
198
- # "content-type" => ["text/html"],
199
- # "date" => ["Wed, 22 Jun 2005 22:11:50 GMT"]}
459
+ # Returns a hash of the key/value pairs:
460
+ #
461
+ # req = Net::HTTP::Get.new(uri)
462
+ # req.to_hash
463
+ # # =>
464
+ # {"accept-encoding"=>["gzip;q=1.0,deflate;q=0.6,identity;q=0.3"],
465
+ # "accept"=>["*/*"],
466
+ # "user-agent"=>["Ruby"],
467
+ # "host"=>["jsonplaceholder.typicode.com"]}
468
+ #
200
469
  def to_hash
201
470
  @header.dup
202
471
  end
203
472
 
204
- # As for #each_header, except the keys are provided in capitalized form.
205
- #
206
- # Note that header names are capitalized systematically;
207
- # capitalization may not match that used by the remote HTTP
208
- # server in its response.
473
+ # Like #each_header, but the keys are returned in capitalized form.
209
474
  #
210
- # Returns an enumerator if no block is given.
475
+ # Net::HTTPHeader#canonical_each is an alias for Net::HTTPHeader#each_capitalized.
211
476
  def each_capitalized
212
477
  block_given? or return enum_for(__method__) { @header.size }
213
478
  @header.each do |k,v|
@@ -222,8 +487,17 @@ module Net::HTTPHeader
222
487
  end
223
488
  private :capitalize
224
489
 
225
- # Returns an Array of Range objects which represent the Range:
226
- # HTTP header field, or +nil+ if there is no such header.
490
+ # Returns an array of Range objects that represent
491
+ # the value of field <tt>'Range'</tt>,
492
+ # or +nil+ if there is no such field;
493
+ # see {Range request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#range-request-header]:
494
+ #
495
+ # req = Net::HTTP::Get.new(uri)
496
+ # req['Range'] = 'bytes=0-99,200-299,400-499'
497
+ # req.range # => [0..99, 200..299, 400..499]
498
+ # req.delete('Range')
499
+ # req.range # # => nil
500
+ #
227
501
  def range
228
502
  return nil unless @header['range']
229
503
 
@@ -266,14 +540,31 @@ module Net::HTTPHeader
266
540
  result
267
541
  end
268
542
 
269
- # Sets the HTTP Range: header.
270
- # Accepts either a Range object as a single argument,
271
- # or a beginning index and a length from that index.
272
- # Example:
543
+ # call-seq:
544
+ # set_range(length) -> length
545
+ # set_range(offset, length) -> range
546
+ # set_range(begin..length) -> range
547
+ #
548
+ # Sets the value for field <tt>'Range'</tt>;
549
+ # see {Range request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#range-request-header]:
273
550
  #
274
- # req.range = (0..1023)
275
- # req.set_range 0, 1023
551
+ # With argument +length+:
276
552
  #
553
+ # req = Net::HTTP::Get.new(uri)
554
+ # req.set_range(100) # => 100
555
+ # req['Range'] # => "bytes=0-99"
556
+ #
557
+ # With arguments +offset+ and +length+:
558
+ #
559
+ # req.set_range(100, 100) # => 100...200
560
+ # req['Range'] # => "bytes=100-199"
561
+ #
562
+ # With argument +range+:
563
+ #
564
+ # req.set_range(100..199) # => 100..199
565
+ # req['Range'] # => "bytes=100-199"
566
+ #
567
+ # Net::HTTPHeader#range= is an alias for Net::HTTPHeader#set_range.
277
568
  def set_range(r, e = nil)
278
569
  unless r
279
570
  @header.delete 'range'
@@ -305,8 +596,15 @@ module Net::HTTPHeader
305
596
 
306
597
  alias range= set_range
307
598
 
308
- # Returns an Integer object which represents the HTTP Content-Length:
309
- # header field, or +nil+ if that field was not provided.
599
+ # Returns the value of field <tt>'Content-Length'</tt> as an integer,
600
+ # or +nil+ if there is no such field;
601
+ # see {Content-Length request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-length-request-header]:
602
+ #
603
+ # res = Net::HTTP.get_response(hostname, '/nosuch/1')
604
+ # res.content_length # => 2
605
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
606
+ # res.content_length # => nil
607
+ #
310
608
  def content_length
311
609
  return nil unless key?('Content-Length')
312
610
  len = self['Content-Length'].slice(/\d+/) or
@@ -314,6 +612,20 @@ module Net::HTTPHeader
314
612
  len.to_i
315
613
  end
316
614
 
615
+ # Sets the value of field <tt>'Content-Length'</tt> to the given numeric;
616
+ # see {Content-Length response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-length-response-header]:
617
+ #
618
+ # _uri = uri.dup
619
+ # hostname = _uri.hostname # => "jsonplaceholder.typicode.com"
620
+ # _uri.path = '/posts' # => "/posts"
621
+ # req = Net::HTTP::Post.new(_uri) # => #<Net::HTTP::Post POST>
622
+ # req.body = '{"title": "foo","body": "bar","userId": 1}'
623
+ # req.content_length = req.body.size # => 42
624
+ # req.content_type = 'application/json'
625
+ # res = Net::HTTP.start(hostname) do |http|
626
+ # http.request(req)
627
+ # end # => #<Net::HTTPCreated 201 Created readbody=true>
628
+ #
317
629
  def content_length=(len)
318
630
  unless len
319
631
  @header.delete 'content-length'
@@ -322,20 +634,31 @@ module Net::HTTPHeader
322
634
  @header['content-length'] = [len.to_i.to_s]
323
635
  end
324
636
 
325
- # Returns "true" if the "transfer-encoding" header is present and
326
- # set to "chunked". This is an HTTP/1.1 feature, allowing
327
- # the content to be sent in "chunks" without at the outset
328
- # stating the entire content length.
637
+ # Returns +true+ if field <tt>'Transfer-Encoding'</tt>
638
+ # exists and has value <tt>'chunked'</tt>,
639
+ # +false+ otherwise;
640
+ # see {Transfer-Encoding response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#transfer-encoding-response-header]:
641
+ #
642
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
643
+ # res['Transfer-Encoding'] # => "chunked"
644
+ # res.chunked? # => true
645
+ #
329
646
  def chunked?
330
647
  return false unless @header['transfer-encoding']
331
648
  field = self['Transfer-Encoding']
332
649
  (/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
333
650
  end
334
651
 
335
- # Returns a Range object which represents the value of the Content-Range:
336
- # header field.
337
- # For a partial entity body, this indicates where this fragment
338
- # fits inside the full entity body, as range of byte offsets.
652
+ # Returns a Range object representing the value of field
653
+ # <tt>'Content-Range'</tt>, or +nil+ if no such field exists;
654
+ # see {Content-Range response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-range-response-header]:
655
+ #
656
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
657
+ # res['Content-Range'] # => nil
658
+ # res['Content-Range'] = 'bytes 0-499/1000'
659
+ # res['Content-Range'] # => "bytes 0-499/1000"
660
+ # res.content_range # => 0..499
661
+ #
339
662
  def content_range
340
663
  return nil unless @header['content-range']
341
664
  m = %r<\A\s*(\w+)\s+(\d+)-(\d+)/(\d+|\*)>.match(self['Content-Range']) or
@@ -344,14 +667,29 @@ module Net::HTTPHeader
344
667
  m[2].to_i .. m[3].to_i
345
668
  end
346
669
 
347
- # The length of the range represented in Content-Range: header.
670
+ # Returns the integer representing length of the value of field
671
+ # <tt>'Content-Range'</tt>, or +nil+ if no such field exists;
672
+ # see {Content-Range response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-range-response-header]:
673
+ #
674
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
675
+ # res['Content-Range'] # => nil
676
+ # res['Content-Range'] = 'bytes 0-499/1000'
677
+ # res.range_length # => 500
678
+ #
348
679
  def range_length
349
680
  r = content_range() or return nil
350
681
  r.end - r.begin + 1
351
682
  end
352
683
 
353
- # Returns a content type string such as "text/html".
354
- # This method returns nil if Content-Type: header field does not exist.
684
+ # Returns the {media type}[https://en.wikipedia.org/wiki/Media_type]
685
+ # from the value of field <tt>'Content-Type'</tt>,
686
+ # or +nil+ if no such field exists;
687
+ # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
688
+ #
689
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
690
+ # res['content-type'] # => "application/json; charset=utf-8"
691
+ # res.content_type # => "application/json"
692
+ #
355
693
  def content_type
356
694
  return nil unless main_type()
357
695
  if sub_type()
@@ -360,16 +698,31 @@ module Net::HTTPHeader
360
698
  end
361
699
  end
362
700
 
363
- # Returns a content type string such as "text".
364
- # This method returns nil if Content-Type: header field does not exist.
701
+ # Returns the leading ('type') part of the
702
+ # {media type}[https://en.wikipedia.org/wiki/Media_type]
703
+ # from the value of field <tt>'Content-Type'</tt>,
704
+ # or +nil+ if no such field exists;
705
+ # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
706
+ #
707
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
708
+ # res['content-type'] # => "application/json; charset=utf-8"
709
+ # res.main_type # => "application"
710
+ #
365
711
  def main_type
366
712
  return nil unless @header['content-type']
367
713
  self['Content-Type'].split(';').first.to_s.split('/')[0].to_s.strip
368
714
  end
369
715
 
370
- # Returns a content type string such as "html".
371
- # This method returns nil if Content-Type: header field does not exist
372
- # or sub-type is not given (e.g. "Content-Type: text").
716
+ # Returns the trailing ('subtype') part of the
717
+ # {media type}[https://en.wikipedia.org/wiki/Media_type]
718
+ # from the value of field <tt>'Content-Type'</tt>,
719
+ # or +nil+ if no such field exists;
720
+ # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
721
+ #
722
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
723
+ # res['content-type'] # => "application/json; charset=utf-8"
724
+ # res.sub_type # => "json"
725
+ #
373
726
  def sub_type
374
727
  return nil unless @header['content-type']
375
728
  _, sub = *self['Content-Type'].split(';').first.to_s.split('/')
@@ -377,9 +730,14 @@ module Net::HTTPHeader
377
730
  sub.strip
378
731
  end
379
732
 
380
- # Any parameters specified for the content type, returned as a Hash.
381
- # For example, a header of Content-Type: text/html; charset=EUC-JP
382
- # would result in type_params returning {'charset' => 'EUC-JP'}
733
+ # Returns the trailing ('parameters') part of the value of field <tt>'Content-Type'</tt>,
734
+ # or +nil+ if no such field exists;
735
+ # see {Content-Type response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-response-header]:
736
+ #
737
+ # res = Net::HTTP.get_response(hostname, '/todos/1')
738
+ # res['content-type'] # => "application/json; charset=utf-8"
739
+ # res.type_params # => {"charset"=>"utf-8"}
740
+ #
383
741
  def type_params
384
742
  result = {}
385
743
  list = self['Content-Type'].to_s.split(';')
@@ -391,10 +749,14 @@ module Net::HTTPHeader
391
749
  result
392
750
  end
393
751
 
394
- # Sets the content type in an HTTP header.
395
- # The +type+ should be a full HTTP content type, e.g. "text/html".
396
- # The +params+ are an optional Hash of parameters to add after the
397
- # content type, e.g. {'charset' => 'iso-8859-1'}
752
+ # Sets the value of field <tt>'Content-Type'</tt>;
753
+ # returns the new value;
754
+ # see {Content-Type request header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#content-type-request-header]:
755
+ #
756
+ # req = Net::HTTP::Get.new(uri)
757
+ # req.set_content_type('application/json') # => ["application/json"]
758
+ #
759
+ # Net::HTTPHeader#content_type= is an alias for Net::HTTPHeader#set_content_type.
398
760
  def set_content_type(type, params = {})
399
761
  @header['content-type'] = [type + params.map{|k,v|"; #{k}=#{v}"}.join('')]
400
762
  end
@@ -410,10 +772,12 @@ module Net::HTTPHeader
410
772
  # application/x-www-form-urlencoded
411
773
  #
412
774
  # Example:
775
+ #
413
776
  # http.form_data = {"q" => "ruby", "lang" => "en"}
414
777
  # http.form_data = {"q" => ["ruby", "perl"], "lang" => "en"}
415
778
  # http.set_form_data({"q" => "ruby", "lang" => "en"}, ';')
416
779
  #
780
+ # Net::HTTPHeader#form_data= is an alias for Net::HTTPHeader#set_form_data.
417
781
  def set_form_data(params, sep = '&')
418
782
  query = URI.encode_www_form(params)
419
783
  query.gsub!(/&/, sep) if sep != '&'
@@ -438,12 +802,14 @@ module Net::HTTPHeader
438
802
  #
439
803
  # Each item of params should respond to +each+ and yield 2-3 arguments,
440
804
  # or an array of 2-3 elements. The arguments yielded should be:
441
- # * The name of the field.
442
- # * The value of the field, it should be a String or a File or IO-like.
443
- # * An options hash, supporting the following options, only
444
- # used for file uploads:
445
- # :filename :: The name of the file to use.
446
- # :content_type :: The content type of the uploaded file.
805
+ #
806
+ # - The name of the field.
807
+ # - The value of the field, it should be a String or a File or IO-like.
808
+ # - An options hash, supporting the following options
809
+ # (used only for file uploads); entries:
810
+ #
811
+ # - +:filename+: The name of the file to use.
812
+ # - +:content_type+: The content type of the uploaded file.
447
813
  #
448
814
  # Each item is a file field or a normal field.
449
815
  # If +value+ is a File object or the +opt+ hash has a :filename key,
@@ -455,6 +821,7 @@ module Net::HTTPHeader
455
821
  # chunked encoding.
456
822
  #
457
823
  # Example:
824
+ #
458
825
  # req.set_form([["q", "ruby"], ["lang", "en"]])
459
826
  #
460
827
  # req.set_form({"f"=>File.open('/path/to/filename')},