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 23require_relative 'protocol' 24require 'uri' 25autoload :OpenSSL, 'openssl' 26 27module 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: 66401 $.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 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 594 if opt 595 if opt[:use_ssl] 596 opt = {verify_mode: OpenSSL::SSL::VERIFY_PEER}.update(opt) 597 end 598 http.methods.grep(/\A(\w+)=\z/) do |meth| 599 key = $1.to_sym 600 opt.key?(key) or next 601 http.__send__(meth, opt[key]) 602 end 603 end 604 605 http.start(&block) 606 end 607 608 class << HTTP 609 alias newobj new # :nodoc: 610 end 611 612 # Creates a new Net::HTTP object without opening a TCP connection or 613 # HTTP session. 614 # 615 # The +address+ should be a DNS hostname or IP address, the +port+ is the 616 # port the server operates on. If no +port+ is given the default port for 617 # HTTP or HTTPS is used. 618 # 619 # If none of the +p_+ arguments are given, the proxy host and port are 620 # taken from the +http_proxy+ environment variable (or its uppercase 621 # equivalent) if present. If the proxy requires authentication you must 622 # supply it by hand. See URI::Generic#find_proxy for details of proxy 623 # detection from the environment. To disable proxy detection set +p_addr+ 624 # to nil. 625 # 626 # If you are connecting to a custom proxy, +p_addr+ specifies the DNS name 627 # or IP address of the proxy host, +p_port+ the port to use to access the 628 # proxy, +p_user+ and +p_pass+ the username and password if authorization 629 # is required to use the proxy, and p_no_proxy hosts which do not 630 # use the proxy. 631 # 632 def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_no_proxy = nil) 633 http = super address, port 634 635 if proxy_class? then # from Net::HTTP::Proxy() 636 http.proxy_from_env = @proxy_from_env 637 http.proxy_address = @proxy_address 638 http.proxy_port = @proxy_port 639 http.proxy_user = @proxy_user 640 http.proxy_pass = @proxy_pass 641 elsif p_addr == :ENV then 642 http.proxy_from_env = true 643 else 644 if p_addr && p_no_proxy && !URI::Generic.use_proxy?(p_addr, p_addr, p_port, p_no_proxy) 645 p_addr = nil 646 p_port = nil 647 end 648 http.proxy_address = p_addr 649 http.proxy_port = p_port || default_port 650 http.proxy_user = p_user 651 http.proxy_pass = p_pass 652 end 653 654 http 655 end 656 657 # Creates a new Net::HTTP object for the specified server address, 658 # without opening the TCP connection or initializing the HTTP session. 659 # The +address+ should be a DNS hostname or IP address. 660 def initialize(address, port = nil) 661 @address = address 662 @port = (port || HTTP.default_port) 663 @local_host = nil 664 @local_port = nil 665 @curr_http_version = HTTPVersion 666 @keep_alive_timeout = 2 667 @last_communicated = nil 668 @close_on_empty_response = false 669 @socket = nil 670 @started = false 671 @open_timeout = 60 672 @read_timeout = 60 673 @write_timeout = 60 674 @continue_timeout = nil 675 @max_retries = 1 676 @debug_output = nil 677 678 @proxy_from_env = false 679 @proxy_uri = nil 680 @proxy_address = nil 681 @proxy_port = nil 682 @proxy_user = nil 683 @proxy_pass = nil 684 685 @use_ssl = false 686 @ssl_context = nil 687 @ssl_session = nil 688 @sspi_enabled = false 689 SSL_IVNAMES.each do |ivname| 690 instance_variable_set ivname, nil 691 end 692 end 693 694 def inspect 695 "#<#{self.class} #{@address}:#{@port} open=#{started?}>" 696 end 697 698 # *WARNING* This method opens a serious security hole. 699 # Never use this method in production code. 700 # 701 # Sets an output stream for debugging. 702 # 703 # http = Net::HTTP.new(hostname) 704 # http.set_debug_output $stderr 705 # http.start { .... } 706 # 707 def set_debug_output(output) 708 warn 'Net::HTTP#set_debug_output called after HTTP started', uplevel: 1 if started? 709 @debug_output = output 710 end 711 712 # The DNS host name or IP address to connect to. 713 attr_reader :address 714 715 # The port number to connect to. 716 attr_reader :port 717 718 # The local host used to establish the connection. 719 attr_accessor :local_host 720 721 # The local port used to establish the connection. 722 attr_accessor :local_port 723 724 attr_writer :proxy_from_env 725 attr_writer :proxy_address 726 attr_writer :proxy_port 727 attr_writer :proxy_user 728 attr_writer :proxy_pass 729 730 # Number of seconds to wait for the connection to open. Any number 731 # may be used, including Floats for fractional seconds. If the HTTP 732 # object cannot open a connection in this many seconds, it raises a 733 # Net::OpenTimeout exception. The default value is 60 seconds. 734 attr_accessor :open_timeout 735 736 # Number of seconds to wait for one block to be read (via one read(2) 737 # call). Any number may be used, including Floats for fractional 738 # seconds. If the HTTP object cannot read data in this many seconds, 739 # it raises a Net::ReadTimeout exception. The default value is 60 seconds. 740 attr_reader :read_timeout 741 742 # Number of seconds to wait for one block to be written (via one write(2) 743 # call). Any number may be used, including Floats for fractional 744 # seconds. If the HTTP object cannot write data in this many seconds, 745 # it raises a Net::WriteTimeout exception. The default value is 60 seconds. 746 # Net::WriteTimeout is not raised on Windows. 747 attr_reader :write_timeout 748 749 # Maximum number of times to retry an idempotent request in case of 750 # Net::ReadTimeout, IOError, EOFError, Errno::ECONNRESET, 751 # Errno::ECONNABORTED, Errno::EPIPE, OpenSSL::SSL::SSLError, 752 # Timeout::Error. 753 # Should be a non-negative integer number. Zero means no retries. 754 # The default value is 1. 755 def max_retries=(retries) 756 retries = retries.to_int 757 if retries < 0 758 raise ArgumentError, 'max_retries should be non-negative integer number' 759 end 760 @max_retries = retries 761 end 762 763 attr_reader :max_retries 764 765 # Setter for the read_timeout attribute. 766 def read_timeout=(sec) 767 @socket.read_timeout = sec if @socket 768 @read_timeout = sec 769 end 770 771 # Setter for the write_timeout attribute. 772 def write_timeout=(sec) 773 @socket.write_timeout = sec if @socket 774 @write_timeout = sec 775 end 776 777 # Seconds to wait for 100 Continue response. If the HTTP object does not 778 # receive a response in this many seconds it sends the request body. The 779 # default value is +nil+. 780 attr_reader :continue_timeout 781 782 # Setter for the continue_timeout attribute. 783 def continue_timeout=(sec) 784 @socket.continue_timeout = sec if @socket 785 @continue_timeout = sec 786 end 787 788 # Seconds to reuse the connection of the previous request. 789 # If the idle time is less than this Keep-Alive Timeout, 790 # Net::HTTP reuses the TCP/IP socket used by the previous communication. 791 # The default value is 2 seconds. 792 attr_accessor :keep_alive_timeout 793 794 # Returns true if the HTTP session has been started. 795 def started? 796 @started 797 end 798 799 alias active? started? #:nodoc: obsolete 800 801 attr_accessor :close_on_empty_response 802 803 # Returns true if SSL/TLS is being used with HTTP. 804 def use_ssl? 805 @use_ssl 806 end 807 808 # Turn on/off SSL. 809 # This flag must be set before starting session. 810 # If you change use_ssl value after session started, 811 # a Net::HTTP object raises IOError. 812 def use_ssl=(flag) 813 flag = flag ? true : false 814 if started? and @use_ssl != flag 815 raise IOError, "use_ssl value changed, but session already started" 816 end 817 @use_ssl = flag 818 end 819 820 SSL_IVNAMES = [ 821 :@ca_file, 822 :@ca_path, 823 :@cert, 824 :@cert_store, 825 :@ciphers, 826 :@key, 827 :@ssl_timeout, 828 :@ssl_version, 829 :@min_version, 830 :@max_version, 831 :@verify_callback, 832 :@verify_depth, 833 :@verify_mode, 834 ] 835 SSL_ATTRIBUTES = [ 836 :ca_file, 837 :ca_path, 838 :cert, 839 :cert_store, 840 :ciphers, 841 :key, 842 :ssl_timeout, 843 :ssl_version, 844 :min_version, 845 :max_version, 846 :verify_callback, 847 :verify_depth, 848 :verify_mode, 849 ] 850 851 # Sets path of a CA certification file in PEM format. 852 # 853 # The file can contain several CA certificates. 854 attr_accessor :ca_file 855 856 # Sets path of a CA certification directory containing certifications in 857 # PEM format. 858 attr_accessor :ca_path 859 860 # Sets an OpenSSL::X509::Certificate object as client certificate. 861 # (This method is appeared in Michal Rokos's OpenSSL extension). 862 attr_accessor :cert 863 864 # Sets the X509::Store to verify peer certificate. 865 attr_accessor :cert_store 866 867 # Sets the available ciphers. See OpenSSL::SSL::SSLContext#ciphers= 868 attr_accessor :ciphers 869 870 # Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object. 871 # (This method is appeared in Michal Rokos's OpenSSL extension.) 872 attr_accessor :key 873 874 # Sets the SSL timeout seconds. 875 attr_accessor :ssl_timeout 876 877 # Sets the SSL version. See OpenSSL::SSL::SSLContext#ssl_version= 878 attr_accessor :ssl_version 879 880 # Sets the minimum SSL version. See OpenSSL::SSL::SSLContext#min_version= 881 attr_accessor :min_version 882 883 # Sets the maximum SSL version. See OpenSSL::SSL::SSLContext#max_version= 884 attr_accessor :max_version 885 886 # Sets the verify callback for the server certification verification. 887 attr_accessor :verify_callback 888 889 # Sets the maximum depth for the certificate chain verification. 890 attr_accessor :verify_depth 891 892 # Sets the flags for server the certification verification at beginning of 893 # SSL/TLS session. 894 # 895 # OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER are acceptable. 896 attr_accessor :verify_mode 897 898 # Returns the X.509 certificates the server presented. 899 def peer_cert 900 if not use_ssl? or not @socket 901 return nil 902 end 903 @socket.io.peer_cert 904 end 905 906 # Opens a TCP connection and HTTP session. 907 # 908 # When this method is called with a block, it passes the Net::HTTP 909 # object to the block, and closes the TCP connection and HTTP session 910 # after the block has been executed. 911 # 912 # When called with a block, it returns the return value of the 913 # block; otherwise, it returns self. 914 # 915 def start # :yield: http 916 raise IOError, 'HTTP session already opened' if @started 917 if block_given? 918 begin 919 do_start 920 return yield(self) 921 ensure 922 do_finish 923 end 924 end 925 do_start 926 self 927 end 928 929 def do_start 930 connect 931 @started = true 932 end 933 private :do_start 934 935 def connect 936 if proxy? then 937 conn_address = proxy_address 938 conn_port = proxy_port 939 else 940 conn_address = address 941 conn_port = port 942 end 943 944 D "opening connection to #{conn_address}:#{conn_port}..." 945 s = Timeout.timeout(@open_timeout, Net::OpenTimeout) { 946 begin 947 TCPSocket.open(conn_address, conn_port, @local_host, @local_port) 948 rescue => e 949 raise e, "Failed to open TCP connection to " + 950 "#{conn_address}:#{conn_port} (#{e.message})" 951 end 952 } 953 s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) 954 D "opened" 955 if use_ssl? 956 if proxy? 957 plain_sock = BufferedIO.new(s, read_timeout: @read_timeout, 958 write_timeout: @write_timeout, 959 continue_timeout: @continue_timeout, 960 debug_output: @debug_output) 961 buf = "CONNECT #{@address}:#{@port} HTTP/#{HTTPVersion}\r\n" 962 buf << "Host: #{@address}:#{@port}\r\n" 963 if proxy_user 964 credential = ["#{proxy_user}:#{proxy_pass}"].pack('m0') 965 buf << "Proxy-Authorization: Basic #{credential}\r\n" 966 end 967 buf << "\r\n" 968 plain_sock.write(buf) 969 HTTPResponse.read_new(plain_sock).value 970 # assuming nothing left in buffers after successful CONNECT response 971 end 972 973 ssl_parameters = Hash.new 974 iv_list = instance_variables 975 SSL_IVNAMES.each_with_index do |ivname, i| 976 if iv_list.include?(ivname) and 977 value = instance_variable_get(ivname) 978 ssl_parameters[SSL_ATTRIBUTES[i]] = value if value 979 end 980 end 981 @ssl_context = OpenSSL::SSL::SSLContext.new 982 @ssl_context.set_params(ssl_parameters) 983 @ssl_context.session_cache_mode = 984 OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT | 985 OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE 986 @ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess } 987 D "starting SSL for #{conn_address}:#{conn_port}..." 988 s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context) 989 s.sync_close = true 990 # Server Name Indication (SNI) RFC 3546 991 s.hostname = @address if s.respond_to? :hostname= 992 if @ssl_session and 993 Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout 994 s.session = @ssl_session 995 end 996 ssl_socket_connect(s, @open_timeout) 997 if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE 998 s.post_connection_check(@address) 999 end 1000 D "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}" 1001 end 1002 @socket = BufferedIO.new(s, read_timeout: @read_timeout, 1003 write_timeout: @write_timeout, 1004 continue_timeout: @continue_timeout, 1005 debug_output: @debug_output) 1006 on_connect 1007 rescue => exception 1008 if s 1009 D "Conn close because of connect error #{exception}" 1010 s.close 1011 end 1012 raise 1013 end 1014 private :connect 1015 1016 def on_connect 1017 end 1018 private :on_connect 1019 1020 # Finishes the HTTP session and closes the TCP connection. 1021 # Raises IOError if the session has not been started. 1022 def finish 1023 raise IOError, 'HTTP session not yet started' unless started? 1024 do_finish 1025 end 1026 1027 def do_finish 1028 @started = false 1029 @socket.close if @socket 1030 @socket = nil 1031 end 1032 private :do_finish 1033 1034 # 1035 # proxy 1036 # 1037 1038 public 1039 1040 # no proxy 1041 @is_proxy_class = false 1042 @proxy_from_env = false 1043 @proxy_addr = nil 1044 @proxy_port = nil 1045 @proxy_user = nil 1046 @proxy_pass = nil 1047 1048 # Creates an HTTP proxy class which behaves like Net::HTTP, but 1049 # performs all access via the specified proxy. 1050 # 1051 # This class is obsolete. You may pass these same parameters directly to 1052 # Net::HTTP.new. See Net::HTTP.new for details of the arguments. 1053 def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil) 1054 return self unless p_addr 1055 1056 Class.new(self) { 1057 @is_proxy_class = true 1058 1059 if p_addr == :ENV then 1060 @proxy_from_env = true 1061 @proxy_address = nil 1062 @proxy_port = nil 1063 else 1064 @proxy_from_env = false 1065 @proxy_address = p_addr 1066 @proxy_port = p_port || default_port 1067 end 1068 1069 @proxy_user = p_user 1070 @proxy_pass = p_pass 1071 } 1072 end 1073 1074 class << HTTP 1075 # returns true if self is a class which was created by HTTP::Proxy. 1076 def proxy_class? 1077 defined?(@is_proxy_class) ? @is_proxy_class : false 1078 end 1079 1080 # Address of proxy host. If Net::HTTP does not use a proxy, nil. 1081 attr_reader :proxy_address 1082 1083 # Port number of proxy host. If Net::HTTP does not use a proxy, nil. 1084 attr_reader :proxy_port 1085 1086 # User name for accessing proxy. If Net::HTTP does not use a proxy, nil. 1087 attr_reader :proxy_user 1088 1089 # User password for accessing proxy. If Net::HTTP does not use a proxy, 1090 # nil. 1091 attr_reader :proxy_pass 1092 end 1093 1094 # True if requests for this connection will be proxied 1095 def proxy? 1096 !!(@proxy_from_env ? proxy_uri : @proxy_address) 1097 end 1098 1099 # True if the proxy for this connection is determined from the environment 1100 def proxy_from_env? 1101 @proxy_from_env 1102 end 1103 1104 # The proxy URI determined from the environment for this connection. 1105 def proxy_uri # :nodoc: 1106 return if @proxy_uri == false 1107 @proxy_uri ||= URI::HTTP.new( 1108 "http".freeze, nil, address, port, nil, nil, nil, nil, nil 1109 ).find_proxy || false 1110 @proxy_uri || nil 1111 end 1112 1113 # The address of the proxy server, if one is configured. 1114 def proxy_address 1115 if @proxy_from_env then 1116 proxy_uri&.hostname 1117 else 1118 @proxy_address 1119 end 1120 end 1121 1122 # The port of the proxy server, if one is configured. 1123 def proxy_port 1124 if @proxy_from_env then 1125 proxy_uri&.port 1126 else 1127 @proxy_port 1128 end 1129 end 1130 1131 # [Bug #12921] 1132 if /linux|freebsd|darwin/ =~ RUBY_PLATFORM 1133 ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE = true 1134 else 1135 ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE = false 1136 end 1137 1138 # The username of the proxy server, if one is configured. 1139 def proxy_user 1140 if ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE && @proxy_from_env 1141 proxy_uri&.user 1142 else 1143 @proxy_user 1144 end 1145 end 1146 1147 # The password of the proxy server, if one is configured. 1148 def proxy_pass 1149 if ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE && @proxy_from_env 1150 proxy_uri&.password 1151 else 1152 @proxy_pass 1153 end 1154 end 1155 1156 alias proxyaddr proxy_address #:nodoc: obsolete 1157 alias proxyport proxy_port #:nodoc: obsolete 1158 1159 private 1160 1161 # without proxy, obsolete 1162 1163 def conn_address # :nodoc: 1164 address() 1165 end 1166 1167 def conn_port # :nodoc: 1168 port() 1169 end 1170 1171 def edit_path(path) 1172 if proxy? 1173 if path.start_with?("ftp://") || use_ssl? 1174 path 1175 else 1176 "http://#{addr_port}#{path}" 1177 end 1178 else 1179 path 1180 end 1181 end 1182 1183 # 1184 # HTTP operations 1185 # 1186 1187 public 1188 1189 # Retrieves data from +path+ on the connected-to host which may be an 1190 # absolute path String or a URI to extract the path from. 1191 # 1192 # +initheader+ must be a Hash like { 'Accept' => '*/*', ... }, 1193 # and it defaults to an empty hash. 1194 # If +initheader+ doesn't have the key 'accept-encoding', then 1195 # a value of "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" is used, 1196 # so that gzip compression is used in preference to deflate 1197 # compression, which is used in preference to no compression. 1198 # Ruby doesn't have libraries to support the compress (Lempel-Ziv) 1199 # compression, so that is not supported. The intent of this is 1200 # to reduce bandwidth by default. If this routine sets up 1201 # compression, then it does the decompression also, removing 1202 # the header as well to prevent confusion. Otherwise 1203 # it leaves the body as it found it. 1204 # 1205 # This method returns a Net::HTTPResponse object. 1206 # 1207 # If called with a block, yields each fragment of the 1208 # entity body in turn as a string as it is read from 1209 # the socket. Note that in this case, the returned response 1210 # object will *not* contain a (meaningful) body. 1211 # 1212 # +dest+ argument is obsolete. 1213 # It still works but you must not use it. 1214 # 1215 # This method never raises an exception. 1216 # 1217 # response = http.get('/index.html') 1218 # 1219 # # using block 1220 # File.open('result.txt', 'w') {|f| 1221 # http.get('/~foo/') do |str| 1222 # f.write str 1223 # end 1224 # } 1225 # 1226 def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+ 1227 res = nil 1228 request(Get.new(path, initheader)) {|r| 1229 r.read_body dest, &block 1230 res = r 1231 } 1232 res 1233 end 1234 1235 # Gets only the header from +path+ on the connected-to host. 1236 # +header+ is a Hash like { 'Accept' => '*/*', ... }. 1237 # 1238 # This method returns a Net::HTTPResponse object. 1239 # 1240 # This method never raises an exception. 1241 # 1242 # response = nil 1243 # Net::HTTP.start('some.www.server', 80) {|http| 1244 # response = http.head('/index.html') 1245 # } 1246 # p response['content-type'] 1247 # 1248 def head(path, initheader = nil) 1249 request(Head.new(path, initheader)) 1250 end 1251 1252 # Posts +data+ (must be a String) to +path+. +header+ must be a Hash 1253 # like { 'Accept' => '*/*', ... }. 1254 # 1255 # This method returns a Net::HTTPResponse object. 1256 # 1257 # If called with a block, yields each fragment of the 1258 # entity body in turn as a string as it is read from 1259 # the socket. Note that in this case, the returned response 1260 # object will *not* contain a (meaningful) body. 1261 # 1262 # +dest+ argument is obsolete. 1263 # It still works but you must not use it. 1264 # 1265 # This method never raises exception. 1266 # 1267 # response = http.post('/cgi-bin/search.rb', 'query=foo') 1268 # 1269 # # using block 1270 # File.open('result.txt', 'w') {|f| 1271 # http.post('/cgi-bin/search.rb', 'query=foo') do |str| 1272 # f.write str 1273 # end 1274 # } 1275 # 1276 # You should set Content-Type: header field for POST. 1277 # If no Content-Type: field given, this method uses 1278 # "application/x-www-form-urlencoded" by default. 1279 # 1280 def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+ 1281 send_entity(path, data, initheader, dest, Post, &block) 1282 end 1283 1284 # Sends a PATCH request to the +path+ and gets a response, 1285 # as an HTTPResponse object. 1286 def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+ 1287 send_entity(path, data, initheader, dest, Patch, &block) 1288 end 1289 1290 def put(path, data, initheader = nil) #:nodoc: 1291 request(Put.new(path, initheader), data) 1292 end 1293 1294 # Sends a PROPPATCH request to the +path+ and gets a response, 1295 # as an HTTPResponse object. 1296 def proppatch(path, body, initheader = nil) 1297 request(Proppatch.new(path, initheader), body) 1298 end 1299 1300 # Sends a LOCK request to the +path+ and gets a response, 1301 # as an HTTPResponse object. 1302 def lock(path, body, initheader = nil) 1303 request(Lock.new(path, initheader), body) 1304 end 1305 1306 # Sends a UNLOCK request to the +path+ and gets a response, 1307 # as an HTTPResponse object. 1308 def unlock(path, body, initheader = nil) 1309 request(Unlock.new(path, initheader), body) 1310 end 1311 1312 # Sends a OPTIONS request to the +path+ and gets a response, 1313 # as an HTTPResponse object. 1314 def options(path, initheader = nil) 1315 request(Options.new(path, initheader)) 1316 end 1317 1318 # Sends a PROPFIND request to the +path+ and gets a response, 1319 # as an HTTPResponse object. 1320 def propfind(path, body = nil, initheader = {'Depth' => '0'}) 1321 request(Propfind.new(path, initheader), body) 1322 end 1323 1324 # Sends a DELETE request to the +path+ and gets a response, 1325 # as an HTTPResponse object. 1326 def delete(path, initheader = {'Depth' => 'Infinity'}) 1327 request(Delete.new(path, initheader)) 1328 end 1329 1330 # Sends a MOVE request to the +path+ and gets a response, 1331 # as an HTTPResponse object. 1332 def move(path, initheader = nil) 1333 request(Move.new(path, initheader)) 1334 end 1335 1336 # Sends a COPY request to the +path+ and gets a response, 1337 # as an HTTPResponse object. 1338 def copy(path, initheader = nil) 1339 request(Copy.new(path, initheader)) 1340 end 1341 1342 # Sends a MKCOL request to the +path+ and gets a response, 1343 # as an HTTPResponse object. 1344 def mkcol(path, body = nil, initheader = nil) 1345 request(Mkcol.new(path, initheader), body) 1346 end 1347 1348 # Sends a TRACE request to the +path+ and gets a response, 1349 # as an HTTPResponse object. 1350 def trace(path, initheader = nil) 1351 request(Trace.new(path, initheader)) 1352 end 1353 1354 # Sends a GET request to the +path+. 1355 # Returns the response as a Net::HTTPResponse object. 1356 # 1357 # When called with a block, passes an HTTPResponse object to the block. 1358 # The body of the response will not have been read yet; 1359 # the block can process it using HTTPResponse#read_body, 1360 # if desired. 1361 # 1362 # Returns the response. 1363 # 1364 # This method never raises Net::* exceptions. 1365 # 1366 # response = http.request_get('/index.html') 1367 # # The entity body is already read in this case. 1368 # p response['content-type'] 1369 # puts response.body 1370 # 1371 # # Using a block 1372 # http.request_get('/index.html') {|response| 1373 # p response['content-type'] 1374 # response.read_body do |str| # read body now 1375 # print str 1376 # end 1377 # } 1378 # 1379 def request_get(path, initheader = nil, &block) # :yield: +response+ 1380 request(Get.new(path, initheader), &block) 1381 end 1382 1383 # Sends a HEAD request to the +path+ and returns the response 1384 # as a Net::HTTPResponse object. 1385 # 1386 # Returns the response. 1387 # 1388 # This method never raises Net::* exceptions. 1389 # 1390 # response = http.request_head('/index.html') 1391 # p response['content-type'] 1392 # 1393 def request_head(path, initheader = nil, &block) 1394 request(Head.new(path, initheader), &block) 1395 end 1396 1397 # Sends a POST request to the +path+. 1398 # 1399 # Returns the response as a Net::HTTPResponse object. 1400 # 1401 # When called with a block, the block is passed an HTTPResponse 1402 # object. The body of that response will not have been read yet; 1403 # the block can process it using HTTPResponse#read_body, if desired. 1404 # 1405 # Returns the response. 1406 # 1407 # This method never raises Net::* exceptions. 1408 # 1409 # # example 1410 # response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...') 1411 # p response.status 1412 # puts response.body # body is already read in this case 1413 # 1414 # # using block 1415 # http.request_post('/cgi-bin/nice.rb', 'datadatadata...') {|response| 1416 # p response.status 1417 # p response['content-type'] 1418 # response.read_body do |str| # read body now 1419 # print str 1420 # end 1421 # } 1422 # 1423 def request_post(path, data, initheader = nil, &block) # :yield: +response+ 1424 request Post.new(path, initheader), data, &block 1425 end 1426 1427 def request_put(path, data, initheader = nil, &block) #:nodoc: 1428 request Put.new(path, initheader), data, &block 1429 end 1430 1431 alias get2 request_get #:nodoc: obsolete 1432 alias head2 request_head #:nodoc: obsolete 1433 alias post2 request_post #:nodoc: obsolete 1434 alias put2 request_put #:nodoc: obsolete 1435 1436 1437 # Sends an HTTP request to the HTTP server. 1438 # Also sends a DATA string if +data+ is given. 1439 # 1440 # Returns a Net::HTTPResponse object. 1441 # 1442 # This method never raises Net::* exceptions. 1443 # 1444 # response = http.send_request('GET', '/index.html') 1445 # puts response.body 1446 # 1447 def send_request(name, path, data = nil, header = nil) 1448 has_response_body = name != 'HEAD' 1449 r = HTTPGenericRequest.new(name,(data ? true : false),has_response_body,path,header) 1450 request r, data 1451 end 1452 1453 # Sends an HTTPRequest object +req+ to the HTTP server. 1454 # 1455 # If +req+ is a Net::HTTP::Post or Net::HTTP::Put request containing 1456 # data, the data is also sent. Providing data for a Net::HTTP::Head or 1457 # Net::HTTP::Get request results in an ArgumentError. 1458 # 1459 # Returns an HTTPResponse object. 1460 # 1461 # When called with a block, passes an HTTPResponse object to the block. 1462 # The body of the response will not have been read yet; 1463 # the block can process it using HTTPResponse#read_body, 1464 # if desired. 1465 # 1466 # This method never raises Net::* exceptions. 1467 # 1468 def request(req, body = nil, &block) # :yield: +response+ 1469 unless started? 1470 start { 1471 req['connection'] ||= 'close' 1472 return request(req, body, &block) 1473 } 1474 end 1475 if proxy_user() 1476 req.proxy_basic_auth proxy_user(), proxy_pass() unless use_ssl? 1477 end 1478 req.set_body_internal body 1479 res = transport_request(req, &block) 1480 if sspi_auth?(res) 1481 sspi_auth(req) 1482 res = transport_request(req, &block) 1483 end 1484 res 1485 end 1486 1487 private 1488 1489 # Executes a request which uses a representation 1490 # and returns its body. 1491 def send_entity(path, data, initheader, dest, type, &block) 1492 res = nil 1493 request(type.new(path, initheader), data) {|r| 1494 r.read_body dest, &block 1495 res = r 1496 } 1497 res 1498 end 1499 1500 IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc: 1501 1502 def transport_request(req) 1503 count = 0 1504 begin 1505 begin_transport req 1506 res = catch(:response) { 1507 req.exec @socket, @curr_http_version, edit_path(req.path) 1508 begin 1509 res = HTTPResponse.read_new(@socket) 1510 res.decode_content = req.decode_content 1511 end while res.kind_of?(HTTPInformation) 1512 1513 res.uri = req.uri 1514 1515 res 1516 } 1517 res.reading_body(@socket, req.response_body_permitted?) { 1518 yield res if block_given? 1519 } 1520 rescue Net::OpenTimeout 1521 raise 1522 rescue Net::ReadTimeout, IOError, EOFError, 1523 Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, 1524 # avoid a dependency on OpenSSL 1525 defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : IOError, 1526 Timeout::Error => exception 1527 if count < max_retries && IDEMPOTENT_METHODS_.include?(req.method) 1528 count += 1 1529 @socket.close if @socket 1530 D "Conn close because of error #{exception}, and retry" 1531 retry 1532 end 1533 D "Conn close because of error #{exception}" 1534 @socket.close if @socket 1535 raise 1536 end 1537 1538 end_transport req, res 1539 res 1540 rescue => exception 1541 D "Conn close because of error #{exception}" 1542 @socket.close if @socket 1543 raise exception 1544 end 1545 1546 def begin_transport(req) 1547 if @socket.closed? 1548 connect 1549 elsif @last_communicated 1550 if @last_communicated + @keep_alive_timeout < Process.clock_gettime(Process::CLOCK_MONOTONIC) 1551 D 'Conn close because of keep_alive_timeout' 1552 @socket.close 1553 connect 1554 elsif @socket.io.to_io.wait_readable(0) && @socket.eof? 1555 D "Conn close because of EOF" 1556 @socket.close 1557 connect 1558 end 1559 end 1560 1561 if not req.response_body_permitted? and @close_on_empty_response 1562 req['connection'] ||= 'close' 1563 end 1564 1565 req.update_uri address, port, use_ssl? 1566 req['host'] ||= addr_port() 1567 end 1568 1569 def end_transport(req, res) 1570 @curr_http_version = res.http_version 1571 @last_communicated = nil 1572 if @socket.closed? 1573 D 'Conn socket closed' 1574 elsif not res.body and @close_on_empty_response 1575 D 'Conn close' 1576 @socket.close 1577 elsif keep_alive?(req, res) 1578 D 'Conn keep-alive' 1579 @last_communicated = Process.clock_gettime(Process::CLOCK_MONOTONIC) 1580 else 1581 D 'Conn close' 1582 @socket.close 1583 end 1584 end 1585 1586 def keep_alive?(req, res) 1587 return false if req.connection_close? 1588 if @curr_http_version <= '1.0' 1589 res.connection_keep_alive? 1590 else # HTTP/1.1 or later 1591 not res.connection_close? 1592 end 1593 end 1594 1595 def sspi_auth?(res) 1596 return false unless @sspi_enabled 1597 if res.kind_of?(HTTPProxyAuthenticationRequired) and 1598 proxy? and res["Proxy-Authenticate"].include?("Negotiate") 1599 begin 1600 require 'win32/sspi' 1601 true 1602 rescue LoadError 1603 false 1604 end 1605 else 1606 false 1607 end 1608 end 1609 1610 def sspi_auth(req) 1611 n = Win32::SSPI::NegotiateAuth.new 1612 req["Proxy-Authorization"] = "Negotiate #{n.get_initial_token}" 1613 # Some versions of ISA will close the connection if this isn't present. 1614 req["Connection"] = "Keep-Alive" 1615 req["Proxy-Connection"] = "Keep-Alive" 1616 res = transport_request(req) 1617 authphrase = res["Proxy-Authenticate"] or return res 1618 req["Proxy-Authorization"] = "Negotiate #{n.complete_authentication(authphrase)}" 1619 rescue => err 1620 raise HTTPAuthenticationError.new('HTTP authentication failed', err) 1621 end 1622 1623 # 1624 # utils 1625 # 1626 1627 private 1628 1629 def addr_port 1630 addr = address 1631 addr = "[#{addr}]" if addr.include?(":") 1632 default_port = use_ssl? ? HTTP.https_default_port : HTTP.http_default_port 1633 default_port == port ? addr : "#{addr}:#{port}" 1634 end 1635 1636 def D(msg) 1637 return unless @debug_output 1638 @debug_output << msg 1639 @debug_output << "\n" 1640 end 1641 end 1642 1643end 1644 1645require_relative 'http/exceptions' 1646 1647require_relative 'http/header' 1648 1649require_relative 'http/generic_request' 1650require_relative 'http/request' 1651require_relative 'http/requests' 1652 1653require_relative 'http/response' 1654require_relative 'http/responses' 1655 1656require_relative 'http/proxy_delta' 1657 1658require_relative 'http/backward' 1659