summaryrefslogtreecommitdiff
path: root/jni/ruby/lib/net/http.rb
diff options
context:
space:
mode:
authorJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-16 18:49:26 +0900
committerJari Vetoniemi <jari.vetoniemi@indooratlas.com>2020-03-30 00:39:06 +0900
commitfcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch)
tree64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/lib/net/http.rb
Fresh start
Diffstat (limited to 'jni/ruby/lib/net/http.rb')
-rw-r--r--jni/ruby/lib/net/http.rb1559
1 files changed, 1559 insertions, 0 deletions
diff --git a/jni/ruby/lib/net/http.rb b/jni/ruby/lib/net/http.rb
new file mode 100644
index 0000000..55a67ac
--- /dev/null
+++ b/jni/ruby/lib/net/http.rb
@@ -0,0 +1,1559 @@
+#
+# = net/http.rb
+#
+# Copyright (c) 1999-2007 Yukihiro Matsumoto
+# Copyright (c) 1999-2007 Minero Aoki
+# Copyright (c) 2001 GOTOU Yuuzou
+#
+# Written and maintained by Minero Aoki <aamine@loveruby.net>.
+# HTTPS support added by GOTOU Yuuzou <gotoyuzo@notwork.org>.
+#
+# This file is derived from "http-access.rb".
+#
+# Documented by Minero Aoki; converted to RDoc by William Webber.
+#
+# This program is free software. You can re-distribute and/or
+# modify this program under the same terms of ruby itself ---
+# Ruby Distribution License or GNU General Public License.
+#
+# See Net::HTTP for an overview and examples.
+#
+
+require 'net/protocol'
+require 'uri'
+
+module Net #:nodoc:
+ autoload :OpenSSL, 'openssl'
+
+ # :stopdoc:
+ class HTTPBadResponse < StandardError; end
+ class HTTPHeaderSyntaxError < StandardError; end
+ # :startdoc:
+
+ # == An HTTP client API for Ruby.
+ #
+ # Net::HTTP provides a rich library which can be used to build HTTP
+ # user-agents. For more details about HTTP see
+ # [RFC2616](http://www.ietf.org/rfc/rfc2616.txt)
+ #
+ # Net::HTTP is designed to work closely with URI. URI::HTTP#host,
+ # URI::HTTP#port and URI::HTTP#request_uri are designed to work with
+ # Net::HTTP.
+ #
+ # If you are only performing a few GET requests you should try OpenURI.
+ #
+ # == Simple Examples
+ #
+ # All examples assume you have loaded Net::HTTP with:
+ #
+ # require 'net/http'
+ #
+ # This will also require 'uri' so you don't need to require it separately.
+ #
+ # The Net::HTTP methods in the following section do not persist
+ # connections. They are not recommended if you are performing many HTTP
+ # requests.
+ #
+ # === GET
+ #
+ # Net::HTTP.get('example.com', '/index.html') # => String
+ #
+ # === GET by URI
+ #
+ # uri = URI('http://example.com/index.html?count=10')
+ # Net::HTTP.get(uri) # => String
+ #
+ # === GET with Dynamic Parameters
+ #
+ # uri = URI('http://example.com/index.html')
+ # params = { :limit => 10, :page => 3 }
+ # uri.query = URI.encode_www_form(params)
+ #
+ # res = Net::HTTP.get_response(uri)
+ # puts res.body if res.is_a?(Net::HTTPSuccess)
+ #
+ # === POST
+ #
+ # uri = URI('http://www.example.com/search.cgi')
+ # res = Net::HTTP.post_form(uri, 'q' => 'ruby', 'max' => '50')
+ # puts res.body
+ #
+ # === POST with Multiple Values
+ #
+ # uri = URI('http://www.example.com/search.cgi')
+ # res = Net::HTTP.post_form(uri, 'q' => ['ruby', 'perl'], 'max' => '50')
+ # puts res.body
+ #
+ # == How to use Net::HTTP
+ #
+ # The following example code can be used as the basis of a HTTP user-agent
+ # which can perform a variety of request types using persistent
+ # connections.
+ #
+ # uri = URI('http://example.com/some_path?query=string')
+ #
+ # Net::HTTP.start(uri.host, uri.port) do |http|
+ # request = Net::HTTP::Get.new uri
+ #
+ # response = http.request request # Net::HTTPResponse object
+ # end
+ #
+ # Net::HTTP::start immediately creates a connection to an HTTP server which
+ # is kept open for the duration of the block. The connection will remain
+ # open for multiple requests in the block if the server indicates it
+ # supports persistent connections.
+ #
+ # The request types Net::HTTP supports are listed below in the section "HTTP
+ # Request Classes".
+ #
+ # If you wish to re-use a connection across multiple HTTP requests without
+ # automatically closing it you can use ::new instead of ::start. #request
+ # will automatically open a connection to the server if one is not currently
+ # open. You can manually close the connection with #finish.
+ #
+ # For all the Net::HTTP request objects and shortcut request methods you may
+ # supply either a String for the request path or a URI from which Net::HTTP
+ # will extract the request path.
+ #
+ # === Response Data
+ #
+ # uri = URI('http://example.com/index.html')
+ # res = Net::HTTP.get_response(uri)
+ #
+ # # Headers
+ # res['Set-Cookie'] # => String
+ # res.get_fields('set-cookie') # => Array
+ # res.to_hash['set-cookie'] # => Array
+ # puts "Headers: #{res.to_hash.inspect}"
+ #
+ # # Status
+ # puts res.code # => '200'
+ # puts res.message # => 'OK'
+ # puts res.class.name # => 'HTTPOK'
+ #
+ # # Body
+ # puts res.body if res.response_body_permitted?
+ #
+ # === Following Redirection
+ #
+ # Each Net::HTTPResponse object belongs to a class for its response code.
+ #
+ # For example, all 2XX responses are instances of a Net::HTTPSuccess
+ # subclass, a 3XX response is an instance of a Net::HTTPRedirection
+ # subclass and a 200 response is an instance of the Net::HTTPOK class. For
+ # details of response classes, see the section "HTTP Response Classes"
+ # below.
+ #
+ # Using a case statement you can handle various types of responses properly:
+ #
+ # def fetch(uri_str, limit = 10)
+ # # You should choose a better exception.
+ # raise ArgumentError, 'too many HTTP redirects' if limit == 0
+ #
+ # response = Net::HTTP.get_response(URI(uri_str))
+ #
+ # case response
+ # when Net::HTTPSuccess then
+ # response
+ # when Net::HTTPRedirection then
+ # location = response['location']
+ # warn "redirected to #{location}"
+ # fetch(location, limit - 1)
+ # else
+ # response.value
+ # end
+ # end
+ #
+ # print fetch('http://www.ruby-lang.org')
+ #
+ # === POST
+ #
+ # A POST can be made using the Net::HTTP::Post request class. This example
+ # creates a urlencoded POST body:
+ #
+ # uri = URI('http://www.example.com/todo.cgi')
+ # req = Net::HTTP::Post.new(uri)
+ # req.set_form_data('from' => '2005-01-01', 'to' => '2005-03-31')
+ #
+ # res = Net::HTTP.start(uri.hostname, uri.port) do |http|
+ # http.request(req)
+ # end
+ #
+ # case res
+ # when Net::HTTPSuccess, Net::HTTPRedirection
+ # # OK
+ # else
+ # res.value
+ # end
+ #
+ # At this time Net::HTTP does not support multipart/form-data. To send
+ # multipart/form-data use Net::HTTPRequest#body= and
+ # Net::HTTPRequest#content_type=:
+ #
+ # req = Net::HTTP::Post.new(uri)
+ # req.body = multipart_data
+ # req.content_type = 'multipart/form-data'
+ #
+ # Other requests that can contain a body such as PUT can be created in the
+ # same way using the corresponding request class (Net::HTTP::Put).
+ #
+ # === Setting Headers
+ #
+ # The following example performs a conditional GET using the
+ # If-Modified-Since header. If the files has not been modified since the
+ # time in the header a Not Modified response will be returned. See RFC 2616
+ # section 9.3 for further details.
+ #
+ # uri = URI('http://example.com/cached_response')
+ # file = File.stat 'cached_response'
+ #
+ # req = Net::HTTP::Get.new(uri)
+ # req['If-Modified-Since'] = file.mtime.rfc2822
+ #
+ # res = Net::HTTP.start(uri.hostname, uri.port) {|http|
+ # http.request(req)
+ # }
+ #
+ # open 'cached_response', 'w' do |io|
+ # io.write res.body
+ # end if res.is_a?(Net::HTTPSuccess)
+ #
+ # === Basic Authentication
+ #
+ # Basic authentication is performed according to
+ # [RFC2617](http://www.ietf.org/rfc/rfc2617.txt)
+ #
+ # uri = URI('http://example.com/index.html?key=value')
+ #
+ # req = Net::HTTP::Get.new(uri)
+ # req.basic_auth 'user', 'pass'
+ #
+ # res = Net::HTTP.start(uri.hostname, uri.port) {|http|
+ # http.request(req)
+ # }
+ # puts res.body
+ #
+ # === Streaming Response Bodies
+ #
+ # By default Net::HTTP reads an entire response into memory. If you are
+ # handling large files or wish to implement a progress bar you can instead
+ # stream the body directly to an IO.
+ #
+ # uri = URI('http://example.com/large_file')
+ #
+ # Net::HTTP.start(uri.host, uri.port) do |http|
+ # request = Net::HTTP::Get.new uri
+ #
+ # http.request request do |response|
+ # open 'large_file', 'w' do |io|
+ # response.read_body do |chunk|
+ # io.write chunk
+ # end
+ # end
+ # end
+ # end
+ #
+ # === HTTPS
+ #
+ # HTTPS is enabled for an HTTP connection by Net::HTTP#use_ssl=.
+ #
+ # uri = URI('https://secure.example.com/some_path?query=string')
+ #
+ # Net::HTTP.start(uri.host, uri.port,
+ # :use_ssl => uri.scheme == 'https') do |http|
+ # request = Net::HTTP::Get.new uri
+ #
+ # response = http.request request # Net::HTTPResponse object
+ # end
+ #
+ # In previous versions of Ruby you would need to require 'net/https' to use
+ # HTTPS. This is no longer true.
+ #
+ # === Proxies
+ #
+ # Net::HTTP will automatically create a proxy from the +http_proxy+
+ # environment variable if it is present. To disable use of +http_proxy+,
+ # pass +nil+ for the proxy address.
+ #
+ # You may also create a custom proxy:
+ #
+ # proxy_addr = 'your.proxy.host'
+ # proxy_port = 8080
+ #
+ # Net::HTTP.new('example.com', nil, proxy_addr, proxy_port).start { |http|
+ # # always proxy via your.proxy.addr:8080
+ # }
+ #
+ # See Net::HTTP.new for further details and examples such as proxies that
+ # require a username and password.
+ #
+ # === Compression
+ #
+ # Net::HTTP automatically adds Accept-Encoding for compression of response
+ # bodies and automatically decompresses gzip and deflate responses unless a
+ # Range header was sent.
+ #
+ # Compression can be disabled through the Accept-Encoding: identity header.
+ #
+ # == HTTP Request Classes
+ #
+ # Here is the HTTP request class hierarchy.
+ #
+ # * Net::HTTPRequest
+ # * Net::HTTP::Get
+ # * Net::HTTP::Head
+ # * Net::HTTP::Post
+ # * Net::HTTP::Patch
+ # * Net::HTTP::Put
+ # * Net::HTTP::Proppatch
+ # * Net::HTTP::Lock
+ # * Net::HTTP::Unlock
+ # * Net::HTTP::Options
+ # * Net::HTTP::Propfind
+ # * Net::HTTP::Delete
+ # * Net::HTTP::Move
+ # * Net::HTTP::Copy
+ # * Net::HTTP::Mkcol
+ # * Net::HTTP::Trace
+ #
+ # == HTTP Response Classes
+ #
+ # Here is HTTP response class hierarchy. All classes are defined in Net
+ # module and are subclasses of Net::HTTPResponse.
+ #
+ # HTTPUnknownResponse:: For unhandled HTTP extensions
+ # HTTPInformation:: 1xx
+ # HTTPContinue:: 100
+ # HTTPSwitchProtocol:: 101
+ # HTTPSuccess:: 2xx
+ # HTTPOK:: 200
+ # HTTPCreated:: 201
+ # HTTPAccepted:: 202
+ # HTTPNonAuthoritativeInformation:: 203
+ # HTTPNoContent:: 204
+ # HTTPResetContent:: 205
+ # HTTPPartialContent:: 206
+ # HTTPMultiStatus:: 207
+ # HTTPIMUsed:: 226
+ # HTTPRedirection:: 3xx
+ # HTTPMultipleChoices:: 300
+ # HTTPMovedPermanently:: 301
+ # HTTPFound:: 302
+ # HTTPSeeOther:: 303
+ # HTTPNotModified:: 304
+ # HTTPUseProxy:: 305
+ # HTTPTemporaryRedirect:: 307
+ # HTTPClientError:: 4xx
+ # HTTPBadRequest:: 400
+ # HTTPUnauthorized:: 401
+ # HTTPPaymentRequired:: 402
+ # HTTPForbidden:: 403
+ # HTTPNotFound:: 404
+ # HTTPMethodNotAllowed:: 405
+ # HTTPNotAcceptable:: 406
+ # HTTPProxyAuthenticationRequired:: 407
+ # HTTPRequestTimeOut:: 408
+ # HTTPConflict:: 409
+ # HTTPGone:: 410
+ # HTTPLengthRequired:: 411
+ # HTTPPreconditionFailed:: 412
+ # HTTPRequestEntityTooLarge:: 413
+ # HTTPRequestURITooLong:: 414
+ # HTTPUnsupportedMediaType:: 415
+ # HTTPRequestedRangeNotSatisfiable:: 416
+ # HTTPExpectationFailed:: 417
+ # HTTPUnprocessableEntity:: 422
+ # HTTPLocked:: 423
+ # HTTPFailedDependency:: 424
+ # HTTPUpgradeRequired:: 426
+ # HTTPPreconditionRequired:: 428
+ # HTTPTooManyRequests:: 429
+ # HTTPRequestHeaderFieldsTooLarge:: 431
+ # HTTPServerError:: 5xx
+ # HTTPInternalServerError:: 500
+ # HTTPNotImplemented:: 501
+ # HTTPBadGateway:: 502
+ # HTTPServiceUnavailable:: 503
+ # HTTPGatewayTimeOut:: 504
+ # HTTPVersionNotSupported:: 505
+ # HTTPInsufficientStorage:: 507
+ # HTTPNetworkAuthenticationRequired:: 511
+ #
+ # There is also the Net::HTTPBadResponse exception which is raised when
+ # there is a protocol error.
+ #
+ class HTTP < Protocol
+
+ # :stopdoc:
+ Revision = %q$Revision: 49278 $.split[1]
+ HTTPVersion = '1.1'
+ begin
+ require 'zlib'
+ require 'stringio' #for our purposes (unpacking gzip) lump these together
+ HAVE_ZLIB=true
+ rescue LoadError
+ HAVE_ZLIB=false
+ end
+ # :startdoc:
+
+ # Turns on net/http 1.2 (Ruby 1.8) features.
+ # Defaults to ON in Ruby 1.8 or later.
+ def HTTP.version_1_2
+ true
+ end
+
+ # Returns true if net/http is in version 1.2 mode.
+ # Defaults to true.
+ def HTTP.version_1_2?
+ true
+ end
+
+ def HTTP.version_1_1? #:nodoc:
+ false
+ end
+
+ class << HTTP
+ alias is_version_1_1? version_1_1? #:nodoc:
+ alias is_version_1_2? version_1_2? #:nodoc:
+ end
+
+ #
+ # short cut methods
+ #
+
+ #
+ # Gets the body text from the target and outputs it to $stdout. The
+ # target can either be specified as
+ # (+uri+), or as (+host+, +path+, +port+ = 80); so:
+ #
+ # Net::HTTP.get_print URI('http://www.example.com/index.html')
+ #
+ # or:
+ #
+ # Net::HTTP.get_print 'www.example.com', '/index.html'
+ #
+ def HTTP.get_print(uri_or_host, path = nil, port = nil)
+ get_response(uri_or_host, path, port) {|res|
+ res.read_body do |chunk|
+ $stdout.print chunk
+ end
+ }
+ nil
+ end
+
+ # Sends a GET request to the target and returns the HTTP response
+ # as a string. The target can either be specified as
+ # (+uri+), or as (+host+, +path+, +port+ = 80); so:
+ #
+ # print Net::HTTP.get(URI('http://www.example.com/index.html'))
+ #
+ # or:
+ #
+ # print Net::HTTP.get('www.example.com', '/index.html')
+ #
+ def HTTP.get(uri_or_host, path = nil, port = nil)
+ get_response(uri_or_host, path, port).body
+ end
+
+ # Sends a GET request to the target and returns the HTTP response
+ # as a Net::HTTPResponse object. The target can either be specified as
+ # (+uri+), or as (+host+, +path+, +port+ = 80); so:
+ #
+ # res = Net::HTTP.get_response(URI('http://www.example.com/index.html'))
+ # print res.body
+ #
+ # or:
+ #
+ # res = Net::HTTP.get_response('www.example.com', '/index.html')
+ # print res.body
+ #
+ def HTTP.get_response(uri_or_host, path = nil, port = nil, &block)
+ if path
+ host = uri_or_host
+ new(host, port || HTTP.default_port).start {|http|
+ return http.request_get(path, &block)
+ }
+ else
+ uri = uri_or_host
+ start(uri.hostname, uri.port,
+ :use_ssl => uri.scheme == 'https') {|http|
+ return http.request_get(uri, &block)
+ }
+ end
+ end
+
+ # Posts HTML form data to the specified URI object.
+ # The form data must be provided as a Hash mapping from String to String.
+ # Example:
+ #
+ # { "cmd" => "search", "q" => "ruby", "max" => "50" }
+ #
+ # This method also does Basic Authentication iff +url+.user exists.
+ # But userinfo for authentication is deprecated (RFC3986).
+ # So this feature will be removed.
+ #
+ # Example:
+ #
+ # require 'net/http'
+ # require 'uri'
+ #
+ # Net::HTTP.post_form URI('http://www.example.com/search.cgi'),
+ # { "q" => "ruby", "max" => "50" }
+ #
+ def HTTP.post_form(url, params)
+ req = Post.new(url)
+ req.form_data = params
+ req.basic_auth url.user, url.password if url.user
+ start(url.hostname, url.port,
+ :use_ssl => url.scheme == 'https' ) {|http|
+ http.request(req)
+ }
+ end
+
+ #
+ # HTTP session management
+ #
+
+ # The default port to use for HTTP requests; defaults to 80.
+ def HTTP.default_port
+ http_default_port()
+ end
+
+ # The default port to use for HTTP requests; defaults to 80.
+ def HTTP.http_default_port
+ 80
+ end
+
+ # The default port to use for HTTPS requests; defaults to 443.
+ def HTTP.https_default_port
+ 443
+ end
+
+ def HTTP.socket_type #:nodoc: obsolete
+ BufferedIO
+ end
+
+ # :call-seq:
+ # HTTP.start(address, port, p_addr, p_port, p_user, p_pass, &block)
+ # HTTP.start(address, port=nil, p_addr=nil, p_port=nil, p_user=nil, p_pass=nil, opt, &block)
+ #
+ # Creates a new Net::HTTP object, then additionally opens the TCP
+ # connection and HTTP session.
+ #
+ # Arguments are the following:
+ # _address_ :: hostname or IP address of the server
+ # _port_ :: port of the server
+ # _p_addr_ :: address of proxy
+ # _p_port_ :: port of proxy
+ # _p_user_ :: user of proxy
+ # _p_pass_ :: pass of proxy
+ # _opt_ :: optional hash
+ #
+ # _opt_ sets following values by its accessor.
+ # The keys are ca_file, ca_path, cert, cert_store, ciphers,
+ # close_on_empty_response, key, open_timeout, read_timeout, ssl_timeout,
+ # ssl_version, use_ssl, verify_callback, verify_depth and verify_mode.
+ # If you set :use_ssl as true, you can use https and default value of
+ # verify_mode is set as OpenSSL::SSL::VERIFY_PEER.
+ #
+ # If the optional block is given, the newly
+ # created Net::HTTP object is passed to it and closed when the
+ # block finishes. In this case, the return value of this method
+ # is the return value of the block. If no block is given, the
+ # return value of this method is the newly created Net::HTTP object
+ # itself, and the caller is responsible for closing it upon completion
+ # using the finish() method.
+ def HTTP.start(address, *arg, &block) # :yield: +http+
+ arg.pop if opt = Hash.try_convert(arg[-1])
+ port, p_addr, p_port, p_user, p_pass = *arg
+ port = https_default_port if !port && opt && opt[:use_ssl]
+ http = new(address, port, p_addr, p_port, p_user, p_pass)
+
+ if opt
+ if opt[:use_ssl]
+ opt = {verify_mode: OpenSSL::SSL::VERIFY_PEER}.update(opt)
+ end
+ http.methods.grep(/\A(\w+)=\z/) do |meth|
+ key = $1.to_sym
+ opt.key?(key) or next
+ http.__send__(meth, opt[key])
+ end
+ end
+
+ http.start(&block)
+ end
+
+ class << HTTP
+ alias newobj new # :nodoc:
+ end
+
+ # Creates a new Net::HTTP object without opening a TCP connection or
+ # HTTP session.
+ #
+ # The +address+ should be a DNS hostname or IP address, the +port+ is the
+ # port the server operates on. If no +port+ is given the default port for
+ # HTTP or HTTPS is used.
+ #
+ # If none of the +p_+ arguments are given, the proxy host and port are
+ # taken from the +http_proxy+ environment variable (or its uppercase
+ # equivalent) if present. If the proxy requires authentication you must
+ # supply it by hand. See URI::Generic#find_proxy for details of proxy
+ # detection from the environment. To disable proxy detection set +p_addr+
+ # to nil.
+ #
+ # If you are connecting to a custom proxy, +p_addr+ the DNS name or IP
+ # address of the proxy host, +p_port+ the port to use to access the proxy,
+ # and +p_user+ and +p_pass+ the username and password if authorization is
+ # required to use the proxy.
+ #
+ def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil)
+ http = super address, port
+
+ if proxy_class? then # from Net::HTTP::Proxy()
+ http.proxy_from_env = @proxy_from_env
+ http.proxy_address = @proxy_address
+ http.proxy_port = @proxy_port
+ http.proxy_user = @proxy_user
+ http.proxy_pass = @proxy_pass
+ elsif p_addr == :ENV then
+ http.proxy_from_env = true
+ else
+ http.proxy_address = p_addr
+ http.proxy_port = p_port || default_port
+ http.proxy_user = p_user
+ http.proxy_pass = p_pass
+ end
+
+ http
+ end
+
+ # Creates a new Net::HTTP object for the specified server address,
+ # without opening the TCP connection or initializing the HTTP session.
+ # The +address+ should be a DNS hostname or IP address.
+ def initialize(address, port = nil)
+ @address = address
+ @port = (port || HTTP.default_port)
+ @local_host = nil
+ @local_port = nil
+ @curr_http_version = HTTPVersion
+ @keep_alive_timeout = 2
+ @last_communicated = nil
+ @close_on_empty_response = false
+ @socket = nil
+ @started = false
+ @open_timeout = nil
+ @read_timeout = 60
+ @continue_timeout = nil
+ @debug_output = nil
+
+ @proxy_from_env = false
+ @proxy_uri = nil
+ @proxy_address = nil
+ @proxy_port = nil
+ @proxy_user = nil
+ @proxy_pass = nil
+
+ @use_ssl = false
+ @ssl_context = nil
+ @ssl_session = nil
+ @enable_post_connection_check = true
+ @sspi_enabled = false
+ SSL_IVNAMES.each do |ivname|
+ instance_variable_set ivname, nil
+ end
+ end
+
+ def inspect
+ "#<#{self.class} #{@address}:#{@port} open=#{started?}>"
+ end
+
+ # *WARNING* This method opens a serious security hole.
+ # Never use this method in production code.
+ #
+ # Sets an output stream for debugging.
+ #
+ # http = Net::HTTP.new(hostname)
+ # http.set_debug_output $stderr
+ # http.start { .... }
+ #
+ def set_debug_output(output)
+ warn 'Net::HTTP#set_debug_output called after HTTP started' if started?
+ @debug_output = output
+ end
+
+ # The DNS host name or IP address to connect to.
+ attr_reader :address
+
+ # The port number to connect to.
+ attr_reader :port
+
+ # The local host used to establish the connection.
+ attr_accessor :local_host
+
+ # The local port used to establish the connection.
+ attr_accessor :local_port
+
+ attr_writer :proxy_from_env
+ attr_writer :proxy_address
+ attr_writer :proxy_port
+ attr_writer :proxy_user
+ attr_writer :proxy_pass
+
+ # Number of seconds to wait for the connection to open. Any number
+ # may be used, including Floats for fractional seconds. If the HTTP
+ # object cannot open a connection in this many seconds, it raises a
+ # Net::OpenTimeout exception. The default value is +nil+.
+ attr_accessor :open_timeout
+
+ # Number of seconds to wait for one block to be read (via one read(2)
+ # call). Any number may be used, including Floats for fractional
+ # seconds. If the HTTP object cannot read data in this many seconds,
+ # it raises a Net::ReadTimeout exception. The default value is 60 seconds.
+ attr_reader :read_timeout
+
+ # Setter for the read_timeout attribute.
+ def read_timeout=(sec)
+ @socket.read_timeout = sec if @socket
+ @read_timeout = sec
+ end
+
+ # Seconds to wait for 100 Continue response. If the HTTP object does not
+ # receive a response in this many seconds it sends the request body. The
+ # default value is +nil+.
+ attr_reader :continue_timeout
+
+ # Setter for the continue_timeout attribute.
+ def continue_timeout=(sec)
+ @socket.continue_timeout = sec if @socket
+ @continue_timeout = sec
+ end
+
+ # Seconds to reuse the connection of the previous request.
+ # If the idle time is less than this Keep-Alive Timeout,
+ # Net::HTTP reuses the TCP/IP socket used by the previous communication.
+ # The default value is 2 seconds.
+ attr_accessor :keep_alive_timeout
+
+ # Returns true if the HTTP session has been started.
+ def started?
+ @started
+ end
+
+ alias active? started? #:nodoc: obsolete
+
+ attr_accessor :close_on_empty_response
+
+ # Returns true if SSL/TLS is being used with HTTP.
+ def use_ssl?
+ @use_ssl
+ end
+
+ # Turn on/off SSL.
+ # This flag must be set before starting session.
+ # If you change use_ssl value after session started,
+ # a Net::HTTP object raises IOError.
+ def use_ssl=(flag)
+ flag = flag ? true : false
+ if started? and @use_ssl != flag
+ raise IOError, "use_ssl value changed, but session already started"
+ end
+ @use_ssl = flag
+ end
+
+ SSL_IVNAMES = [
+ :@ca_file,
+ :@ca_path,
+ :@cert,
+ :@cert_store,
+ :@ciphers,
+ :@key,
+ :@ssl_timeout,
+ :@ssl_version,
+ :@verify_callback,
+ :@verify_depth,
+ :@verify_mode,
+ ]
+ SSL_ATTRIBUTES = [
+ :ca_file,
+ :ca_path,
+ :cert,
+ :cert_store,
+ :ciphers,
+ :key,
+ :ssl_timeout,
+ :ssl_version,
+ :verify_callback,
+ :verify_depth,
+ :verify_mode,
+ ]
+
+ # Sets path of a CA certification file in PEM format.
+ #
+ # The file can contain several CA certificates.
+ attr_accessor :ca_file
+
+ # Sets path of a CA certification directory containing certifications in
+ # PEM format.
+ attr_accessor :ca_path
+
+ # Sets an OpenSSL::X509::Certificate object as client certificate.
+ # (This method is appeared in Michal Rokos's OpenSSL extension).
+ attr_accessor :cert
+
+ # Sets the X509::Store to verify peer certificate.
+ attr_accessor :cert_store
+
+ # Sets the available ciphers. See OpenSSL::SSL::SSLContext#ciphers=
+ attr_accessor :ciphers
+
+ # Sets an OpenSSL::PKey::RSA or OpenSSL::PKey::DSA object.
+ # (This method is appeared in Michal Rokos's OpenSSL extension.)
+ attr_accessor :key
+
+ # Sets the SSL timeout seconds.
+ attr_accessor :ssl_timeout
+
+ # Sets the SSL version. See OpenSSL::SSL::SSLContext#ssl_version=
+ attr_accessor :ssl_version
+
+ # Sets the verify callback for the server certification verification.
+ attr_accessor :verify_callback
+
+ # Sets the maximum depth for the certificate chain verification.
+ attr_accessor :verify_depth
+
+ # Sets the flags for server the certification verification at beginning of
+ # SSL/TLS session.
+ #
+ # OpenSSL::SSL::VERIFY_NONE or OpenSSL::SSL::VERIFY_PEER are acceptable.
+ attr_accessor :verify_mode
+
+ # Returns the X.509 certificates the server presented.
+ def peer_cert
+ if not use_ssl? or not @socket
+ return nil
+ end
+ @socket.io.peer_cert
+ end
+
+ # Opens a TCP connection and HTTP session.
+ #
+ # When this method is called with a block, it passes the Net::HTTP
+ # object to the block, and closes the TCP connection and HTTP session
+ # after the block has been executed.
+ #
+ # When called with a block, it returns the return value of the
+ # block; otherwise, it returns self.
+ #
+ def start # :yield: http
+ raise IOError, 'HTTP session already opened' if @started
+ if block_given?
+ begin
+ do_start
+ return yield(self)
+ ensure
+ do_finish
+ end
+ end
+ do_start
+ self
+ end
+
+ def do_start
+ connect
+ @started = true
+ end
+ private :do_start
+
+ def connect
+ if proxy? then
+ conn_address = proxy_address
+ conn_port = proxy_port
+ else
+ conn_address = address
+ conn_port = port
+ end
+
+ D "opening connection to #{conn_address}:#{conn_port}..."
+ s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
+ TCPSocket.open(conn_address, conn_port, @local_host, @local_port)
+ }
+ s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
+ D "opened"
+ if use_ssl?
+ ssl_parameters = Hash.new
+ iv_list = instance_variables
+ SSL_IVNAMES.each_with_index do |ivname, i|
+ if iv_list.include?(ivname) and
+ value = instance_variable_get(ivname)
+ ssl_parameters[SSL_ATTRIBUTES[i]] = value if value
+ end
+ end
+ @ssl_context = OpenSSL::SSL::SSLContext.new
+ @ssl_context.set_params(ssl_parameters)
+ D "starting SSL for #{conn_address}:#{conn_port}..."
+ s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
+ s.sync_close = true
+ D "SSL established"
+ end
+ @socket = BufferedIO.new(s)
+ @socket.read_timeout = @read_timeout
+ @socket.continue_timeout = @continue_timeout
+ @socket.debug_output = @debug_output
+ if use_ssl?
+ begin
+ if proxy?
+ buf = "CONNECT #{@address}:#{@port} HTTP/#{HTTPVersion}\r\n"
+ buf << "Host: #{@address}:#{@port}\r\n"
+ if proxy_user
+ credential = ["#{proxy_user}:#{proxy_pass}"].pack('m')
+ credential.delete!("\r\n")
+ buf << "Proxy-Authorization: Basic #{credential}\r\n"
+ end
+ buf << "\r\n"
+ @socket.write(buf)
+ HTTPResponse.read_new(@socket).value
+ end
+ if @ssl_session and
+ Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
+ s.session = @ssl_session if @ssl_session
+ end
+ # Server Name Indication (SNI) RFC 3546
+ s.hostname = @address if s.respond_to? :hostname=
+ Timeout.timeout(@open_timeout, Net::OpenTimeout) { s.connect }
+ if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
+ s.post_connection_check(@address)
+ end
+ @ssl_session = s.session
+ rescue => exception
+ D "Conn close because of connect error #{exception}"
+ @socket.close if @socket and not @socket.closed?
+ raise exception
+ end
+ end
+ on_connect
+ end
+ private :connect
+
+ def on_connect
+ end
+ private :on_connect
+
+ # Finishes the HTTP session and closes the TCP connection.
+ # Raises IOError if the session has not been started.
+ def finish
+ raise IOError, 'HTTP session not yet started' unless started?
+ do_finish
+ end
+
+ def do_finish
+ @started = false
+ @socket.close if @socket and not @socket.closed?
+ @socket = nil
+ end
+ private :do_finish
+
+ #
+ # proxy
+ #
+
+ public
+
+ # no proxy
+ @is_proxy_class = false
+ @proxy_from_env = false
+ @proxy_addr = nil
+ @proxy_port = nil
+ @proxy_user = nil
+ @proxy_pass = nil
+
+ # Creates an HTTP proxy class which behaves like Net::HTTP, but
+ # performs all access via the specified proxy.
+ #
+ # This class is obsolete. You may pass these same parameters directly to
+ # Net::HTTP.new. See Net::HTTP.new for details of the arguments.
+ def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil)
+ return self unless p_addr
+
+ Class.new(self) {
+ @is_proxy_class = true
+
+ if p_addr == :ENV then
+ @proxy_from_env = true
+ @proxy_address = nil
+ @proxy_port = nil
+ else
+ @proxy_from_env = false
+ @proxy_address = p_addr
+ @proxy_port = p_port || default_port
+ end
+
+ @proxy_user = p_user
+ @proxy_pass = p_pass
+ }
+ end
+
+ class << HTTP
+ # returns true if self is a class which was created by HTTP::Proxy.
+ def proxy_class?
+ defined?(@is_proxy_class) ? @is_proxy_class : false
+ end
+
+ # Address of proxy host. If Net::HTTP does not use a proxy, nil.
+ attr_reader :proxy_address
+
+ # Port number of proxy host. If Net::HTTP does not use a proxy, nil.
+ attr_reader :proxy_port
+
+ # User name for accessing proxy. If Net::HTTP does not use a proxy, nil.
+ attr_reader :proxy_user
+
+ # User password for accessing proxy. If Net::HTTP does not use a proxy,
+ # nil.
+ attr_reader :proxy_pass
+ end
+
+ # True if requests for this connection will be proxied
+ def proxy?
+ !!if @proxy_from_env then
+ proxy_uri
+ else
+ @proxy_address
+ end
+ end
+
+ # True if the proxy for this connection is determined from the environment
+ def proxy_from_env?
+ @proxy_from_env
+ end
+
+ # The proxy URI determined from the environment for this connection.
+ def proxy_uri # :nodoc:
+ @proxy_uri ||= URI::HTTP.new(
+ "http".freeze, nil, address, port, nil, nil, nil, nil, nil
+ ).find_proxy
+ end
+
+ # The address of the proxy server, if one is configured.
+ def proxy_address
+ if @proxy_from_env then
+ proxy_uri && proxy_uri.hostname
+ else
+ @proxy_address
+ end
+ end
+
+ # The port of the proxy server, if one is configured.
+ def proxy_port
+ if @proxy_from_env then
+ proxy_uri && proxy_uri.port
+ else
+ @proxy_port
+ end
+ end
+
+ # The proxy username, if one is configured
+ def proxy_user
+ @proxy_user
+ end
+
+ # The proxy password, if one is configured
+ def proxy_pass
+ @proxy_pass
+ end
+
+ alias proxyaddr proxy_address #:nodoc: obsolete
+ alias proxyport proxy_port #:nodoc: obsolete
+
+ private
+
+ # without proxy, obsolete
+
+ def conn_address # :nodoc:
+ address()
+ end
+
+ def conn_port # :nodoc:
+ port()
+ end
+
+ def edit_path(path)
+ if proxy? and not use_ssl? then
+ "http://#{addr_port}#{path}"
+ else
+ path
+ end
+ end
+
+ #
+ # HTTP operations
+ #
+
+ public
+
+ # Retrieves data from +path+ on the connected-to host which may be an
+ # absolute path String or a URI to extract the path from.
+ #
+ # +initheader+ must be a Hash like { 'Accept' => '*/*', ... },
+ # and it defaults to an empty hash.
+ # If +initheader+ doesn't have the key 'accept-encoding', then
+ # a value of "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" is used,
+ # so that gzip compression is used in preference to deflate
+ # compression, which is used in preference to no compression.
+ # Ruby doesn't have libraries to support the compress (Lempel-Ziv)
+ # compression, so that is not supported. The intent of this is
+ # to reduce bandwidth by default. If this routine sets up
+ # compression, then it does the decompression also, removing
+ # the header as well to prevent confusion. Otherwise
+ # it leaves the body as it found it.
+ #
+ # This method returns a Net::HTTPResponse object.
+ #
+ # If called with a block, yields each fragment of the
+ # entity body in turn as a string as it is read from
+ # the socket. Note that in this case, the returned response
+ # object will *not* contain a (meaningful) body.
+ #
+ # +dest+ argument is obsolete.
+ # It still works but you must not use it.
+ #
+ # This method never raises an exception.
+ #
+ # response = http.get('/index.html')
+ #
+ # # using block
+ # File.open('result.txt', 'w') {|f|
+ # http.get('/~foo/') do |str|
+ # f.write str
+ # end
+ # }
+ #
+ def get(path, initheader = nil, dest = nil, &block) # :yield: +body_segment+
+ res = nil
+ request(Get.new(path, initheader)) {|r|
+ r.read_body dest, &block
+ res = r
+ }
+ res
+ end
+
+ # Gets only the header from +path+ on the connected-to host.
+ # +header+ is a Hash like { 'Accept' => '*/*', ... }.
+ #
+ # This method returns a Net::HTTPResponse object.
+ #
+ # This method never raises an exception.
+ #
+ # response = nil
+ # Net::HTTP.start('some.www.server', 80) {|http|
+ # response = http.head('/index.html')
+ # }
+ # p response['content-type']
+ #
+ def head(path, initheader = nil)
+ request(Head.new(path, initheader))
+ end
+
+ # Posts +data+ (must be a String) to +path+. +header+ must be a Hash
+ # like { 'Accept' => '*/*', ... }.
+ #
+ # This method returns a Net::HTTPResponse object.
+ #
+ # If called with a block, yields each fragment of the
+ # entity body in turn as a string as it is read from
+ # the socket. Note that in this case, the returned response
+ # object will *not* contain a (meaningful) body.
+ #
+ # +dest+ argument is obsolete.
+ # It still works but you must not use it.
+ #
+ # This method never raises exception.
+ #
+ # response = http.post('/cgi-bin/search.rb', 'query=foo')
+ #
+ # # using block
+ # File.open('result.txt', 'w') {|f|
+ # http.post('/cgi-bin/search.rb', 'query=foo') do |str|
+ # f.write str
+ # end
+ # }
+ #
+ # You should set Content-Type: header field for POST.
+ # If no Content-Type: field given, this method uses
+ # "application/x-www-form-urlencoded" by default.
+ #
+ def post(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
+ send_entity(path, data, initheader, dest, Post, &block)
+ end
+
+ # Sends a PATCH request to the +path+ and gets a response,
+ # as an HTTPResponse object.
+ def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
+ send_entity(path, data, initheader, dest, Patch, &block)
+ end
+
+ def put(path, data, initheader = nil) #:nodoc:
+ request(Put.new(path, initheader), data)
+ end
+
+ # Sends a PROPPATCH request to the +path+ and gets a response,
+ # as an HTTPResponse object.
+ def proppatch(path, body, initheader = nil)
+ request(Proppatch.new(path, initheader), body)
+ end
+
+ # Sends a LOCK request to the +path+ and gets a response,
+ # as an HTTPResponse object.
+ def lock(path, body, initheader = nil)
+ request(Lock.new(path, initheader), body)
+ end
+
+ # Sends a UNLOCK request to the +path+ and gets a response,
+ # as an HTTPResponse object.
+ def unlock(path, body, initheader = nil)
+ request(Unlock.new(path, initheader), body)
+ end
+
+ # Sends a OPTIONS request to the +path+ and gets a response,
+ # as an HTTPResponse object.
+ def options(path, initheader = nil)
+ request(Options.new(path, initheader))
+ end
+
+ # Sends a PROPFIND request to the +path+ and gets a response,
+ # as an HTTPResponse object.
+ def propfind(path, body = nil, initheader = {'Depth' => '0'})
+ request(Propfind.new(path, initheader), body)
+ end
+
+ # Sends a DELETE request to the +path+ and gets a response,
+ # as an HTTPResponse object.
+ def delete(path, initheader = {'Depth' => 'Infinity'})
+ request(Delete.new(path, initheader))
+ end
+
+ # Sends a MOVE request to the +path+ and gets a response,
+ # as an HTTPResponse object.
+ def move(path, initheader = nil)
+ request(Move.new(path, initheader))
+ end
+
+ # Sends a COPY request to the +path+ and gets a response,
+ # as an HTTPResponse object.
+ def copy(path, initheader = nil)
+ request(Copy.new(path, initheader))
+ end
+
+ # Sends a MKCOL request to the +path+ and gets a response,
+ # as an HTTPResponse object.
+ def mkcol(path, body = nil, initheader = nil)
+ request(Mkcol.new(path, initheader), body)
+ end
+
+ # Sends a TRACE request to the +path+ and gets a response,
+ # as an HTTPResponse object.
+ def trace(path, initheader = nil)
+ request(Trace.new(path, initheader))
+ end
+
+ # Sends a GET request to the +path+.
+ # Returns the response as a Net::HTTPResponse object.
+ #
+ # When called with a block, passes an HTTPResponse object to the block.
+ # The body of the response will not have been read yet;
+ # the block can process it using HTTPResponse#read_body,
+ # if desired.
+ #
+ # Returns the response.
+ #
+ # This method never raises Net::* exceptions.
+ #
+ # response = http.request_get('/index.html')
+ # # The entity body is already read in this case.
+ # p response['content-type']
+ # puts response.body
+ #
+ # # Using a block
+ # http.request_get('/index.html') {|response|
+ # p response['content-type']
+ # response.read_body do |str| # read body now
+ # print str
+ # end
+ # }
+ #
+ def request_get(path, initheader = nil, &block) # :yield: +response+
+ request(Get.new(path, initheader), &block)
+ end
+
+ # Sends a HEAD request to the +path+ and returns the response
+ # as a Net::HTTPResponse object.
+ #
+ # Returns the response.
+ #
+ # This method never raises Net::* exceptions.
+ #
+ # response = http.request_head('/index.html')
+ # p response['content-type']
+ #
+ def request_head(path, initheader = nil, &block)
+ request(Head.new(path, initheader), &block)
+ end
+
+ # Sends a POST request to the +path+.
+ #
+ # Returns the response as a Net::HTTPResponse object.
+ #
+ # When called with a block, the block is passed an HTTPResponse
+ # object. The body of that response will not have been read yet;
+ # the block can process it using HTTPResponse#read_body, if desired.
+ #
+ # Returns the response.
+ #
+ # This method never raises Net::* exceptions.
+ #
+ # # example
+ # response = http.request_post('/cgi-bin/nice.rb', 'datadatadata...')
+ # p response.status
+ # puts response.body # body is already read in this case
+ #
+ # # using block
+ # http.request_post('/cgi-bin/nice.rb', 'datadatadata...') {|response|
+ # p response.status
+ # p response['content-type']
+ # response.read_body do |str| # read body now
+ # print str
+ # end
+ # }
+ #
+ def request_post(path, data, initheader = nil, &block) # :yield: +response+
+ request Post.new(path, initheader), data, &block
+ end
+
+ def request_put(path, data, initheader = nil, &block) #:nodoc:
+ request Put.new(path, initheader), data, &block
+ end
+
+ alias get2 request_get #:nodoc: obsolete
+ alias head2 request_head #:nodoc: obsolete
+ alias post2 request_post #:nodoc: obsolete
+ alias put2 request_put #:nodoc: obsolete
+
+
+ # Sends an HTTP request to the HTTP server.
+ # Also sends a DATA string if +data+ is given.
+ #
+ # Returns a Net::HTTPResponse object.
+ #
+ # This method never raises Net::* exceptions.
+ #
+ # response = http.send_request('GET', '/index.html')
+ # puts response.body
+ #
+ def send_request(name, path, data = nil, header = nil)
+ has_response_body = name != 'HEAD'
+ r = HTTPGenericRequest.new(name,(data ? true : false),has_response_body,path,header)
+ request r, data
+ end
+
+ # Sends an HTTPRequest object +req+ to the HTTP server.
+ #
+ # If +req+ is a Net::HTTP::Post or Net::HTTP::Put request containing
+ # data, the data is also sent. Providing data for a Net::HTTP::Head or
+ # Net::HTTP::Get request results in an ArgumentError.
+ #
+ # Returns an HTTPResponse object.
+ #
+ # When called with a block, passes an HTTPResponse object to the block.
+ # The body of the response will not have been read yet;
+ # the block can process it using HTTPResponse#read_body,
+ # if desired.
+ #
+ # This method never raises Net::* exceptions.
+ #
+ def request(req, body = nil, &block) # :yield: +response+
+ unless started?
+ start {
+ req['connection'] ||= 'close'
+ return request(req, body, &block)
+ }
+ end
+ if proxy_user()
+ req.proxy_basic_auth proxy_user(), proxy_pass() unless use_ssl?
+ end
+ req.set_body_internal body
+ res = transport_request(req, &block)
+ if sspi_auth?(res)
+ sspi_auth(req)
+ res = transport_request(req, &block)
+ end
+ res
+ end
+
+ private
+
+ # Executes a request which uses a representation
+ # and returns its body.
+ def send_entity(path, data, initheader, dest, type, &block)
+ res = nil
+ request(type.new(path, initheader), data) {|r|
+ r.read_body dest, &block
+ res = r
+ }
+ res
+ end
+
+ IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:
+
+ def transport_request(req)
+ count = 0
+ begin
+ begin_transport req
+ res = catch(:response) {
+ req.exec @socket, @curr_http_version, edit_path(req.path)
+ begin
+ res = HTTPResponse.read_new(@socket)
+ res.decode_content = req.decode_content
+ end while res.kind_of?(HTTPContinue)
+
+ res.uri = req.uri
+
+ res.reading_body(@socket, req.response_body_permitted?) {
+ yield res if block_given?
+ }
+ res
+ }
+ rescue Net::OpenTimeout
+ raise
+ rescue Net::ReadTimeout, IOError, EOFError,
+ Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE,
+ # avoid a dependency on OpenSSL
+ defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : IOError,
+ Timeout::Error => exception
+ if count == 0 && IDEMPOTENT_METHODS_.include?(req.method)
+ count += 1
+ @socket.close if @socket and not @socket.closed?
+ D "Conn close because of error #{exception}, and retry"
+ retry
+ end
+ D "Conn close because of error #{exception}"
+ @socket.close if @socket and not @socket.closed?
+ raise
+ end
+
+ end_transport req, res
+ res
+ rescue => exception
+ D "Conn close because of error #{exception}"
+ @socket.close if @socket and not @socket.closed?
+ raise exception
+ end
+
+ def begin_transport(req)
+ if @socket.closed?
+ connect
+ elsif @last_communicated && @last_communicated + @keep_alive_timeout < Time.now
+ D 'Conn close because of keep_alive_timeout'
+ @socket.close
+ connect
+ end
+
+ if not req.response_body_permitted? and @close_on_empty_response
+ req['connection'] ||= 'close'
+ end
+
+ req.update_uri address, port, use_ssl?
+ req['host'] ||= addr_port()
+ end
+
+ def end_transport(req, res)
+ @curr_http_version = res.http_version
+ @last_communicated = nil
+ if @socket.closed?
+ D 'Conn socket closed'
+ elsif not res.body and @close_on_empty_response
+ D 'Conn close'
+ @socket.close
+ elsif keep_alive?(req, res)
+ D 'Conn keep-alive'
+ @last_communicated = Time.now
+ else
+ D 'Conn close'
+ @socket.close
+ end
+ end
+
+ def keep_alive?(req, res)
+ return false if req.connection_close?
+ if @curr_http_version <= '1.0'
+ res.connection_keep_alive?
+ else # HTTP/1.1 or later
+ not res.connection_close?
+ end
+ end
+
+ def sspi_auth?(res)
+ return false unless @sspi_enabled
+ if res.kind_of?(HTTPProxyAuthenticationRequired) and
+ proxy? and res["Proxy-Authenticate"].include?("Negotiate")
+ begin
+ require 'win32/sspi'
+ true
+ rescue LoadError
+ false
+ end
+ else
+ false
+ end
+ end
+
+ def sspi_auth(req)
+ n = Win32::SSPI::NegotiateAuth.new
+ req["Proxy-Authorization"] = "Negotiate #{n.get_initial_token}"
+ # Some versions of ISA will close the connection if this isn't present.
+ req["Connection"] = "Keep-Alive"
+ req["Proxy-Connection"] = "Keep-Alive"
+ res = transport_request(req)
+ authphrase = res["Proxy-Authenticate"] or return res
+ req["Proxy-Authorization"] = "Negotiate #{n.complete_authentication(authphrase)}"
+ rescue => err
+ raise HTTPAuthenticationError.new('HTTP authentication failed', err)
+ end
+
+ #
+ # utils
+ #
+
+ private
+
+ def addr_port
+ if use_ssl?
+ address() + (port == HTTP.https_default_port ? '' : ":#{port()}")
+ else
+ address() + (port == HTTP.http_default_port ? '' : ":#{port()}")
+ end
+ end
+
+ def D(msg)
+ return unless @debug_output
+ @debug_output << msg
+ @debug_output << "\n"
+ end
+ end
+
+end
+
+require 'net/http/exceptions'
+
+require 'net/http/header'
+
+require 'net/http/generic_request'
+require 'net/http/request'
+require 'net/http/requests'
+
+require 'net/http/response'
+require 'net/http/responses'
+
+require 'net/http/proxy_delta'
+
+require 'net/http/backward'
+