net-http 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 14bdacaf426ba55dbcb6185d8f79591c7197574e40429fce13a9d7d3a8471245
4
+ data.tar.gz: f1c49cd5d4ddc6f465a58b6b01e4a1f9ac871386e018b16e34b747a001d84fb3
5
+ SHA512:
6
+ metadata.gz: 7ecc73e91fd63c65b108ff6085028f7490c597b346fa03887b34e8693600618d513bd243eccbf0d9a5cfb808418f1bb548c71ff546358ded71e4641c596927a0
7
+ data.tar.gz: a89f8b7a499c914d94745d3b74c09206144fe7d8336b64aa1f3bfde9ed7890206c6b957834210960ff2272018881c500e65d05de73347f30534a55adaa9a447e
@@ -0,0 +1,24 @@
1
+ name: ubuntu
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ name: build (${{ matrix.ruby }} / ${{ matrix.os }})
8
+ strategy:
9
+ matrix:
10
+ ruby: [ 2.7, 2.6, head ]
11
+ os: [ ubuntu-latest, macos-latest ]
12
+ runs-on: ${{ matrix.os }}
13
+ steps:
14
+ - uses: actions/checkout@master
15
+ - name: Set up Ruby
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: Install dependencies
20
+ run: |
21
+ gem install bundler --no-document
22
+ bundle install
23
+ - name: Run test
24
+ run: rake test
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "rake"
6
+ gem "test-unit"
@@ -0,0 +1,23 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ net-http (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ power_assert (1.1.5)
10
+ rake (13.0.1)
11
+ test-unit (3.3.5)
12
+ power_assert
13
+
14
+ PLATFORMS
15
+ ruby
16
+
17
+ DEPENDENCIES
18
+ net-http!
19
+ rake
20
+ test-unit
21
+
22
+ BUNDLED WITH
23
+ 2.1.4
@@ -0,0 +1,92 @@
1
+ # Net::Http
2
+
3
+ Net::HTTP provides a rich library which can be used to build HTTP
4
+ user-agents. For more details about HTTP see
5
+ [RFC2616](http://www.ietf.org/rfc/rfc2616.txt).
6
+
7
+ Net::HTTP is designed to work closely with URI. URI::HTTP#host,
8
+ URI::HTTP#port and URI::HTTP#request_uri are designed to work with
9
+ Net::HTTP.
10
+
11
+ If you are only performing a few GET requests you should try OpenURI.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'net-http'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle install
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install net-http
28
+
29
+ ## Usage
30
+
31
+ All examples assume you have loaded Net::HTTP with:
32
+
33
+ ```ruby
34
+ require 'net/http'
35
+ ```
36
+
37
+ This will also require 'uri' so you don't need to require it separately.
38
+
39
+ The Net::HTTP methods in the following section do not persist
40
+ connections. They are not recommended if you are performing many HTTP
41
+ requests.
42
+
43
+ ### GET
44
+
45
+ ```ruby
46
+ Net::HTTP.get('example.com', '/index.html') # => String
47
+ ```
48
+
49
+ ### GET by URI
50
+
51
+ ```ruby
52
+ uri = URI('http://example.com/index.html?count=10')
53
+ Net::HTTP.get(uri) # => String
54
+ ```
55
+
56
+ ### GET with Dynamic Parameters
57
+
58
+ ```ruby
59
+ uri = URI('http://example.com/index.html')
60
+ params = { :limit => 10, :page => 3 }
61
+ uri.query = URI.encode_www_form(params)
62
+
63
+ res = Net::HTTP.get_response(uri)
64
+ puts res.body if res.is_a?(Net::HTTPSuccess)
65
+ ```
66
+
67
+ ### POST
68
+
69
+ ```ruby
70
+ uri = URI('http://www.example.com/search.cgi')
71
+ res = Net::HTTP.post_form(uri, 'q' => 'ruby', 'max' => '50')
72
+ puts res.body
73
+ ```
74
+
75
+ ### POST with Multiple Values
76
+
77
+ ```ruby
78
+ uri = URI('http://www.example.com/search.cgi')
79
+ res = Net::HTTP.post_form(uri, 'q' => ['ruby', 'perl'], 'max' => '50')
80
+ puts res.body
81
+ ```
82
+
83
+ ## Development
84
+
85
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
86
+
87
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
88
+
89
+ ## Contributing
90
+
91
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/net-http.
92
+
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test/lib"
6
+ t.ruby_opts << "-rhelper"
7
+ t.test_files = FileList["test/**/test_*.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "net/http"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,1685 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # = net/http.rb
4
+ #
5
+ # Copyright (c) 1999-2007 Yukihiro Matsumoto
6
+ # Copyright (c) 1999-2007 Minero Aoki
7
+ # Copyright (c) 2001 GOTOU Yuuzou
8
+ #
9
+ # Written and maintained by Minero Aoki <aamine@loveruby.net>.
10
+ # HTTPS support added by GOTOU Yuuzou <gotoyuzo@notwork.org>.
11
+ #
12
+ # This file is derived from "http-access.rb".
13
+ #
14
+ # Documented by Minero Aoki; converted to RDoc by William Webber.
15
+ #
16
+ # This program is free software. You can re-distribute and/or
17
+ # modify this program under the same terms of ruby itself ---
18
+ # Ruby Distribution License or GNU General Public License.
19
+ #
20
+ # See Net::HTTP for an overview and examples.
21
+ #
22
+
23
+ require 'net/protocol'
24
+ require 'uri'
25
+ autoload :OpenSSL, 'openssl'
26
+
27
+ module Net #:nodoc:
28
+
29
+ # :stopdoc:
30
+ class HTTPBadResponse < StandardError; end
31
+ class HTTPHeaderSyntaxError < StandardError; end
32
+ # :startdoc:
33
+
34
+ # == An HTTP client API for Ruby.
35
+ #
36
+ # Net::HTTP provides a rich library which can be used to build HTTP
37
+ # user-agents. For more details about HTTP see
38
+ # [RFC2616](http://www.ietf.org/rfc/rfc2616.txt).
39
+ #
40
+ # Net::HTTP is designed to work closely with URI. URI::HTTP#host,
41
+ # URI::HTTP#port and URI::HTTP#request_uri are designed to work with
42
+ # Net::HTTP.
43
+ #
44
+ # If you are only performing a few GET requests you should try OpenURI.
45
+ #
46
+ # == Simple Examples
47
+ #
48
+ # All examples assume you have loaded Net::HTTP with:
49
+ #
50
+ # require 'net/http'
51
+ #
52
+ # This will also require 'uri' so you don't need to require it separately.
53
+ #
54
+ # The Net::HTTP methods in the following section do not persist
55
+ # connections. They are not recommended if you are performing many HTTP
56
+ # requests.
57
+ #
58
+ # === GET
59
+ #
60
+ # Net::HTTP.get('example.com', '/index.html') # => String
61
+ #
62
+ # === GET by URI
63
+ #
64
+ # uri = URI('http://example.com/index.html?count=10')
65
+ # Net::HTTP.get(uri) # => String
66
+ #
67
+ # === GET with Dynamic Parameters
68
+ #
69
+ # uri = URI('http://example.com/index.html')
70
+ # params = { :limit => 10, :page => 3 }
71
+ # uri.query = URI.encode_www_form(params)
72
+ #
73
+ # res = Net::HTTP.get_response(uri)
74
+ # puts res.body if res.is_a?(Net::HTTPSuccess)
75
+ #
76
+ # === POST
77
+ #
78
+ # uri = URI('http://www.example.com/search.cgi')
79
+ # res = Net::HTTP.post_form(uri, 'q' => 'ruby', 'max' => '50')
80
+ # puts res.body
81
+ #
82
+ # === POST with Multiple Values
83
+ #
84
+ # uri = URI('http://www.example.com/search.cgi')
85
+ # res = Net::HTTP.post_form(uri, 'q' => ['ruby', 'perl'], 'max' => '50')
86
+ # puts res.body
87
+ #
88
+ # == How to use Net::HTTP
89
+ #
90
+ # The following example code can be used as the basis of an HTTP user-agent
91
+ # which can perform a variety of request types using persistent
92
+ # connections.
93
+ #
94
+ # uri = URI('http://example.com/some_path?query=string')
95
+ #
96
+ # Net::HTTP.start(uri.host, uri.port) do |http|
97
+ # request = Net::HTTP::Get.new uri
98
+ #
99
+ # response = http.request request # Net::HTTPResponse object
100
+ # end
101
+ #
102
+ # Net::HTTP::start immediately creates a connection to an HTTP server which
103
+ # is kept open for the duration of the block. The connection will remain
104
+ # open for multiple requests in the block if the server indicates it
105
+ # supports persistent connections.
106
+ #
107
+ # If you wish to re-use a connection across multiple HTTP requests without
108
+ # automatically closing it you can use ::new and then call #start and
109
+ # #finish manually.
110
+ #
111
+ # The request types Net::HTTP supports are listed below in the section "HTTP
112
+ # Request Classes".
113
+ #
114
+ # For all the Net::HTTP request objects and shortcut request methods you may
115
+ # supply either a String for the request path or a URI from which Net::HTTP
116
+ # will extract the request path.
117
+ #
118
+ # === Response Data
119
+ #
120
+ # uri = URI('http://example.com/index.html')
121
+ # res = Net::HTTP.get_response(uri)
122
+ #
123
+ # # Headers
124
+ # res['Set-Cookie'] # => String
125
+ # res.get_fields('set-cookie') # => Array
126
+ # res.to_hash['set-cookie'] # => Array
127
+ # puts "Headers: #{res.to_hash.inspect}"
128
+ #
129
+ # # Status
130
+ # puts res.code # => '200'
131
+ # puts res.message # => 'OK'
132
+ # puts res.class.name # => 'HTTPOK'
133
+ #
134
+ # # Body
135
+ # puts res.body if res.response_body_permitted?
136
+ #
137
+ # === Following Redirection
138
+ #
139
+ # Each Net::HTTPResponse object belongs to a class for its response code.
140
+ #
141
+ # For example, all 2XX responses are instances of a Net::HTTPSuccess
142
+ # subclass, a 3XX response is an instance of a Net::HTTPRedirection
143
+ # subclass and a 200 response is an instance of the Net::HTTPOK class. For
144
+ # details of response classes, see the section "HTTP Response Classes"
145
+ # below.
146
+ #
147
+ # Using a case statement you can handle various types of responses properly:
148
+ #
149
+ # def fetch(uri_str, limit = 10)
150
+ # # You should choose a better exception.
151
+ # raise ArgumentError, 'too many HTTP redirects' if limit == 0
152
+ #
153
+ # response = Net::HTTP.get_response(URI(uri_str))
154
+ #
155
+ # case response
156
+ # when Net::HTTPSuccess then
157
+ # response
158
+ # when Net::HTTPRedirection then
159
+ # location = response['location']
160
+ # warn "redirected to #{location}"
161
+ # fetch(location, limit - 1)
162
+ # else
163
+ # response.value
164
+ # end
165
+ # end
166
+ #
167
+ # print fetch('http://www.ruby-lang.org')
168
+ #
169
+ # === POST
170
+ #
171
+ # A POST can be made using the Net::HTTP::Post request class. This example
172
+ # creates a URL encoded POST body:
173
+ #
174
+ # uri = URI('http://www.example.com/todo.cgi')
175
+ # req = Net::HTTP::Post.new(uri)
176
+ # req.set_form_data('from' => '2005-01-01', 'to' => '2005-03-31')
177
+ #
178
+ # res = Net::HTTP.start(uri.hostname, uri.port) do |http|
179
+ # http.request(req)
180
+ # end
181
+ #
182
+ # case res
183
+ # when Net::HTTPSuccess, Net::HTTPRedirection
184
+ # # OK
185
+ # else
186
+ # res.value
187
+ # end
188
+ #
189
+ # To send multipart/form-data use Net::HTTPHeader#set_form:
190
+ #
191
+ # req = Net::HTTP::Post.new(uri)
192
+ # req.set_form([['upload', File.open('foo.bar')]], 'multipart/form-data')
193
+ #
194
+ # Other requests that can contain a body such as PUT can be created in the
195
+ # same way using the corresponding request class (Net::HTTP::Put).
196
+ #
197
+ # === Setting Headers
198
+ #
199
+ # The following example performs a conditional GET using the
200
+ # If-Modified-Since header. If the files has not been modified since the
201
+ # time in the header a Not Modified response will be returned. See RFC 2616
202
+ # section 9.3 for further details.
203
+ #
204
+ # uri = URI('http://example.com/cached_response')
205
+ # file = File.stat 'cached_response'
206
+ #
207
+ # req = Net::HTTP::Get.new(uri)
208
+ # req['If-Modified-Since'] = file.mtime.rfc2822
209
+ #
210
+ # res = Net::HTTP.start(uri.hostname, uri.port) {|http|
211
+ # http.request(req)
212
+ # }
213
+ #
214
+ # open 'cached_response', 'w' do |io|
215
+ # io.write res.body
216
+ # end if res.is_a?(Net::HTTPSuccess)
217
+ #
218
+ # === Basic Authentication
219
+ #
220
+ # Basic authentication is performed according to
221
+ # [RFC2617](http://www.ietf.org/rfc/rfc2617.txt).
222
+ #
223
+ # uri = URI('http://example.com/index.html?key=value')
224
+ #
225
+ # req = Net::HTTP::Get.new(uri)
226
+ # req.basic_auth 'user', 'pass'
227
+ #
228
+ # res = Net::HTTP.start(uri.hostname, uri.port) {|http|
229
+ # http.request(req)
230
+ # }
231
+ # puts res.body
232
+ #
233
+ # === Streaming Response Bodies
234
+ #
235
+ # By default Net::HTTP reads an entire response into memory. If you are
236
+ # handling large files or wish to implement a progress bar you can instead
237
+ # stream the body directly to an IO.
238
+ #
239
+ # uri = URI('http://example.com/large_file')
240
+ #
241
+ # Net::HTTP.start(uri.host, uri.port) do |http|
242
+ # request = Net::HTTP::Get.new uri
243
+ #
244
+ # http.request request do |response|
245
+ # open 'large_file', 'w' do |io|
246
+ # response.read_body do |chunk|
247
+ # io.write chunk
248
+ # end
249
+ # end
250
+ # end
251
+ # end
252
+ #
253
+ # === HTTPS
254
+ #
255
+ # HTTPS is enabled for an HTTP connection by Net::HTTP#use_ssl=.
256
+ #
257
+ # uri = URI('https://secure.example.com/some_path?query=string')
258
+ #
259
+ # Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
260
+ # request = Net::HTTP::Get.new uri
261
+ # response = http.request request # Net::HTTPResponse object
262
+ # end
263
+ #
264
+ # Or if you simply want to make a GET request, you may pass in an URI
265
+ # object that has an HTTPS URL. Net::HTTP automatically turns on TLS
266
+ # verification if the URI object has a 'https' URI scheme.
267
+ #
268
+ # uri = URI('https://example.com/')
269
+ # Net::HTTP.get(uri) # => String
270
+ #
271
+ # In previous versions of Ruby you would need to require 'net/https' to use
272
+ # HTTPS. This is no longer true.
273
+ #
274
+ # === Proxies
275
+ #
276
+ # Net::HTTP will automatically create a proxy from the +http_proxy+
277
+ # environment variable if it is present. To disable use of +http_proxy+,
278
+ # pass +nil+ for the proxy address.
279
+ #
280
+ # You may also create a custom proxy:
281
+ #
282
+ # proxy_addr = 'your.proxy.host'
283
+ # proxy_port = 8080
284
+ #
285
+ # Net::HTTP.new('example.com', nil, proxy_addr, proxy_port).start { |http|
286
+ # # always proxy via your.proxy.addr:8080
287
+ # }
288
+ #
289
+ # See Net::HTTP.new for further details and examples such as proxies that
290
+ # require a username and password.
291
+ #
292
+ # === Compression
293
+ #
294
+ # Net::HTTP automatically adds Accept-Encoding for compression of response
295
+ # bodies and automatically decompresses gzip and deflate responses unless a
296
+ # Range header was sent.
297
+ #
298
+ # Compression can be disabled through the Accept-Encoding: identity header.
299
+ #
300
+ # == HTTP Request Classes
301
+ #
302
+ # Here is the HTTP request class hierarchy.
303
+ #
304
+ # * Net::HTTPRequest
305
+ # * Net::HTTP::Get
306
+ # * Net::HTTP::Head
307
+ # * Net::HTTP::Post
308
+ # * Net::HTTP::Patch
309
+ # * Net::HTTP::Put
310
+ # * Net::HTTP::Proppatch
311
+ # * Net::HTTP::Lock
312
+ # * Net::HTTP::Unlock
313
+ # * Net::HTTP::Options
314
+ # * Net::HTTP::Propfind
315
+ # * Net::HTTP::Delete
316
+ # * Net::HTTP::Move
317
+ # * Net::HTTP::Copy
318
+ # * Net::HTTP::Mkcol
319
+ # * Net::HTTP::Trace
320
+ #
321
+ # == HTTP Response Classes
322
+ #
323
+ # Here is HTTP response class hierarchy. All classes are defined in Net
324
+ # module and are subclasses of Net::HTTPResponse.
325
+ #
326
+ # HTTPUnknownResponse:: For unhandled HTTP extensions
327
+ # HTTPInformation:: 1xx
328
+ # HTTPContinue:: 100
329
+ # HTTPSwitchProtocol:: 101
330
+ # HTTPSuccess:: 2xx
331
+ # HTTPOK:: 200
332
+ # HTTPCreated:: 201
333
+ # HTTPAccepted:: 202
334
+ # HTTPNonAuthoritativeInformation:: 203
335
+ # HTTPNoContent:: 204
336
+ # HTTPResetContent:: 205
337
+ # HTTPPartialContent:: 206
338
+ # HTTPMultiStatus:: 207
339
+ # HTTPIMUsed:: 226
340
+ # HTTPRedirection:: 3xx
341
+ # HTTPMultipleChoices:: 300
342
+ # HTTPMovedPermanently:: 301
343
+ # HTTPFound:: 302
344
+ # HTTPSeeOther:: 303
345
+ # HTTPNotModified:: 304
346
+ # HTTPUseProxy:: 305
347
+ # HTTPTemporaryRedirect:: 307
348
+ # HTTPClientError:: 4xx
349
+ # HTTPBadRequest:: 400
350
+ # HTTPUnauthorized:: 401
351
+ # HTTPPaymentRequired:: 402
352
+ # HTTPForbidden:: 403
353
+ # HTTPNotFound:: 404
354
+ # HTTPMethodNotAllowed:: 405
355
+ # HTTPNotAcceptable:: 406
356
+ # HTTPProxyAuthenticationRequired:: 407
357
+ # HTTPRequestTimeOut:: 408
358
+ # HTTPConflict:: 409
359
+ # HTTPGone:: 410
360
+ # HTTPLengthRequired:: 411
361
+ # HTTPPreconditionFailed:: 412
362
+ # HTTPRequestEntityTooLarge:: 413
363
+ # HTTPRequestURITooLong:: 414
364
+ # HTTPUnsupportedMediaType:: 415
365
+ # HTTPRequestedRangeNotSatisfiable:: 416
366
+ # HTTPExpectationFailed:: 417
367
+ # HTTPUnprocessableEntity:: 422
368
+ # HTTPLocked:: 423
369
+ # HTTPFailedDependency:: 424
370
+ # HTTPUpgradeRequired:: 426
371
+ # HTTPPreconditionRequired:: 428
372
+ # HTTPTooManyRequests:: 429
373
+ # HTTPRequestHeaderFieldsTooLarge:: 431
374
+ # HTTPUnavailableForLegalReasons:: 451
375
+ # HTTPServerError:: 5xx
376
+ # HTTPInternalServerError:: 500
377
+ # HTTPNotImplemented:: 501
378
+ # HTTPBadGateway:: 502
379
+ # HTTPServiceUnavailable:: 503
380
+ # HTTPGatewayTimeOut:: 504
381
+ # HTTPVersionNotSupported:: 505
382
+ # HTTPInsufficientStorage:: 507
383
+ # HTTPNetworkAuthenticationRequired:: 511
384
+ #
385
+ # There is also the Net::HTTPBadResponse exception which is raised when
386
+ # there is a protocol error.
387
+ #
388
+ class HTTP < Protocol
389
+
390
+ # :stopdoc:
391
+ Revision = %q$Revision$.split[1]
392
+ HTTPVersion = '1.1'
393
+ begin
394
+ require 'zlib'
395
+ require 'stringio' #for our purposes (unpacking gzip) lump these together
396
+ HAVE_ZLIB=true
397
+ rescue LoadError
398
+ HAVE_ZLIB=false
399
+ end
400
+ # :startdoc:
401
+
402
+ # Turns on net/http 1.2 (Ruby 1.8) features.
403
+ # Defaults to ON in Ruby 1.8 or later.
404
+ def HTTP.version_1_2
405
+ true
406
+ end
407
+
408
+ # Returns true if net/http is in version 1.2 mode.
409
+ # Defaults to true.
410
+ def HTTP.version_1_2?
411
+ true
412
+ end
413
+
414
+ def HTTP.version_1_1? #:nodoc:
415
+ false
416
+ end
417
+
418
+ class << HTTP
419
+ alias is_version_1_1? version_1_1? #:nodoc:
420
+ alias is_version_1_2? version_1_2? #:nodoc:
421
+ end
422
+
423
+ #
424
+ # short cut methods
425
+ #
426
+
427
+ #
428
+ # Gets the body text from the target and outputs it to $stdout. The
429
+ # target can either be specified as
430
+ # (+uri+), or as (+host+, +path+, +port+ = 80); so:
431
+ #
432
+ # Net::HTTP.get_print URI('http://www.example.com/index.html')
433
+ #
434
+ # or:
435
+ #
436
+ # Net::HTTP.get_print 'www.example.com', '/index.html'
437
+ #
438
+ def HTTP.get_print(uri_or_host, path = nil, port = nil)
439
+ get_response(uri_or_host, path, port) {|res|
440
+ res.read_body do |chunk|
441
+ $stdout.print chunk
442
+ end
443
+ }
444
+ nil
445
+ end
446
+
447
+ # Sends a GET request to the target and returns the HTTP response
448
+ # as a string. The target can either be specified as
449
+ # (+uri+), or as (+host+, +path+, +port+ = 80); so:
450
+ #
451
+ # print Net::HTTP.get(URI('http://www.example.com/index.html'))
452
+ #
453
+ # or:
454
+ #
455
+ # print Net::HTTP.get('www.example.com', '/index.html')
456
+ #
457
+ def HTTP.get(uri_or_host, path = nil, port = nil)
458
+ get_response(uri_or_host, path, port).body
459
+ end
460
+
461
+ # Sends a GET request to the target and returns the HTTP response
462
+ # as a Net::HTTPResponse object. The target can either be specified as
463
+ # (+uri+), or as (+host+, +path+, +port+ = 80); so:
464
+ #
465
+ # res = Net::HTTP.get_response(URI('http://www.example.com/index.html'))
466
+ # print res.body
467
+ #
468
+ # or:
469
+ #
470
+ # res = Net::HTTP.get_response('www.example.com', '/index.html')
471
+ # print res.body
472
+ #
473
+ def HTTP.get_response(uri_or_host, path = nil, port = nil, &block)
474
+ if path
475
+ host = uri_or_host
476
+ new(host, port || HTTP.default_port).start {|http|
477
+ return http.request_get(path, &block)
478
+ }
479
+ else
480
+ uri = uri_or_host
481
+ start(uri.hostname, uri.port,
482
+ :use_ssl => uri.scheme == 'https') {|http|
483
+ return http.request_get(uri, &block)
484
+ }
485
+ end
486
+ end
487
+
488
+ # Posts data to the specified URI object.
489
+ #
490
+ # Example:
491
+ #
492
+ # require 'net/http'
493
+ # require 'uri'
494
+ #
495
+ # Net::HTTP.post URI('http://www.example.com/api/search'),
496
+ # { "q" => "ruby", "max" => "50" }.to_json,
497
+ # "Content-Type" => "application/json"
498
+ #
499
+ def HTTP.post(url, data, header = nil)
500
+ start(url.hostname, url.port,
501
+ :use_ssl => url.scheme == 'https' ) {|http|
502
+ http.post(url, data, header)
503
+ }
504
+ end
505
+
506
+ # Posts HTML form data to the specified URI object.
507
+ # The form data must be provided as a Hash mapping from String to String.
508
+ # Example:
509
+ #
510
+ # { "cmd" => "search", "q" => "ruby", "max" => "50" }
511
+ #
512
+ # This method also does Basic Authentication iff +url+.user exists.
513
+ # But userinfo for authentication is deprecated (RFC3986).
514
+ # So this feature will be removed.
515
+ #
516
+ # Example:
517
+ #
518
+ # require 'net/http'
519
+ # require 'uri'
520
+ #
521
+ # Net::HTTP.post_form URI('http://www.example.com/search.cgi'),
522
+ # { "q" => "ruby", "max" => "50" }
523
+ #
524
+ def HTTP.post_form(url, params)
525
+ req = Post.new(url)
526
+ req.form_data = params
527
+ req.basic_auth url.user, url.password if url.user
528
+ start(url.hostname, url.port,
529
+ :use_ssl => url.scheme == 'https' ) {|http|
530
+ http.request(req)
531
+ }
532
+ end
533
+
534
+ #
535
+ # HTTP session management
536
+ #
537
+
538
+ # The default port to use for HTTP requests; defaults to 80.
539
+ def HTTP.default_port
540
+ http_default_port()
541
+ end
542
+
543
+ # The default port to use for HTTP requests; defaults to 80.
544
+ def HTTP.http_default_port
545
+ 80
546
+ end
547
+
548
+ # The default port to use for HTTPS requests; defaults to 443.
549
+ def HTTP.https_default_port
550
+ 443
551
+ end
552
+
553
+ def HTTP.socket_type #:nodoc: obsolete
554
+ BufferedIO
555
+ end
556
+
557
+ # :call-seq:
558
+ # HTTP.start(address, port, p_addr, p_port, p_user, p_pass, &block)
559
+ # HTTP.start(address, port=nil, p_addr=:ENV, p_port=nil, p_user=nil, p_pass=nil, opt, &block)
560
+ #
561
+ # Creates a new Net::HTTP object, then additionally opens the TCP
562
+ # connection and HTTP session.
563
+ #
564
+ # Arguments are the following:
565
+ # _address_ :: hostname or IP address of the server
566
+ # _port_ :: port of the server
567
+ # _p_addr_ :: address of proxy
568
+ # _p_port_ :: port of proxy
569
+ # _p_user_ :: user of proxy
570
+ # _p_pass_ :: pass of proxy
571
+ # _opt_ :: optional hash
572
+ #
573
+ # _opt_ sets following values by its accessor.
574
+ # The keys are ipaddr, ca_file, ca_path, cert, cert_store, ciphers,
575
+ # close_on_empty_response, key, open_timeout, read_timeout, write_timeout, ssl_timeout,
576
+ # ssl_version, use_ssl, verify_callback, verify_depth and verify_mode.
577
+ # If you set :use_ssl as true, you can use https and default value of
578
+ # verify_mode is set as OpenSSL::SSL::VERIFY_PEER.
579
+ #
580
+ # If the optional block is given, the newly
581
+ # created Net::HTTP object is passed to it and closed when the
582
+ # block finishes. In this case, the return value of this method
583
+ # is the return value of the block. If no block is given, the
584
+ # return value of this method is the newly created Net::HTTP object
585
+ # itself, and the caller is responsible for closing it upon completion
586
+ # using the finish() method.
587
+ def HTTP.start(address, *arg, &block) # :yield: +http+
588
+ arg.pop if opt = Hash.try_convert(arg[-1])
589
+ port, p_addr, p_port, p_user, p_pass = *arg
590
+ p_addr = :ENV if arg.size < 2
591
+ port = https_default_port if !port && opt && opt[:use_ssl]
592
+ http = new(address, port, p_addr, p_port, p_user, p_pass)
593
+ http.ipaddr = opt[:ipaddr] if opt && opt[:ipaddr]
594
+
595
+ if opt
596
+ if opt[:use_ssl]
597
+ opt = {verify_mode: OpenSSL::SSL::VERIFY_PEER}.update(opt)
598
+ end
599
+ http.methods.grep(/\A(\w+)=\z/) do |meth|
600
+ key = $1.to_sym
601
+ opt.key?(key) or next
602
+ http.__send__(meth, opt[key])
603
+ end
604
+ end
605
+
606
+ http.start(&block)
607
+ end
608
+
609
+ class << HTTP
610
+ alias newobj new # :nodoc:
611
+ end
612
+
613
+ # Creates a new Net::HTTP object without opening a TCP connection or
614
+ # HTTP session.
615
+ #
616
+ # The +address+ should be a DNS hostname or IP address, the +port+ is the
617
+ # port the server operates on. If no +port+ is given the default port for
618
+ # HTTP or HTTPS is used.
619
+ #
620
+ # If none of the +p_+ arguments are given, the proxy host and port are
621
+ # taken from the +http_proxy+ environment variable (or its uppercase
622
+ # equivalent) if present. If the proxy requires authentication you must
623
+ # supply it by hand. See URI::Generic#find_proxy for details of proxy
624
+ # detection from the environment. To disable proxy detection set +p_addr+
625
+ # to nil.
626
+ #
627
+ # If you are connecting to a custom proxy, +p_addr+ specifies the DNS name
628
+ # or IP address of the proxy host, +p_port+ the port to use to access the
629
+ # proxy, +p_user+ and +p_pass+ the username and password if authorization
630
+ # is required to use the proxy, and p_no_proxy hosts which do not
631
+ # use the proxy.
632
+ #
633
+ def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_no_proxy = nil)
634
+ http = super address, port
635
+
636
+ if proxy_class? then # from Net::HTTP::Proxy()
637
+ http.proxy_from_env = @proxy_from_env
638
+ http.proxy_address = @proxy_address
639
+ http.proxy_port = @proxy_port
640
+ http.proxy_user = @proxy_user
641
+ http.proxy_pass = @proxy_pass
642
+ elsif p_addr == :ENV then
643
+ http.proxy_from_env = true
644
+ else
645
+ if p_addr && p_no_proxy && !URI::Generic.use_proxy?(p_addr, p_addr, p_port, p_no_proxy)
646
+ p_addr = nil
647
+ p_port = nil
648
+ end
649
+ http.proxy_address = p_addr
650
+ http.proxy_port = p_port || default_port
651
+ http.proxy_user = p_user
652
+ http.proxy_pass = p_pass
653
+ end
654
+
655
+ http
656
+ end
657
+
658
+ # Creates a new Net::HTTP object for the specified server address,
659
+ # without opening the TCP connection or initializing the HTTP session.
660
+ # The +address+ should be a DNS hostname or IP address.
661
+ def initialize(address, port = nil)
662
+ @address = address
663
+ @port = (port || HTTP.default_port)
664
+ @ipaddr = nil
665
+ @local_host = nil
666
+ @local_port = nil
667
+ @curr_http_version = HTTPVersion
668
+ @keep_alive_timeout = 2
669
+ @last_communicated = nil
670
+ @close_on_empty_response = false
671
+ @socket = nil
672
+ @started = false
673
+ @open_timeout = 60
674
+ @read_timeout = 60
675
+ @write_timeout = 60
676
+ @continue_timeout = nil
677
+ @max_retries = 1
678
+ @debug_output = nil
679
+
680
+ @proxy_from_env = false
681
+ @proxy_uri = nil
682
+ @proxy_address = nil
683
+ @proxy_port = nil
684
+ @proxy_user = nil
685
+ @proxy_pass = nil
686
+
687
+ @use_ssl = false
688
+ @ssl_context = nil
689
+ @ssl_session = nil
690
+ @sspi_enabled = false
691
+ SSL_IVNAMES.each do |ivname|
692
+ instance_variable_set ivname, nil
693
+ end
694
+ end
695
+
696
+ def inspect
697
+ "#<#{self.class} #{@address}:#{@port} open=#{started?}>"
698
+ end
699
+
700
+ # *WARNING* This method opens a serious security hole.
701
+ # Never use this method in production code.
702
+ #
703
+ # Sets an output stream for debugging.
704
+ #
705
+ # http = Net::HTTP.new(hostname)
706
+ # http.set_debug_output $stderr
707
+ # http.start { .... }
708
+ #
709
+ def set_debug_output(output)
710
+ warn 'Net::HTTP#set_debug_output called after HTTP started', uplevel: 1 if started?
711
+ @debug_output = output
712
+ end
713
+
714
+ # The DNS host name or IP address to connect to.
715
+ attr_reader :address
716
+
717
+ # The port number to connect to.
718
+ attr_reader :port
719
+
720
+ # The local host used to establish the connection.
721
+ attr_accessor :local_host
722
+
723
+ # The local port used to establish the connection.
724
+ attr_accessor :local_port
725
+
726
+ attr_writer :proxy_from_env
727
+ attr_writer :proxy_address
728
+ attr_writer :proxy_port
729
+ attr_writer :proxy_user
730
+ attr_writer :proxy_pass
731
+
732
+ # The IP address to connect to/used to connect to
733
+ def ipaddr
734
+ started? ? @socket.io.peeraddr[3] : @ipaddr
735
+ end
736
+
737
+ # Set the IP address to connect to
738
+ def ipaddr=(addr)
739
+ raise IOError, "ipaddr value changed, but session already started" if started?
740
+ @ipaddr = addr
741
+ end
742
+
743
+ # Number of seconds to wait for the connection to open. Any number
744
+ # may be used, including Floats for fractional seconds. If the HTTP
745
+ # object cannot open a connection in this many seconds, it raises a
746
+ # Net::OpenTimeout exception. The default value is 60 seconds.
747
+ attr_accessor :open_timeout
748
+
749
+ # Number of seconds to wait for one block to be read (via one read(2)
750
+ # call). Any number may be used, including Floats for fractional
751
+ # seconds. If the HTTP object cannot read data in this many seconds,
752
+ # it raises a Net::ReadTimeout exception. The default value is 60 seconds.
753
+ attr_reader :read_timeout
754
+
755
+ # Number of seconds to wait for one block to be written (via one write(2)
756
+ # call). Any number may be used, including Floats for fractional
757
+ # seconds. If the HTTP object cannot write data in this many seconds,
758
+ # it raises a Net::WriteTimeout exception. The default value is 60 seconds.
759
+ # Net::WriteTimeout is not raised on Windows.
760
+ attr_reader :write_timeout
761
+
762
+ # Maximum number of times to retry an idempotent request in case of
763
+ # Net::ReadTimeout, IOError, EOFError, Errno::ECONNRESET,
764
+ # Errno::ECONNABORTED, Errno::EPIPE, OpenSSL::SSL::SSLError,
765
+ # Timeout::Error.
766
+ # Should be a non-negative integer number. Zero means no retries.
767
+ # The default value is 1.
768
+ def max_retries=(retries)
769
+ retries = retries.to_int
770
+ if retries < 0
771
+ raise ArgumentError, 'max_retries should be non-negative integer number'
772
+ end
773
+ @max_retries = retries
774
+ end
775
+
776
+ attr_reader :max_retries
777
+
778
+ # Setter for the read_timeout attribute.
779
+ def read_timeout=(sec)
780
+ @socket.read_timeout = sec if @socket
781
+ @read_timeout = sec
782
+ end
783
+
784
+ # Setter for the write_timeout attribute.
785
+ def write_timeout=(sec)
786
+ @socket.write_timeout = sec if @socket
787
+ @write_timeout = sec
788
+ end
789
+
790
+ # Seconds to wait for 100 Continue response. If the HTTP object does not
791
+ # receive a response in this many seconds it sends the request body. The
792
+ # default value is +nil+.
793
+ attr_reader :continue_timeout
794
+
795
+ # Setter for the continue_timeout attribute.
796
+ def continue_timeout=(sec)
797
+ @socket.continue_timeout = sec if @socket
798
+ @continue_timeout = sec
799
+ end
800
+
801
+ # Seconds to reuse the connection of the previous request.
802
+ # If the idle time is less than this Keep-Alive Timeout,
803
+ # Net::HTTP reuses the TCP/IP socket used by the previous communication.
804
+ # The default value is 2 seconds.
805
+ attr_accessor :keep_alive_timeout
806
+
807
+ # Returns true if the HTTP session has been started.
808
+ def started?
809
+ @started
810
+ end
811
+
812
+ alias active? started? #:nodoc: obsolete
813
+
814
+ attr_accessor :close_on_empty_response
815
+
816
+ # Returns true if SSL/TLS is being used with HTTP.
817
+ def use_ssl?
818
+ @use_ssl
819
+ end
820
+
821
+ # Turn on/off SSL.
822
+ # This flag must be set before starting session.
823
+ # If you change use_ssl value after session started,
824
+ # a Net::HTTP object raises IOError.
825
+ def use_ssl=(flag)
826
+ flag = flag ? true : false
827
+ if started? and @use_ssl != flag
828
+ raise IOError, "use_ssl value changed, but session already started"
829
+ end
830
+ @use_ssl = flag
831
+ end
832
+
833
+ SSL_IVNAMES = [
834
+ :@ca_file,
835
+ :@ca_path,
836
+ :@cert,
837
+ :@cert_store,
838
+ :@ciphers,
839
+ :@key,
840
+ :@ssl_timeout,
841
+ :@ssl_version,
842
+ :@min_version,
843
+ :@max_version,
844
+ :@verify_callback,
845
+ :@verify_depth,
846
+ :@verify_mode,
847
+ :@verify_hostname,
848
+ ]
849
+ SSL_ATTRIBUTES = [
850
+ :ca_file,
851
+ :ca_path,
852
+ :cert,
853
+ :cert_store,
854
+ :ciphers,
855
+ :key,
856
+ :ssl_timeout,
857
+ :ssl_version,
858
+ :min_version,
859
+ :max_version,
860
+ :verify_callback,
861
+ :verify_depth,
862
+ :verify_mode,
863
+ :verify_hostname,
864
+ ]
865
+
866
+ # Sets path of a CA certification file in PEM format.
867
+ #
868
+ # The file can contain several CA certificates.
869
+ attr_accessor :ca_file
870
+
871
+ # Sets path of a CA certification directory containing certifications in
872
+ # PEM format.
873
+ attr_accessor :ca_path
874
+
875
+ # Sets an OpenSSL::X509::Certificate object as client certificate.
876
+ # (This method is appeared in Michal Rokos's OpenSSL extension).
877
+ attr_accessor :cert
878
+
879
+ # Sets the X509::Store to verify peer certificate.
880
+ attr_accessor :cert_store
881
+
882
+ # Sets the available ciphers. See OpenSSL::SSL::SSLContext#ciphers=
883
+ attr_accessor :ciphers
884
+
885
+ # Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
886
+ # (This method is appeared in Michal Rokos's OpenSSL extension.)
887
+ attr_accessor :key
888
+
889
+ # Sets the SSL timeout seconds.
890
+ attr_accessor :ssl_timeout
891
+
892
+ # Sets the SSL version. See OpenSSL::SSL::SSLContext#ssl_version=
893
+ attr_accessor :ssl_version
894
+
895
+ # Sets the minimum SSL version. See OpenSSL::SSL::SSLContext#min_version=
896
+ attr_accessor :min_version
897
+
898
+ # Sets the maximum SSL version. See OpenSSL::SSL::SSLContext#max_version=
899
+ attr_accessor :max_version
900
+
901
+ # Sets the verify callback for the server certification verification.
902
+ attr_accessor :verify_callback
903
+
904
+ # Sets the maximum depth for the certificate chain verification.
905
+ attr_accessor :verify_depth
906
+
907
+ # Sets the flags for server the certification verification at beginning of
908
+ # SSL/TLS session.
909
+ #
910
+ # OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER are acceptable.
911
+ attr_accessor :verify_mode
912
+
913
+ # Sets to check the server certificate is valid for the hostname.
914
+ # See OpenSSL::SSL::SSLContext#verify_hostname=
915
+ attr_accessor :verify_hostname
916
+
917
+ # Returns the X.509 certificates the server presented.
918
+ def peer_cert
919
+ if not use_ssl? or not @socket
920
+ return nil
921
+ end
922
+ @socket.io.peer_cert
923
+ end
924
+
925
+ # Opens a TCP connection and HTTP session.
926
+ #
927
+ # When this method is called with a block, it passes the Net::HTTP
928
+ # object to the block, and closes the TCP connection and HTTP session
929
+ # after the block has been executed.
930
+ #
931
+ # When called with a block, it returns the return value of the
932
+ # block; otherwise, it returns self.
933
+ #
934
+ def start # :yield: http
935
+ raise IOError, 'HTTP session already opened' if @started
936
+ if block_given?
937
+ begin
938
+ do_start
939
+ return yield(self)
940
+ ensure
941
+ do_finish
942
+ end
943
+ end
944
+ do_start
945
+ self
946
+ end
947
+
948
+ def do_start
949
+ connect
950
+ @started = true
951
+ end
952
+ private :do_start
953
+
954
+ def connect
955
+ if proxy? then
956
+ conn_addr = proxy_address
957
+ conn_port = proxy_port
958
+ else
959
+ conn_addr = conn_address
960
+ conn_port = port
961
+ end
962
+
963
+ D "opening connection to #{conn_addr}:#{conn_port}..."
964
+ s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
965
+ begin
966
+ TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
967
+ rescue => e
968
+ raise e, "Failed to open TCP connection to " +
969
+ "#{conn_addr}:#{conn_port} (#{e.message})"
970
+ end
971
+ }
972
+ s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
973
+ D "opened"
974
+ if use_ssl?
975
+ if proxy?
976
+ plain_sock = BufferedIO.new(s, read_timeout: @read_timeout,
977
+ write_timeout: @write_timeout,
978
+ continue_timeout: @continue_timeout,
979
+ debug_output: @debug_output)
980
+ buf = "CONNECT #{conn_address}:#{@port} HTTP/#{HTTPVersion}\r\n"
981
+ buf << "Host: #{@address}:#{@port}\r\n"
982
+ if proxy_user
983
+ credential = ["#{proxy_user}:#{proxy_pass}"].pack('m0')
984
+ buf << "Proxy-Authorization: Basic #{credential}\r\n"
985
+ end
986
+ buf << "\r\n"
987
+ plain_sock.write(buf)
988
+ HTTPResponse.read_new(plain_sock).value
989
+ # assuming nothing left in buffers after successful CONNECT response
990
+ end
991
+
992
+ ssl_parameters = Hash.new
993
+ iv_list = instance_variables
994
+ SSL_IVNAMES.each_with_index do |ivname, i|
995
+ if iv_list.include?(ivname)
996
+ value = instance_variable_get(ivname)
997
+ unless value.nil?
998
+ ssl_parameters[SSL_ATTRIBUTES[i]] = value
999
+ end
1000
+ end
1001
+ end
1002
+ @ssl_context = OpenSSL::SSL::SSLContext.new
1003
+ @ssl_context.set_params(ssl_parameters)
1004
+ @ssl_context.session_cache_mode =
1005
+ OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
1006
+ OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
1007
+ @ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
1008
+ D "starting SSL for #{conn_addr}:#{conn_port}..."
1009
+ s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
1010
+ s.sync_close = true
1011
+ # Server Name Indication (SNI) RFC 3546
1012
+ s.hostname = @address if s.respond_to? :hostname=
1013
+ if @ssl_session and
1014
+ Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
1015
+ s.session = @ssl_session
1016
+ end
1017
+ ssl_socket_connect(s, @open_timeout)
1018
+ if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && @ssl_context.verify_hostname
1019
+ s.post_connection_check(@address)
1020
+ end
1021
+ D "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
1022
+ end
1023
+ @socket = BufferedIO.new(s, read_timeout: @read_timeout,
1024
+ write_timeout: @write_timeout,
1025
+ continue_timeout: @continue_timeout,
1026
+ debug_output: @debug_output)
1027
+ on_connect
1028
+ rescue => exception
1029
+ if s
1030
+ D "Conn close because of connect error #{exception}"
1031
+ s.close
1032
+ end
1033
+ raise
1034
+ end
1035
+ private :connect
1036
+
1037
+ def on_connect
1038
+ end
1039
+ private :on_connect
1040
+
1041
+ # Finishes the HTTP session and closes the TCP connection.
1042
+ # Raises IOError if the session has not been started.
1043
+ def finish
1044
+ raise IOError, 'HTTP session not yet started' unless started?
1045
+ do_finish
1046
+ end
1047
+
1048
+ def do_finish
1049
+ @started = false
1050
+ @socket.close if @socket
1051
+ @socket = nil
1052
+ end
1053
+ private :do_finish
1054
+
1055
+ #
1056
+ # proxy
1057
+ #
1058
+
1059
+ public
1060
+
1061
+ # no proxy
1062
+ @is_proxy_class = false
1063
+ @proxy_from_env = false
1064
+ @proxy_addr = nil
1065
+ @proxy_port = nil
1066
+ @proxy_user = nil
1067
+ @proxy_pass = nil
1068
+
1069
+ # Creates an HTTP proxy class which behaves like Net::HTTP, but
1070
+ # performs all access via the specified proxy.
1071
+ #
1072
+ # This class is obsolete. You may pass these same parameters directly to
1073
+ # Net::HTTP.new. See Net::HTTP.new for details of the arguments.
1074
+ def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil)
1075
+ return self unless p_addr
1076
+
1077
+ Class.new(self) {
1078
+ @is_proxy_class = true
1079
+
1080
+ if p_addr == :ENV then
1081
+ @proxy_from_env = true
1082
+ @proxy_address = nil
1083
+ @proxy_port = nil
1084
+ else
1085
+ @proxy_from_env = false
1086
+ @proxy_address = p_addr
1087
+ @proxy_port = p_port || default_port
1088
+ end
1089
+
1090
+ @proxy_user = p_user
1091
+ @proxy_pass = p_pass
1092
+ }
1093
+ end
1094
+
1095
+ class << HTTP
1096
+ # returns true if self is a class which was created by HTTP::Proxy.
1097
+ def proxy_class?
1098
+ defined?(@is_proxy_class) ? @is_proxy_class : false
1099
+ end
1100
+
1101
+ # Address of proxy host. If Net::HTTP does not use a proxy, nil.
1102
+ attr_reader :proxy_address
1103
+
1104
+ # Port number of proxy host. If Net::HTTP does not use a proxy, nil.
1105
+ attr_reader :proxy_port
1106
+
1107
+ # User name for accessing proxy. If Net::HTTP does not use a proxy, nil.
1108
+ attr_reader :proxy_user
1109
+
1110
+ # User password for accessing proxy. If Net::HTTP does not use a proxy,
1111
+ # nil.
1112
+ attr_reader :proxy_pass
1113
+ end
1114
+
1115
+ # True if requests for this connection will be proxied
1116
+ def proxy?
1117
+ !!(@proxy_from_env ? proxy_uri : @proxy_address)
1118
+ end
1119
+
1120
+ # True if the proxy for this connection is determined from the environment
1121
+ def proxy_from_env?
1122
+ @proxy_from_env
1123
+ end
1124
+
1125
+ # The proxy URI determined from the environment for this connection.
1126
+ def proxy_uri # :nodoc:
1127
+ return if @proxy_uri == false
1128
+ @proxy_uri ||= URI::HTTP.new(
1129
+ "http".freeze, nil, address, port, nil, nil, nil, nil, nil
1130
+ ).find_proxy || false
1131
+ @proxy_uri || nil
1132
+ end
1133
+
1134
+ # The address of the proxy server, if one is configured.
1135
+ def proxy_address
1136
+ if @proxy_from_env then
1137
+ proxy_uri&.hostname
1138
+ else
1139
+ @proxy_address
1140
+ end
1141
+ end
1142
+
1143
+ # The port of the proxy server, if one is configured.
1144
+ def proxy_port
1145
+ if @proxy_from_env then
1146
+ proxy_uri&.port
1147
+ else
1148
+ @proxy_port
1149
+ end
1150
+ end
1151
+
1152
+ # [Bug #12921]
1153
+ if /linux|freebsd|darwin/ =~ RUBY_PLATFORM
1154
+ ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE = true
1155
+ else
1156
+ ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE = false
1157
+ end
1158
+
1159
+ # The username of the proxy server, if one is configured.
1160
+ def proxy_user
1161
+ if ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE && @proxy_from_env
1162
+ proxy_uri&.user
1163
+ else
1164
+ @proxy_user
1165
+ end
1166
+ end
1167
+
1168
+ # The password of the proxy server, if one is configured.
1169
+ def proxy_pass
1170
+ if ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE && @proxy_from_env
1171
+ proxy_uri&.password
1172
+ else
1173
+ @proxy_pass
1174
+ end
1175
+ end
1176
+
1177
+ alias proxyaddr proxy_address #:nodoc: obsolete
1178
+ alias proxyport proxy_port #:nodoc: obsolete
1179
+
1180
+ private
1181
+
1182
+ # without proxy, obsolete
1183
+
1184
+ def conn_address # :nodoc:
1185
+ @ipaddr || address()
1186
+ end
1187
+
1188
+ def conn_port # :nodoc:
1189
+ port()
1190
+ end
1191
+
1192
+ def edit_path(path)
1193
+ if proxy?
1194
+ if path.start_with?("ftp://") || use_ssl?
1195
+ path
1196
+ else
1197
+ "http://#{addr_port}#{path}"
1198
+ end
1199
+ else
1200
+ path
1201
+ end
1202
+ end
1203
+
1204
+ #
1205
+ # HTTP operations
1206
+ #
1207
+
1208
+ public
1209
+
1210
+ # Retrieves data from +path+ on the connected-to host which may be an
1211
+ # absolute path String or a URI to extract the path from.
1212
+ #
1213
+ # +initheader+ must be a Hash like { 'Accept' => '*/*', ... },
1214
+ # and it defaults to an empty hash.
1215
+ # If +initheader+ doesn't have the key 'accept-encoding', then
1216
+ # a value of "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" is used,
1217
+ # so that gzip compression is used in preference to deflate
1218
+ # compression, which is used in preference to no compression.
1219
+ # Ruby doesn't have libraries to support the compress (Lempel-Ziv)
1220
+ # compression, so that is not supported. The intent of this is
1221
+ # to reduce bandwidth by default. If this routine sets up
1222
+ # compression, then it does the decompression also, removing
1223
+ # the header as well to prevent confusion. Otherwise
1224
+ # it leaves the body as it found it.
1225
+ #
1226
+ # This method returns a Net::HTTPResponse object.
1227
+ #
1228
+ # If called with a block, yields each fragment of the
1229
+ # entity body in turn as a string as it is read from
1230
+ # the socket. Note that in this case, the returned response
1231
+ # object will *not* contain a (meaningful) body.
1232
+ #
1233
+ # +dest+ argument is obsolete.
1234
+ # It still works but you must not use it.
1235
+ #
1236
+ # This method never raises an exception.
1237
+ #
1238
+ # response = http.get('/index.html')
1239
+ #
1240
+ # # using block
1241
+ # File.open('result.txt', 'w') {|f|
1242
+ # http.get('/~foo/') do |str|
1243
+ # f.write str
1244
+ # end
1245
+ # }
1246
+ #
1247
+ def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+
1248
+ res = nil
1249
+ request(Get.new(path, initheader)) {|r|
1250
+ r.read_body dest, &block
1251
+ res = r
1252
+ }
1253
+ res
1254
+ end
1255
+
1256
+ # Gets only the header from +path+ on the connected-to host.
1257
+ # +header+ is a Hash like { 'Accept' => '*/*', ... }.
1258
+ #
1259
+ # This method returns a Net::HTTPResponse object.
1260
+ #
1261
+ # This method never raises an exception.
1262
+ #
1263
+ # response = nil
1264
+ # Net::HTTP.start('some.www.server', 80) {|http|
1265
+ # response = http.head('/index.html')
1266
+ # }
1267
+ # p response['content-type']
1268
+ #
1269
+ def head(path, initheader = nil)
1270
+ request(Head.new(path, initheader))
1271
+ end
1272
+
1273
+ # Posts +data+ (must be a String) to +path+. +header+ must be a Hash
1274
+ # like { 'Accept' => '*/*', ... }.
1275
+ #
1276
+ # This method returns a Net::HTTPResponse object.
1277
+ #
1278
+ # If called with a block, yields each fragment of the
1279
+ # entity body in turn as a string as it is read from
1280
+ # the socket. Note that in this case, the returned response
1281
+ # object will *not* contain a (meaningful) body.
1282
+ #
1283
+ # +dest+ argument is obsolete.
1284
+ # It still works but you must not use it.
1285
+ #
1286
+ # This method never raises exception.
1287
+ #
1288
+ # response = http.post('/cgi-bin/search.rb', 'query=foo')
1289
+ #
1290
+ # # using block
1291
+ # File.open('result.txt', 'w') {|f|
1292
+ # http.post('/cgi-bin/search.rb', 'query=foo') do |str|
1293
+ # f.write str
1294
+ # end
1295
+ # }
1296
+ #
1297
+ # You should set Content-Type: header field for POST.
1298
+ # If no Content-Type: field given, this method uses
1299
+ # "application/x-www-form-urlencoded" by default.
1300
+ #
1301
+ def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
1302
+ send_entity(path, data, initheader, dest, Post, &block)
1303
+ end
1304
+
1305
+ # Sends a PATCH request to the +path+ and gets a response,
1306
+ # as an HTTPResponse object.
1307
+ def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
1308
+ send_entity(path, data, initheader, dest, Patch, &block)
1309
+ end
1310
+
1311
+ def put(path, data, initheader = nil) #:nodoc:
1312
+ request(Put.new(path, initheader), data)
1313
+ end
1314
+
1315
+ # Sends a PROPPATCH request to the +path+ and gets a response,
1316
+ # as an HTTPResponse object.
1317
+ def proppatch(path, body, initheader = nil)
1318
+ request(Proppatch.new(path, initheader), body)
1319
+ end
1320
+
1321
+ # Sends a LOCK request to the +path+ and gets a response,
1322
+ # as an HTTPResponse object.
1323
+ def lock(path, body, initheader = nil)
1324
+ request(Lock.new(path, initheader), body)
1325
+ end
1326
+
1327
+ # Sends a UNLOCK request to the +path+ and gets a response,
1328
+ # as an HTTPResponse object.
1329
+ def unlock(path, body, initheader = nil)
1330
+ request(Unlock.new(path, initheader), body)
1331
+ end
1332
+
1333
+ # Sends a OPTIONS request to the +path+ and gets a response,
1334
+ # as an HTTPResponse object.
1335
+ def options(path, initheader = nil)
1336
+ request(Options.new(path, initheader))
1337
+ end
1338
+
1339
+ # Sends a PROPFIND request to the +path+ and gets a response,
1340
+ # as an HTTPResponse object.
1341
+ def propfind(path, body = nil, initheader = {'Depth' => '0'})
1342
+ request(Propfind.new(path, initheader), body)
1343
+ end
1344
+
1345
+ # Sends a DELETE request to the +path+ and gets a response,
1346
+ # as an HTTPResponse object.
1347
+ def delete(path, initheader = {'Depth' => 'Infinity'})
1348
+ request(Delete.new(path, initheader))
1349
+ end
1350
+
1351
+ # Sends a MOVE request to the +path+ and gets a response,
1352
+ # as an HTTPResponse object.
1353
+ def move(path, initheader = nil)
1354
+ request(Move.new(path, initheader))
1355
+ end
1356
+
1357
+ # Sends a COPY request to the +path+ and gets a response,
1358
+ # as an HTTPResponse object.
1359
+ def copy(path, initheader = nil)
1360
+ request(Copy.new(path, initheader))
1361
+ end
1362
+
1363
+ # Sends a MKCOL request to the +path+ and gets a response,
1364
+ # as an HTTPResponse object.
1365
+ def mkcol(path, body = nil, initheader = nil)
1366
+ request(Mkcol.new(path, initheader), body)
1367
+ end
1368
+
1369
+ # Sends a TRACE request to the +path+ and gets a response,
1370
+ # as an HTTPResponse object.
1371
+ def trace(path, initheader = nil)
1372
+ request(Trace.new(path, initheader))
1373
+ end
1374
+
1375
+ # Sends a GET request to the +path+.
1376
+ # Returns the response as a Net::HTTPResponse object.
1377
+ #
1378
+ # When called with a block, passes an HTTPResponse object to the block.
1379
+ # The body of the response will not have been read yet;
1380
+ # the block can process it using HTTPResponse#read_body,
1381
+ # if desired.
1382
+ #
1383
+ # Returns the response.
1384
+ #
1385
+ # This method never raises Net::* exceptions.
1386
+ #
1387
+ # response = http.request_get('/index.html')
1388
+ # # The entity body is already read in this case.
1389
+ # p response['content-type']
1390
+ # puts response.body
1391
+ #
1392
+ # # Using a block
1393
+ # http.request_get('/index.html') {|response|
1394
+ # p response['content-type']
1395
+ # response.read_body do |str| # read body now
1396
+ # print str
1397
+ # end
1398
+ # }
1399
+ #
1400
+ def request_get(path, initheader = nil, &block) # :yield: +response+
1401
+ request(Get.new(path, initheader), &block)
1402
+ end
1403
+
1404
+ # Sends a HEAD request to the +path+ and returns the response
1405
+ # as a Net::HTTPResponse object.
1406
+ #
1407
+ # Returns the response.
1408
+ #
1409
+ # This method never raises Net::* exceptions.
1410
+ #
1411
+ # response = http.request_head('/index.html')
1412
+ # p response['content-type']
1413
+ #
1414
+ def request_head(path, initheader = nil, &block)
1415
+ request(Head.new(path, initheader), &block)
1416
+ end
1417
+
1418
+ # Sends a POST request to the +path+.
1419
+ #
1420
+ # Returns the response as a Net::HTTPResponse object.
1421
+ #
1422
+ # When called with a block, the block is passed an HTTPResponse
1423
+ # object. The body of that response will not have been read yet;
1424
+ # the block can process it using HTTPResponse#read_body, if desired.
1425
+ #
1426
+ # Returns the response.
1427
+ #
1428
+ # This method never raises Net::* exceptions.
1429
+ #
1430
+ # # example
1431
+ # response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...')
1432
+ # p response.status
1433
+ # puts response.body # body is already read in this case
1434
+ #
1435
+ # # using block
1436
+ # http.request_post('/cgi-bin/nice.rb', 'datadatadata...') {|response|
1437
+ # p response.status
1438
+ # p response['content-type']
1439
+ # response.read_body do |str| # read body now
1440
+ # print str
1441
+ # end
1442
+ # }
1443
+ #
1444
+ def request_post(path, data, initheader = nil, &block) # :yield: +response+
1445
+ request Post.new(path, initheader), data, &block
1446
+ end
1447
+
1448
+ def request_put(path, data, initheader = nil, &block) #:nodoc:
1449
+ request Put.new(path, initheader), data, &block
1450
+ end
1451
+
1452
+ alias get2 request_get #:nodoc: obsolete
1453
+ alias head2 request_head #:nodoc: obsolete
1454
+ alias post2 request_post #:nodoc: obsolete
1455
+ alias put2 request_put #:nodoc: obsolete
1456
+
1457
+
1458
+ # Sends an HTTP request to the HTTP server.
1459
+ # Also sends a DATA string if +data+ is given.
1460
+ #
1461
+ # Returns a Net::HTTPResponse object.
1462
+ #
1463
+ # This method never raises Net::* exceptions.
1464
+ #
1465
+ # response = http.send_request('GET', '/index.html')
1466
+ # puts response.body
1467
+ #
1468
+ def send_request(name, path, data = nil, header = nil)
1469
+ has_response_body = name != 'HEAD'
1470
+ r = HTTPGenericRequest.new(name,(data ? true : false),has_response_body,path,header)
1471
+ request r, data
1472
+ end
1473
+
1474
+ # Sends an HTTPRequest object +req+ to the HTTP server.
1475
+ #
1476
+ # If +req+ is a Net::HTTP::Post or Net::HTTP::Put request containing
1477
+ # data, the data is also sent. Providing data for a Net::HTTP::Head or
1478
+ # Net::HTTP::Get request results in an ArgumentError.
1479
+ #
1480
+ # Returns an HTTPResponse object.
1481
+ #
1482
+ # When called with a block, passes an HTTPResponse object to the block.
1483
+ # The body of the response will not have been read yet;
1484
+ # the block can process it using HTTPResponse#read_body,
1485
+ # if desired.
1486
+ #
1487
+ # This method never raises Net::* exceptions.
1488
+ #
1489
+ def request(req, body = nil, &block) # :yield: +response+
1490
+ unless started?
1491
+ start {
1492
+ req['connection'] ||= 'close'
1493
+ return request(req, body, &block)
1494
+ }
1495
+ end
1496
+ if proxy_user()
1497
+ req.proxy_basic_auth proxy_user(), proxy_pass() unless use_ssl?
1498
+ end
1499
+ req.set_body_internal body
1500
+ res = transport_request(req, &block)
1501
+ if sspi_auth?(res)
1502
+ sspi_auth(req)
1503
+ res = transport_request(req, &block)
1504
+ end
1505
+ res
1506
+ end
1507
+
1508
+ private
1509
+
1510
+ # Executes a request which uses a representation
1511
+ # and returns its body.
1512
+ def send_entity(path, data, initheader, dest, type, &block)
1513
+ res = nil
1514
+ request(type.new(path, initheader), data) {|r|
1515
+ r.read_body dest, &block
1516
+ res = r
1517
+ }
1518
+ res
1519
+ end
1520
+
1521
+ IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:
1522
+
1523
+ def transport_request(req)
1524
+ count = 0
1525
+ begin
1526
+ begin_transport req
1527
+ res = catch(:response) {
1528
+ begin
1529
+ req.exec @socket, @curr_http_version, edit_path(req.path)
1530
+ rescue Errno::EPIPE
1531
+ # Failure when writing full request, but we can probably
1532
+ # still read the received response.
1533
+ end
1534
+
1535
+ begin
1536
+ res = HTTPResponse.read_new(@socket)
1537
+ res.decode_content = req.decode_content
1538
+ end while res.kind_of?(HTTPInformation)
1539
+
1540
+ res.uri = req.uri
1541
+
1542
+ res
1543
+ }
1544
+ res.reading_body(@socket, req.response_body_permitted?) {
1545
+ yield res if block_given?
1546
+ }
1547
+ rescue Net::OpenTimeout
1548
+ raise
1549
+ rescue Net::ReadTimeout, IOError, EOFError,
1550
+ Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, Errno::ETIMEDOUT,
1551
+ # avoid a dependency on OpenSSL
1552
+ defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : IOError,
1553
+ Timeout::Error => exception
1554
+ if count < max_retries && IDEMPOTENT_METHODS_.include?(req.method)
1555
+ count += 1
1556
+ @socket.close if @socket
1557
+ D "Conn close because of error #{exception}, and retry"
1558
+ retry
1559
+ end
1560
+ D "Conn close because of error #{exception}"
1561
+ @socket.close if @socket
1562
+ raise
1563
+ end
1564
+
1565
+ end_transport req, res
1566
+ res
1567
+ rescue => exception
1568
+ D "Conn close because of error #{exception}"
1569
+ @socket.close if @socket
1570
+ raise exception
1571
+ end
1572
+
1573
+ def begin_transport(req)
1574
+ if @socket.closed?
1575
+ connect
1576
+ elsif @last_communicated
1577
+ if @last_communicated + @keep_alive_timeout < Process.clock_gettime(Process::CLOCK_MONOTONIC)
1578
+ D 'Conn close because of keep_alive_timeout'
1579
+ @socket.close
1580
+ connect
1581
+ elsif @socket.io.to_io.wait_readable(0) && @socket.eof?
1582
+ D "Conn close because of EOF"
1583
+ @socket.close
1584
+ connect
1585
+ end
1586
+ end
1587
+
1588
+ if not req.response_body_permitted? and @close_on_empty_response
1589
+ req['connection'] ||= 'close'
1590
+ end
1591
+
1592
+ req.update_uri address, port, use_ssl?
1593
+ req['host'] ||= addr_port()
1594
+ end
1595
+
1596
+ def end_transport(req, res)
1597
+ @curr_http_version = res.http_version
1598
+ @last_communicated = nil
1599
+ if @socket.closed?
1600
+ D 'Conn socket closed'
1601
+ elsif not res.body and @close_on_empty_response
1602
+ D 'Conn close'
1603
+ @socket.close
1604
+ elsif keep_alive?(req, res)
1605
+ D 'Conn keep-alive'
1606
+ @last_communicated = Process.clock_gettime(Process::CLOCK_MONOTONIC)
1607
+ else
1608
+ D 'Conn close'
1609
+ @socket.close
1610
+ end
1611
+ end
1612
+
1613
+ def keep_alive?(req, res)
1614
+ return false if req.connection_close?
1615
+ if @curr_http_version <= '1.0'
1616
+ res.connection_keep_alive?
1617
+ else # HTTP/1.1 or later
1618
+ not res.connection_close?
1619
+ end
1620
+ end
1621
+
1622
+ def sspi_auth?(res)
1623
+ return false unless @sspi_enabled
1624
+ if res.kind_of?(HTTPProxyAuthenticationRequired) and
1625
+ proxy? and res["Proxy-Authenticate"].include?("Negotiate")
1626
+ begin
1627
+ require 'win32/sspi'
1628
+ true
1629
+ rescue LoadError
1630
+ false
1631
+ end
1632
+ else
1633
+ false
1634
+ end
1635
+ end
1636
+
1637
+ def sspi_auth(req)
1638
+ n = Win32::SSPI::NegotiateAuth.new
1639
+ req["Proxy-Authorization"] = "Negotiate #{n.get_initial_token}"
1640
+ # Some versions of ISA will close the connection if this isn't present.
1641
+ req["Connection"] = "Keep-Alive"
1642
+ req["Proxy-Connection"] = "Keep-Alive"
1643
+ res = transport_request(req)
1644
+ authphrase = res["Proxy-Authenticate"] or return res
1645
+ req["Proxy-Authorization"] = "Negotiate #{n.complete_authentication(authphrase)}"
1646
+ rescue => err
1647
+ raise HTTPAuthenticationError.new('HTTP authentication failed', err)
1648
+ end
1649
+
1650
+ #
1651
+ # utils
1652
+ #
1653
+
1654
+ private
1655
+
1656
+ def addr_port
1657
+ addr = address
1658
+ addr = "[#{addr}]" if addr.include?(":")
1659
+ default_port = use_ssl? ? HTTP.https_default_port : HTTP.http_default_port
1660
+ default_port == port ? addr : "#{addr}:#{port}"
1661
+ end
1662
+
1663
+ def D(msg)
1664
+ return unless @debug_output
1665
+ @debug_output << msg
1666
+ @debug_output << "\n"
1667
+ end
1668
+ end
1669
+
1670
+ end
1671
+
1672
+ require_relative 'http/exceptions'
1673
+
1674
+ require_relative 'http/header'
1675
+
1676
+ require_relative 'http/generic_request'
1677
+ require_relative 'http/request'
1678
+ require_relative 'http/requests'
1679
+
1680
+ require_relative 'http/response'
1681
+ require_relative 'http/responses'
1682
+
1683
+ require_relative 'http/proxy_delta'
1684
+
1685
+ require_relative 'http/backward'