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.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/doc/net-http/examples.rdoc +30 -0
- data/lib/net/http/header.rb +470 -103
- data/lib/net/http/request.rb +27 -5
- data/lib/net/http/requests.rb +296 -24
- data/lib/net/http/response.rb +127 -11
- data/lib/net/http/responses.rb +479 -69
- data/lib/net/http.rb +599 -346
- metadata +3 -2
data/lib/net/http/header.rb
CHANGED
@@ -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
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
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
|
37
|
-
#
|
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
|
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
|
-
#
|
53
|
-
#
|
54
|
-
#
|
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
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
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
|
-
#
|
105
|
-
#
|
106
|
-
#
|
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
|
-
#
|
110
|
-
#
|
111
|
-
#
|
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
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
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
|
-
#
|
131
|
-
# and value to the code block supplied.
|
338
|
+
# Calls the block with each key/value pair:
|
132
339
|
#
|
133
|
-
#
|
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
|
-
#
|
345
|
+
# Output:
|
136
346
|
#
|
137
|
-
#
|
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
|
-
#
|
149
|
-
#
|
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
|
-
#
|
160
|
-
#
|
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
|
-
#
|
163
|
-
#
|
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
|
-
#
|
175
|
-
#
|
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
|
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+
|
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
|
196
|
-
#
|
197
|
-
#
|
198
|
-
#
|
199
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
226
|
-
#
|
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
|
-
#
|
270
|
-
#
|
271
|
-
#
|
272
|
-
#
|
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
|
-
#
|
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
|
309
|
-
#
|
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
|
326
|
-
#
|
327
|
-
#
|
328
|
-
#
|
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
|
336
|
-
#
|
337
|
-
#
|
338
|
-
#
|
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
|
-
#
|
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
|
354
|
-
#
|
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
|
364
|
-
#
|
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
|
371
|
-
#
|
372
|
-
#
|
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
|
-
#
|
381
|
-
#
|
382
|
-
#
|
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
|
395
|
-
#
|
396
|
-
#
|
397
|
-
#
|
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
|
-
#
|
442
|
-
#
|
443
|
-
#
|
444
|
-
#
|
445
|
-
#
|
446
|
-
#
|
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')},
|