diff options
author | hsbt <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-09-14 03:30:02 +0000 |
---|---|---|
committer | hsbt <hsbt@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2014-09-14 03:30:02 +0000 |
commit | 4de117a61517e839f2c45eaf45d56fc243d6d5b2 (patch) | |
tree | 7cb5af7a7eb513e5dddf5e343746b1611e628387 /lib/rubygems/remote_fetcher.rb | |
parent | e548c09d429a5136285ea81aed418685359ed124 (diff) | |
download | ruby-4de117a61517e839f2c45eaf45d56fc243d6d5b2.tar.gz |
* lib/rubygems: Update to RubyGems 2.4.1 master(713ab65)
Complete history at:
https://github.com/rubygems/rubygems/blob/master/History.txt#L3-L216
* test/rubygems: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47582 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/rubygems/remote_fetcher.rb')
-rw-r--r-- | lib/rubygems/remote_fetcher.rb | 71 |
1 files changed, 58 insertions, 13 deletions
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb index d5af458dfe..607827c47e 100644 --- a/lib/rubygems/remote_fetcher.rb +++ b/lib/rubygems/remote_fetcher.rb @@ -2,6 +2,7 @@ require 'rubygems' require 'rubygems/request' require 'rubygems/uri_formatter' require 'rubygems/user_interaction' +require 'rubygems/request/connection_pools' require 'resolv' ## @@ -73,6 +74,9 @@ class Gem::RemoteFetcher Socket.do_not_reverse_lookup = true @proxy = proxy + @pools = {} + @pool_lock = Mutex.new + @cert_files = Gem::Request.get_cert_files @dns = dns end @@ -154,11 +158,10 @@ class Gem::RemoteFetcher # REFACTOR: split this up and dispatch on scheme (eg download_http) # REFACTOR: be sure to clean up fake fetcher when you do this... cleaner case scheme - when 'http', 'https' then + when 'http', 'https', 's3' then unless File.exist? local_gem_path then begin - say "Downloading gem #{gem_file_name}" if - Gem.configuration.really_verbose + verbose "Downloading gem #{gem_file_name}" remote_gem_path = source_uri + "gems/#{gem_file_name}" @@ -168,8 +171,7 @@ class Gem::RemoteFetcher alternate_name = "#{spec.original_name}.gem" - say "Failed, downloading gem #{alternate_name}" if - Gem.configuration.really_verbose + verbose "Failed, downloading gem #{alternate_name}" remote_gem_path = source_uri + "gems/#{alternate_name}" @@ -188,8 +190,7 @@ class Gem::RemoteFetcher local_gem_path = source_uri.to_s end - say "Using local gem #{local_gem_path}" if - Gem.configuration.really_verbose + verbose "Using local gem #{local_gem_path}" when nil then # TODO test for local overriding cache source_path = if Gem.win_platform? && source_uri.scheme && !source_uri.path.include?(':') then @@ -207,8 +208,7 @@ class Gem::RemoteFetcher local_gem_path = source_uri.to_s end - say "Using local gem #{local_gem_path}" if - Gem.configuration.really_verbose + verbose "Using local gem #{local_gem_path}" else raise ArgumentError, "unsupported URI scheme #{source_uri.scheme}" end @@ -232,6 +232,7 @@ class Gem::RemoteFetcher case response when Net::HTTPOK, Net::HTTPNotModified then + response.uri = uri if response.respond_to? :uri head ? response : response.body when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther, Net::HTTPTemporaryRedirect then @@ -265,7 +266,7 @@ class Gem::RemoteFetcher data = send "fetch_#{uri.scheme}", uri, mtime, head - if data and !head and uri.to_s =~ /gz$/ + if data and !head and uri.to_s =~ /\.gz$/ begin data = Gem.gunzip data rescue Zlib::GzipFile::Error @@ -286,6 +287,11 @@ class Gem::RemoteFetcher end end + def fetch_s3(uri, mtime = nil, head = false) + public_uri = sign_s3_url(uri) + fetch_https public_uri, mtime, head + end + ## # Downloads +uri+ to +path+ if necessary. If no path is given, it just # passes the data. @@ -332,18 +338,57 @@ class Gem::RemoteFetcher # connections to reduce connect overhead. def request(uri, request_class, last_modified = nil) - request = Gem::Request.new uri, request_class, last_modified, @proxy + proxy = proxy_for @proxy, uri + pool = pools_for(proxy).pool_for uri + + request = Gem::Request.new uri, request_class, last_modified, pool request.fetch do |req| yield req if block_given? end - ensure - request.close if request end def https?(uri) uri.scheme.downcase == 'https' end + protected + + # we have our own signing code here to avoid a dependency on the aws-sdk gem + # fortunately, a simple GET request isn't too complex to sign properly + def sign_s3_url(uri, expiration = nil) + require 'base64' + require 'openssl' + + unless uri.user && uri.password + raise FetchError.new("credentials needed in s3 source, like s3://key:secret@bucket-name/", uri.to_s) + end + + expiration ||= s3_expiration + canonical_path = "/#{uri.host}#{uri.path}" + payload = "GET\n\n\n#{expiration}\n#{canonical_path}" + digest = OpenSSL::HMAC.digest('sha1', uri.password, payload) + # URI.escape is deprecated, and there isn't yet a replacement that does quite what we want + signature = Base64.encode64(digest).gsub("\n", '').gsub(/[\+\/=]/) { |c| BASE64_URI_TRANSLATE[c] } + URI.parse("https://#{uri.host}.s3.amazonaws.com#{uri.path}?AWSAccessKeyId=#{uri.user}&Expires=#{expiration}&Signature=#{signature}") + end + + def s3_expiration + (Time.now + 3600).to_i # one hour from now + end + + BASE64_URI_TRANSLATE = { '+' => '%2B', '/' => '%2F', '=' => '%3D' }.freeze + + private + + def proxy_for proxy, uri + Gem::Request.proxy_uri(proxy || Gem::Request.get_proxy_from_env(uri.scheme)) + end + + def pools_for proxy + @pool_lock.synchronize do + @pools[proxy] ||= Gem::Request::ConnectionPools.new proxy, @cert_files + end + end end |