Index: NEWS =================================================================== --- NEWS (revision 43418) +++ NEWS (working copy) @@ -461,9 +461,9 @@ with all sufficient information, see the XML declaration is used for XML document encoding. * RubyGems - * Updated to 2.0.12. + * Updated to 2.0.13. - See http://rubygems.rubyforge.org/rubygems-update/History_txt.html#label-2.0.12+%2F+2013-10-14 + See http://rubygems.rubyforge.org/rubygems-update/History_txt.html#label-2.0.13+%2F+2013-10-24 for release notes. * Updated to 2.0.10. This fixes CVE_2013-4363: Index: lib/rubygems/server.rb =================================================================== --- lib/rubygems/server.rb (revision 43418) +++ lib/rubygems/server.rb (working copy) @@ -445,7 +445,7 @@ div.method-source-code pre { color: #ffd @spec_dirs = @gem_dirs.map { |gem_dir| File.join gem_dir, 'specifications' } @spec_dirs.reject! { |spec_dir| !File.directory? spec_dir } - Gem::Specification.dirs = @gem_dirs + reset_gems @have_rdoc_4_plus = nil end @@ -470,7 +470,7 @@ div.method-source-code pre { color: #ffd end def latest_specs(req, res) - Gem::Specification.reset + reset_gems res['content-type'] = 'application/x-gzip' @@ -531,7 +531,7 @@ div.method-source-code pre { color: #ffd end def quick(req, res) - Gem::Specification.reset + reset_gems res['content-type'] = 'text/plain' add_date res @@ -567,7 +567,8 @@ div.method-source-code pre { color: #ffd end def root(req, res) - Gem::Specification.reset + reset_gems + add_date res raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found." unless @@ -698,6 +699,13 @@ div.method-source-code pre { color: #ffd end ## + # Updates the server to use the latest installed gems. + + def reset_gems # :nodoc: + Gem::Specification.dirs = @gem_dirs + end + + ## # Returns true and prepares http response, if rdoc for the requested gem # name pattern was found. # @@ -787,7 +795,7 @@ div.method-source-code pre { color: #ffd end def specs(req, res) - Gem::Specification.reset + reset_gems add_date res Index: lib/rubygems/source.rb =================================================================== --- lib/rubygems/source.rb (revision 43418) +++ lib/rubygems/source.rb (working copy) @@ -63,7 +63,12 @@ class Gem::Source end def update_cache? - @update_cache ||= File.stat(Gem.user_home).uid == Process.uid + @update_cache ||= + begin + File.stat(Gem.user_home).uid == Process.uid + rescue Errno::ENOENT + false + end end def fetch_spec(name) Index: lib/rubygems/spec_fetcher.rb =================================================================== --- lib/rubygems/spec_fetcher.rb (revision 43418) +++ lib/rubygems/spec_fetcher.rb (working copy) @@ -39,7 +39,12 @@ class Gem::SpecFetcher def initialize @dir = File.join Gem.user_home, '.gem', 'specs' - @update_cache = File.stat(Gem.user_home).uid == Process.uid + @update_cache = + begin + File.stat(Gem.user_home).uid == Process.uid + rescue Errno::EACCES, Errno::ENOENT + false + end @specs = {} @latest_specs = {} Index: lib/rubygems/version.rb =================================================================== --- lib/rubygems/version.rb (revision 43418) +++ lib/rubygems/version.rb (working copy) @@ -174,7 +174,7 @@ class Gem::Version # REFACTOR: There's no real reason this should be separate from #initialize. def self.create input - if input.respond_to? :version then + if self === input then # check yourself before you wreck yourself input elsif input.nil? then nil Index: lib/rubygems.rb =================================================================== --- lib/rubygems.rb (revision 43418) +++ lib/rubygems.rb (working copy) @@ -8,7 +8,7 @@ require 'rbconfig' module Gem - VERSION = '2.0.12' + VERSION = '2.0.13' end # Must be first since it unloads the prelude from 1.9.2 Index: test/rubygems/test_gem_server.rb =================================================================== --- test/rubygems/test_gem_server.rb (revision 43418) +++ test/rubygems/test_gem_server.rb (working copy) @@ -85,6 +85,30 @@ class TestGemServer < Gem::TestCase Marshal.load(@res.body) end + def test_latest_specs_gemdirs + data = StringIO.new "GET /latest_specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n" + dir = "#{@gemhome}2" + + spec = quick_spec 'z', 9 + + specs_dir = File.join dir, 'specifications' + FileUtils.mkdir_p specs_dir + + open File.join(specs_dir, spec.spec_name), 'w' do |io| + io.write spec.to_ruby + end + + server = Gem::Server.new dir, process_based_port, false + + @req.parse data + + server.latest_specs @req, @res + + assert_equal 200, @res.status + + assert_equal [['z', v(9), Gem::Platform::RUBY]], Marshal.load(@res.body) + end + def test_latest_specs_gz data = StringIO.new "GET /latest_specs.#{Gem.marshal_version}.gz HTTP/1.0\r\n\r\n" @req.parse data @@ -120,8 +144,41 @@ class TestGemServer < Gem::TestCase assert_equal 2, @server.server.listeners.length end + def test_quick_gemdirs + data = StringIO.new "GET /quick/Marshal.4.8/z-9.gemspec.rz HTTP/1.0\r\n\r\n" + dir = "#{@gemhome}2" + + server = Gem::Server.new dir, process_based_port, false + + @req.parse data + + server.quick @req, @res + + assert_equal 404, @res.status + + spec = quick_spec 'z', 9 + + specs_dir = File.join dir, 'specifications' + + FileUtils.mkdir_p specs_dir + + open File.join(specs_dir, spec.spec_name), 'w' do |io| + io.write spec.to_ruby + end + + data.rewind + + req = WEBrick::HTTPRequest.new :Logger => nil + res = WEBrick::HTTPResponse.new :HTTPVersion => '1.0' + req.parse data + + server.quick req, res + + assert_equal 200, res.status + end + def test_quick_missing - data = StringIO.new "GET /quick/z-9.gemspec.rz HTTP/1.0\r\n\r\n" + data = StringIO.new "GET /quick/Marshal.4.8/z-9.gemspec.rz HTTP/1.0\r\n\r\n" @req.parse data @server.quick @req, @res @@ -188,6 +245,29 @@ class TestGemServer < Gem::TestCase assert_equal 'text/html', @res['content-type'] end + def test_root_gemdirs + data = StringIO.new "GET / HTTP/1.0\r\n\r\n" + dir = "#{@gemhome}2" + + spec = quick_spec 'z', 9 + + specs_dir = File.join dir, 'specifications' + FileUtils.mkdir_p specs_dir + + open File.join(specs_dir, spec.spec_name), 'w' do |io| + io.write spec.to_ruby + end + + server = Gem::Server.new dir, process_based_port, false + + @req.parse data + + server.root @req, @res + + assert_equal 200, @res.status + assert_match 'z 9', @res.body + end + def test_specs data = StringIO.new "GET /specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n" @req.parse data @@ -203,6 +283,30 @@ class TestGemServer < Gem::TestCase Marshal.load(@res.body) end + def test_specs_gemdirs + data = StringIO.new "GET /specs.#{Gem.marshal_version} HTTP/1.0\r\n\r\n" + dir = "#{@gemhome}2" + + spec = quick_spec 'z', 9 + + specs_dir = File.join dir, 'specifications' + FileUtils.mkdir_p specs_dir + + open File.join(specs_dir, spec.spec_name), 'w' do |io| + io.write spec.to_ruby + end + + server = Gem::Server.new dir, process_based_port, false + + @req.parse data + + server.specs @req, @res + + assert_equal 200, @res.status + + assert_equal [['z', v(9), Gem::Platform::RUBY]], Marshal.load(@res.body) + end + def test_specs_gz data = StringIO.new "GET /specs.#{Gem.marshal_version}.gz HTTP/1.0\r\n\r\n" @req.parse data Index: test/rubygems/test_gem_source.rb =================================================================== --- test/rubygems/test_gem_source.rb (revision 43418) +++ test/rubygems/test_gem_source.rb (working copy) @@ -184,5 +184,15 @@ class TestGemSource < Gem::TestCase end end + def test_update_cache_eh + assert @source.update_cache? + end + + def test_update_cache_eh_home_nonexistent + FileUtils.rmdir Gem.user_home + + refute @source.update_cache? + end + end Index: test/rubygems/test_gem_spec_fetcher.rb =================================================================== --- test/rubygems/test_gem_spec_fetcher.rb (revision 43418) +++ test/rubygems/test_gem_spec_fetcher.rb (working copy) @@ -52,6 +52,18 @@ class TestGemSpecFetcher < Gem::TestCase ['x', Gem::Version.new(1), 'ruby']] end + def test_initialize_unwritable_home_dir + skip 'chmod not supported' if Gem.win_platform? + + FileUtils.chmod 0000, Gem.user_home + + begin + assert Gem::SpecFetcher.new + ensure + FileUtils.chmod 0755, Gem.user_home + end + end + def test_spec_for_dependency_all d = "#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}" @fetcher.data["#{d}#{@a1.spec_name}.rz"] = util_zip(Marshal.dump(@a1)) Index: test/rubygems/test_gem_version.rb =================================================================== --- test/rubygems/test_gem_version.rb (revision 43418) +++ test/rubygems/test_gem_version.rb (working copy) @@ -23,14 +23,13 @@ class TestGemVersion < Gem::TestCase assert_bumped_version_equal "6", "5" end - # FIX: For "legacy reasons," any object that responds to +version+ - # is returned unchanged. I'm not certain why. + # A Gem::Version is already a Gem::Version and therefore not transformed by + # Gem::Version.create def test_class_create - fake = Object.new - def fake.version; "1.0" end + real = Gem::Version.new(1.0) - assert_same fake, Gem::Version.create(fake) + assert_same real, Gem::Version.create(real) assert_nil Gem::Version.create(nil) assert_equal v("5.1"), Gem::Version.create("5.1")