Class: Bundler::CompactIndexClient::Updater
Relationships & Source Files | |
Namespace Children | |
Exceptions:
| |
Inherits: | Object |
Defined in: | lib/bundler/compact_index_client/updater.rb |
Class Method Summary
- .new(fetcher) ⇒ Updater constructor
Instance Method Summary
- #update(remote_path, local_path, etag_path)
- #append(remote_path, local_path, etag_path) private
-
#byte_sequence(value)
private
Unwrap surrounding colons (byte sequence) The wrapping characters must be matched or we return nil.
- #etag_for_request(etag_path) private
- #etag_from_response(response) private
-
#parse_digests(response)
private
Unwraps and returns a Hash of digest algorithms and base64 values according to RFC 8941 Structured Field Values for HTTP.
-
#replace(remote_path, local_path, etag_path)
private
request without range header to get the full file or a 304 Not Modified.
- #request_headers(etag, range_start = nil) private
Constructor Details
.new(fetcher) ⇒ Updater
# File 'lib/bundler/compact_index_client/updater.rb', line 12
def initialize(fetcher) @fetcher = fetcher end
Instance Method Details
#append(remote_path, local_path, etag_path) (private)
[ GitHub ]# File 'lib/bundler/compact_index_client/updater.rb', line 26
def append(remote_path, local_path, etag_path) return false unless local_path.file? && local_path.size.nonzero? CacheFile.copy(local_path) do |file| etag = etag_path.read.tap(&:chomp!) if etag_path.file? # Subtract a byte to ensure the range won't be empty. # Avoids 416 (Range Not Satisfiable) responses. response = @fetcher.call(remote_path, request_headers(etag, file.size - 1)) break true if response.is_a?(Gem::Net::HTTPNotModified) file.digests = parse_digests(response) # server may ignore Range and return the full response if response.is_a?(Gem::Net::HTTPPartialContent) break false unless file.append(response.body.byteslice(1..-1)) else file.write(response.body) end CacheFile.write(etag_path, etag_from_response(response)) true end end
#byte_sequence(value) (private)
Unwrap surrounding colons (byte sequence) The wrapping characters must be matched or we return nil. Also handles quotes because right now rubygems.org sends them.
# File 'lib/bundler/compact_index_client/updater.rb', line 97
def byte_sequence(value) return if value.delete_prefix!(":") && !value.delete_suffix!(":") return if value.delete_prefix!('"') && !value.delete_suffix!('"') value end
#etag_for_request(etag_path) (private)
[ GitHub ]# File 'lib/bundler/compact_index_client/updater.rb', line 65
def etag_for_request(etag_path) etag_path.read.tap(&:chomp!) if etag_path.file? end
#etag_from_response(response) (private)
[ GitHub ]# File 'lib/bundler/compact_index_client/updater.rb', line 69
def etag_from_response(response) return unless response["ETag"] etag = response["ETag"].delete_prefix("W/") return if etag.delete_prefix!('"') && !etag.delete_suffix!('"') etag end
#parse_digests(response) (private)
Unwraps and returns a Hash of digest algorithms and base64 values according to RFC 8941 Structured Field Values for HTTP. www.rfc-editor.org/rfc/rfc8941#name-parsing-a-byte-sequence Ignores unsupported algorithms.
# File 'lib/bundler/compact_index_client/updater.rb', line 80
def parse_digests(response) return unless header = response["Repr-Digest"] || response["Digest"] digests = {} header.split(",") do |param| algorithm, value = param.split("=", 2) algorithm.strip! algorithm.downcase! next unless SUPPORTED_DIGESTS.key?(algorithm) next unless value = byte_sequence(value) digests[algorithm] = value end digests.empty? ? nil : digests end
#replace(remote_path, local_path, etag_path) (private)
request without range header to get the full file or a 304 Not Modified
# File 'lib/bundler/compact_index_client/updater.rb', line 50
def replace(remote_path, local_path, etag_path) etag = etag_path.read.tap(&:chomp!) if etag_path.file? response = @fetcher.call(remote_path, request_headers(etag)) return true if response.is_a?(Gem::Net::HTTPNotModified) CacheFile.write(local_path, response.body, parse_digests(response)) CacheFile.write(etag_path, etag_from_response(response)) end
#request_headers(etag, range_start = nil) (private)
[ GitHub ]# File 'lib/bundler/compact_index_client/updater.rb', line 58
def request_headers(etag, range_start = nil) headers = {} headers["Range"] = "bytes=#{range_start}-" if range_start headers["If-None-Match"] = %("#{etag}") if etag headers end
#update(remote_path, local_path, etag_path)
[ GitHub ]# File 'lib/bundler/compact_index_client/updater.rb', line 16
def update(remote_path, local_path, etag_path) append(remote_path, local_path, etag_path) || replace(remote_path, local_path, etag_path) rescue CacheFile::DigestMismatchError => e raise MismatchedChecksumError.new(remote_path, e. ) rescue Zlib::GzipFile::Error raise Bundler::HTTPError end