Index: lib/net/http.rb =================================================================== --- lib/net/http.rb (revision 36037) +++ lib/net/http.rb (working copy) @@ -268,7 +268,18 @@ 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 + # can create a proxy from the +HTTP_PROXY+ environment variable if +:ENV+ is + # used for the proxy address: + # + # Net::HTTP::Proxy(:ENV).start('www.example.com') { |http| + # # connect with ENV['HTTP_PROXY'] if available + # end + # + # 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 +288,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. # @@ -878,15 +886,21 @@ 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 +:ENV+ is given for +p_addr+, 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). # # 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 +921,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 = nil, 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 +943,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