net-http 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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'