summaryrefslogtreecommitdiff
path: root/lib/rubygems/remote_fetcher.rb
diff options
context:
space:
mode:
authordrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-06-26 02:06:00 +0000
committerdrbrain <drbrain@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-06-26 02:06:00 +0000
commit8b424513fd43c398aaeea5dede8bbc5c51602773 (patch)
treeb1509d7a77a52206f7825520c99a693f7818a8a4 /lib/rubygems/remote_fetcher.rb
parentdbf3fb3d8e6e10e2ac2af19937e0016a4815ca50 (diff)
Upgrade to RubyGems 1.2.0 r1824. Incorporates [ruby-core:17353].
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/rubygems/remote_fetcher.rb')
-rw-r--r--lib/rubygems/remote_fetcher.rb104
1 files changed, 55 insertions, 49 deletions
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb
index 93252fe83a..3c747f1d65 100644
--- a/lib/rubygems/remote_fetcher.rb
+++ b/lib/rubygems/remote_fetcher.rb
@@ -1,5 +1,6 @@
require 'net/http'
require 'stringio'
+require 'time'
require 'uri'
require 'rubygems'
@@ -74,7 +75,12 @@ class Gem::RemoteFetcher
# always replaced.
def download(spec, source_uri, install_dir = Gem.dir)
- cache_dir = File.join install_dir, 'cache'
+ if File.writable?(install_dir)
+ cache_dir = File.join install_dir, 'cache'
+ else
+ cache_dir = File.join(ENV['HOME'], '.gem', 'cache')
+ end
+
gem_file_name = "#{spec.full_name}.gem"
local_gem_path = File.join cache_dir, gem_file_name
@@ -132,49 +138,27 @@ class Gem::RemoteFetcher
##
# Downloads +uri+ and returns it as a String.
- def fetch_path(uri)
- open_uri_or_path(uri) do |input|
- input.read
- end
+ def fetch_path(uri, mtime = nil, head = false)
+ data = open_uri_or_path(uri, mtime, head)
+ data = Gem.gunzip data if uri.to_s =~ /gz$/ and not head
+ data
rescue FetchError
raise
rescue Timeout::Error
raise FetchError.new('timed out', uri)
rescue IOError, SocketError, SystemCallError => e
raise FetchError.new("#{e.class}: #{e}", uri)
- rescue => e
- raise FetchError.new("#{e.class}: #{e}", uri)
end
##
# Returns the size of +uri+ in bytes.
- def fetch_size(uri)
- return File.size(get_file_uri_path(uri)) if file_uri? uri
-
- uri = URI.parse uri unless URI::Generic === uri
-
- raise ArgumentError, 'uri is not an HTTP URI' unless URI::HTTP === uri
-
- response = request uri, Net::HTTP::Head
+ def fetch_size(uri) # TODO: phase this out
+ response = fetch_path(uri, nil, true)
- if response.code !~ /^2/ then
- raise FetchError.new("bad response #{response.message} #{response.code}", uri)
- end
-
- if response['content-length'] then
- return response['content-length'].to_i
- else
- response = http.get uri.request_uri
- return response.body.size
- end
-
- rescue SocketError, SystemCallError, Timeout::Error => e
- raise FetchError.new("#{e.message} (#{e.class})\n\tfetching size", uri)
+ response['content-length'].to_i
end
- private
-
def escape(str)
return unless str
URI.escape(str)
@@ -245,24 +229,26 @@ class Gem::RemoteFetcher
# Read the data from the (source based) URI, but if it is a file:// URI,
# read from the filesystem instead.
- def open_uri_or_path(uri, depth = 0, &block)
- if file_uri?(uri)
- open(get_file_uri_path(uri), &block)
- else
- uri = URI.parse uri unless URI::Generic === uri
+ def open_uri_or_path(uri, last_modified = nil, head = false, depth = 0)
+ raise "block is dead" if block_given?
- response = request uri
+ return open(get_file_uri_path(uri)) if file_uri? uri
- case response
- when Net::HTTPOK then
- block.call(StringIO.new(response.body)) if block
- when Net::HTTPRedirection then
- raise FetchError.new('too many redirects', uri) if depth > 10
+ uri = URI.parse uri unless URI::Generic === uri
+ raise ArgumentError, 'uri is not an HTTP URI' unless URI::HTTP === uri
- open_uri_or_path(response['Location'], depth + 1, &block)
- else
- raise FetchError.new("bad response #{response.message} #{response.code}", uri)
- end
+ fetch_type = head ? Net::HTTP::Head : Net::HTTP::Get
+ response = request uri, fetch_type, last_modified
+
+ case response
+ when Net::HTTPOK then
+ head ? response : response.body
+ when Net::HTTPRedirection then
+ raise FetchError.new('too many redirects', uri) if depth > 10
+
+ open_uri_or_path(response['Location'], last_modified, head, depth + 1)
+ else
+ raise FetchError.new("bad response #{response.message} #{response.code}", uri)
end
end
@@ -271,7 +257,7 @@ class Gem::RemoteFetcher
# a Net::HTTP response object. request maintains a table of persistent
# connections to reduce connect overhead.
- def request(uri, request_class = Net::HTTP::Get)
+ def request(uri, request_class, last_modified = nil)
request = request_class.new uri.request_uri
unless uri.nil? || uri.user.nil? || uri.user.empty? then
@@ -287,9 +273,14 @@ class Gem::RemoteFetcher
request.add_field 'Connection', 'keep-alive'
request.add_field 'Keep-Alive', '30'
+ if last_modified then
+ request.add_field 'If-Modified-Since', last_modified.rfc2822
+ end
+
connection = connection_for uri
retried = false
+ bad_response = false
# HACK work around EOFError bug in Net::HTTP
# NOTE Errno::ECONNABORTED raised a lot on Windows, and make impossible
@@ -299,6 +290,13 @@ class Gem::RemoteFetcher
response = connection.request request
say "#{request.method} #{response.code} #{response.message}: #{uri}" if
Gem.configuration.really_verbose
+ rescue Net::HTTPBadResponse
+ reset connection
+
+ raise FetchError.new('too many bad responses', uri) if bad_response
+
+ bad_response = true
+ retry
rescue EOFError, Errno::ECONNABORTED, Errno::ECONNRESET
requests = @requests[connection.object_id]
say "connection reset after #{requests} requests, retrying" if
@@ -306,10 +304,8 @@ class Gem::RemoteFetcher
raise FetchError.new('too many connection resets', uri) if retried
- @requests.delete connection.object_id
+ reset connection
- connection.finish
- connection.start
retried = true
retry
end
@@ -318,6 +314,16 @@ class Gem::RemoteFetcher
end
##
+ # Resets HTTP connection +connection+.
+
+ def reset(connection)
+ @requests.delete connection.object_id
+
+ connection.finish
+ connection.start
+ end
+
+ ##
# Checks if the provided string is a file:// URI.
def file_uri?(uri)