Index: lib/net/http.rb =================================================================== --- lib/net/http.rb (revision 36037) +++ lib/net/http.rb (working copy) @@ -268,7 +268,13 @@ module Net #:nodoc: # === Proxies # # Net::HTTP::Proxy has the same methods as Net::HTTP but its instances always - # connect via the proxy instead of directly to the given host. + # connect via the proxy instead of directly to the given host. 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. Net::HTTP will be returned when no proxy is configured + # so there is no need for conditional code. + # + # You may also create a custom proxy: # # proxy_addr = 'your.proxy.host' # proxy_port = 8080 @@ -277,9 +283,6 @@ module Net #:nodoc: # # always connect to your.proxy.addr:8080 # } # - # Net::HTTP::Proxy returns a Net::HTTP instance when proxy_addr is nil so - # there is no need for conditional code. - # # See Net::HTTP::Proxy for further details and examples such as proxies that # require a username and password. # @@ -571,7 +574,7 @@ module Net #:nodoc: # HTTP session. # The +address+ should be a DNS hostname or IP address. # If +p_addr+ is given, creates a Net::HTTP object with proxy support. - def HTTP.new(address, port = nil, p_addr = nil, p_port = nil, p_user = nil, p_pass = nil) + def HTTP.new(address, port = nil, p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil) Proxy(p_addr, p_port, p_user, p_pass).newobj(address, port) end @@ -878,15 +881,24 @@ module Net #:nodoc: # Creates an HTTP proxy class which behaves like Net::HTTP, but # performs all access via the specified proxy. # - # The arguments are the DNS name or IP address of the proxy host, - # the port to use to access the proxy, and a username and password - # if authorization is required to use the proxy. + # If no arguments are given, the proxy host and port are taken from the + # +HTTP_PROXY+ environment variable (or its lowercase equivalent) if + # present. If the proxy requires authentication you must supply it by + # hand. + # + # If you are connecting to a custom proxy, the arguments are the DNS name + # or IP address of the proxy host, the port to use to access the proxy, + # and a username and password if authorization is required to use the + # proxy. + # + # If +p_addr+ is nil, this method returns self (a Net::HTTP object). If + # +p_addr+ is +:ENV+ the proxy is constructed from +HTTP_PROXY+ and +p_addr+ + # is determined automatically. You may use +:ENV+ with +p_user+ and + # +p_pass+ to provide authentication for +HTTP_PROXY+. # # You can replace any use of the Net::HTTP class with use of the # proxy class created. # - # If +p_addr+ is nil, this method returns self (a Net::HTTP object). - # # # Example # proxy_class = Net::HTTP::Proxy('proxy.example.com', 8080) # @@ -907,15 +919,21 @@ module Net #:nodoc: # # and password # } # - # Note that net/http does not use the HTTP_PROXY environment variable. - # If you want to use a proxy, you must set it explicitly. - # - def HTTP.Proxy(p_addr, p_port = nil, p_user = nil, p_pass = nil) + def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil) return self unless p_addr - delta = ProxyDelta - proxyclass = Class.new(self) - proxyclass.module_eval { - include delta + + if p_addr == :ENV then + env_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY'] + + return self unless env_proxy + + env_proxy =~ /:([^\]]+)\z/ # handle IPv6 address like [::1]:8000 + p_addr = $` || env_proxy + p_port = $1.to_i if $1 + end + + Class.new(self) { + include Net::HTTP::ProxyDelta # with proxy @is_proxy_class = true @proxy_address = p_addr @@ -923,7 +941,6 @@ module Net #:nodoc: @proxy_user = p_user @proxy_pass = p_pass } - proxyclass end class << HTTP Index: test/net/http/test_http.rb =================================================================== --- test/net/http/test_http.rb (revision 36037) +++ test/net/http/test_http.rb (working copy) @@ -5,6 +5,132 @@ require 'net/http' require 'stringio' require_relative 'utils' +class TestNetHTTP < Test::Unit::TestCase + + def test_class_Proxy + no_proxy_class = Net::HTTP.Proxy nil + + assert_equal Net::HTTP, no_proxy_class + + proxy_class = Net::HTTP.Proxy 'proxy.example', 8000, 'user', 'pass' + + refute_equal Net::HTTP, proxy_class + + assert_operator proxy_class, :<, Net::HTTP + + assert_equal 'proxy.example', proxy_class.proxy_address + assert_equal 8000, proxy_class.proxy_port + assert_equal 'user', proxy_class.proxy_user + assert_equal 'pass', proxy_class.proxy_pass + end + + def test_class_Proxy_from_ENV + clean_http_proxy_env do + ENV['HTTP_PROXY'] = 'proxy.example:8000' + + # These are ignored on purpose. See Bug 4388 and Feature 6546 + ENV['HTTP_PROXY_USER'] = 'user' + ENV['HTTP_PROXY_PASS'] = 'pass' + + proxy_class = Net::HTTP.Proxy :ENV + + refute_equal Net::HTTP, proxy_class + + assert_operator proxy_class, :<, Net::HTTP + + assert_equal 'proxy.example', proxy_class.proxy_address + assert_equal 8000, proxy_class.proxy_port + assert_nil proxy_class.proxy_user + assert_nil proxy_class.proxy_pass + end + end + + def test_class_Proxy_from_ENV_ipv6 + clean_http_proxy_env do + ENV['HTTP_PROXY'] = '[::1]:8000' + + proxy_class = Net::HTTP.Proxy :ENV + + refute_equal Net::HTTP, proxy_class + + assert_operator proxy_class, :<, Net::HTTP + + assert_equal '[::1]', proxy_class.proxy_address + assert_equal 8000, proxy_class.proxy_port + assert_nil proxy_class.proxy_user + assert_nil proxy_class.proxy_pass + end + end + + def test_class_Proxy_from_ENV_lowercase + clean_http_proxy_env do + ENV['http_proxy'] = 'proxy.example:8000' + + # These are ignored on purpose. See Bug 4388 and Feature 6546 + ENV['http_proxy_user'] = 'user' + ENV['http_proxy_pass'] = 'pass' + + proxy_class = Net::HTTP.Proxy :ENV + + refute_equal Net::HTTP, proxy_class + + assert_operator proxy_class, :<, Net::HTTP + + assert_equal 'proxy.example', proxy_class.proxy_address + assert_equal 8000, proxy_class.proxy_port + assert_nil proxy_class.proxy_user + assert_nil proxy_class.proxy_pass + end + end + + def test_class_Proxy_from_ENV_none + clean_http_proxy_env do + no_proxy_class = Net::HTTP.Proxy :ENV + + assert_equal Net::HTTP, no_proxy_class + end + end + + def test_class_Proxy_from_ENV_no_port + clean_http_proxy_env do + ENV['HTTP_PROXY'] = 'proxy.example' + + proxy_class = Net::HTTP.Proxy :ENV + + refute_equal Net::HTTP, proxy_class + + assert_operator proxy_class, :<, Net::HTTP + + assert_equal 'proxy.example', proxy_class.proxy_address + assert_equal 80, proxy_class.proxy_port + assert_nil proxy_class.proxy_user + assert_nil proxy_class.proxy_pass + end + end + + def clean_http_proxy_env + orig = { + 'HTTP_PROXY' => ENV['HTTP_PROXY'], + 'http_proxy' => ENV['HTTP_PROXY'], + 'HTTP_PROXY_USER' => ENV['HTTP_PROXY_USER'], + 'http_proxy_user' => ENV['http_proxy_user'], + 'HTTP_PROXY_PASS' => ENV['HTTP_PROXY_PASS'], + 'http_proxy_pass' => ENV['http_proxy_pass'], + } + + orig.each_key do |key| + ENV.delete key + end + + yield + ensure + orig.each do |key, value| + ENV[key] = value + end + end + +end + module TestNetHTTP_version_1_1_methods def test_s_get