bundler/lib/bundler/compact_index_client/updater.rb in rubygems-update-2.6.14 vs bundler/lib/bundler/compact_index_client/updater.rb in rubygems-update-2.7.0

- old
+ new

@@ -1,9 +1,9 @@ # frozen_string_literal: true -require "fileutils" + +require "bundler/vendored_fileutils" require "stringio" -require "tmpdir" require "zlib" module Bundler class CompactIndexClient class Updater @@ -20,10 +20,11 @@ end end def initialize(fetcher) @fetcher = fetcher + require "tmpdir" end def update(local_path, remote_path, retrying = nil) headers = {} @@ -32,11 +33,18 @@ # first try to fetch any new bytes on the existing file if retrying.nil? && local_path.file? FileUtils.cp local_path, local_temp_path headers["If-None-Match"] = etag_for(local_temp_path) - headers["Range"] = "bytes=#{local_temp_path.size}-" + headers["Range"] = + if local_temp_path.size.nonzero? + # Subtract a byte to ensure the range won't be empty. + # Avoids 416 (Range Not Satisfiable) responses. + "bytes=#{local_temp_path.size - 1}-" + else + "bytes=#{local_temp_path.size}-" + end else # Fastly ignores Range when Accept-Encoding: gzip is set headers["Accept-Encoding"] = "gzip" end @@ -46,16 +54,19 @@ content = response.body if response["Content-Encoding"] == "gzip" content = Zlib::GzipReader.new(StringIO.new(content)).read end - mode = response.is_a?(Net::HTTPPartialContent) ? "a" : "w" SharedHelpers.filesystem_access(local_temp_path) do - local_temp_path.open(mode) {|f| f << content } + if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero? + local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) } + else + local_temp_path.open("w") {|f| f << content } + end end - response_etag = response["ETag"].gsub(%r{\AW/}, "") + response_etag = (response["ETag"] || "").gsub(%r{\AW/}, "") if etag_for(local_temp_path) == response_etag SharedHelpers.filesystem_access(local_path) do FileUtils.mv(local_temp_path, local_path) end return nil @@ -72,16 +83,24 @@ def etag_for(path) sum = checksum_for_file(path) sum ? %("#{sum}") : nil end + def slice_body(body, range) + if body.respond_to?(:byteslice) + body.byteslice(range) + else # pre-1.9.3 + body.unpack("@#{range.first}a#{range.end + 1}").first + end + end + def checksum_for_file(path) return nil unless path.file? # This must use IO.read instead of Digest.file().hexdigest # because we need to preserve \n line endings on windows when calculating # the checksum SharedHelpers.filesystem_access(path, :read) do - Digest::MD5.hexdigest(IO.read(path)) + SharedHelpers.digest(:MD5).hexdigest(IO.read(path)) end end end end end