[rubygems/rubygems] Use vendored net-http in Bundler

https://github.com/rubygems/rubygems/commit/0d758e8926
This commit is contained in:
David Rodríguez 2023-01-29 21:28:29 +01:00 committed by Hiroshi SHIBATA
parent ce924ce1fb
commit 90317472e8
19 changed files with 131 additions and 125 deletions

View File

@ -33,11 +33,11 @@ module Bundler
# Subtract a byte to ensure the range won't be empty. # Subtract a byte to ensure the range won't be empty.
# Avoids 416 (Range Not Satisfiable) responses. # Avoids 416 (Range Not Satisfiable) responses.
response = @fetcher.call(remote_path, request_headers(etag, file.size - 1)) response = @fetcher.call(remote_path, request_headers(etag, file.size - 1))
break true if response.is_a?(Net::HTTPNotModified) break true if response.is_a?(Gem::Net::HTTPNotModified)
file.digests = parse_digests(response) file.digests = parse_digests(response)
# server may ignore Range and return the full response # server may ignore Range and return the full response
if response.is_a?(Net::HTTPPartialContent) if response.is_a?(Gem::Net::HTTPPartialContent)
break false unless file.append(response.body.byteslice(1..-1)) break false unless file.append(response.body.byteslice(1..-1))
else else
file.write(response.body) file.write(response.body)
@ -51,7 +51,7 @@ module Bundler
def replace(remote_path, local_path, etag_path) def replace(remote_path, local_path, etag_path)
etag = etag_path.read.tap(&:chomp!) if etag_path.file? etag = etag_path.read.tap(&:chomp!) if etag_path.file?
response = @fetcher.call(remote_path, request_headers(etag)) response = @fetcher.call(remote_path, request_headers(etag))
return true if response.is_a?(Net::HTTPNotModified) return true if response.is_a?(Gem::Net::HTTPNotModified)
CacheFile.write(local_path, response.body, parse_digests(response)) CacheFile.write(local_path, response.body, parse_digests(response))
CacheFile.write(etag_path, etag(response)) CacheFile.write(etag_path, etag(response))
end end

View File

@ -82,7 +82,7 @@ module Bundler
FAIL_ERRORS = begin FAIL_ERRORS = begin
fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError, SecurityError] fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError, SecurityError]
fail_errors << Gem::Requirement::BadRequirementError fail_errors << Gem::Requirement::BadRequirementError
fail_errors.concat(NET_ERRORS.map {|e| Net.const_get(e) }) fail_errors.concat(NET_ERRORS.map {|e| Gem::Net.const_get(e) })
end.freeze end.freeze
class << self class << self
@ -252,7 +252,7 @@ module Bundler
Bundler.settings[:ssl_client_cert] Bundler.settings[:ssl_client_cert]
raise SSLError if needs_ssl && !defined?(OpenSSL::SSL) raise SSLError if needs_ssl && !defined?(OpenSSL::SSL)
con = PersistentHTTP.new name: "bundler", proxy: :ENV con = Gem::Net::HTTP::Persistent.new name: "bundler", proxy: :ENV
if gem_proxy = Gem.configuration[:http_proxy] if gem_proxy = Gem.configuration[:http_proxy]
con.proxy = Bundler::URI.parse(gem_proxy) if gem_proxy != :no_proxy con.proxy = Bundler::URI.parse(gem_proxy) if gem_proxy != :no_proxy
end end
@ -289,8 +289,8 @@ module Bundler
HTTP_ERRORS = [ HTTP_ERRORS = [
Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH, Timeout::Error, EOFError, SocketError, Errno::ENETDOWN, Errno::ENETUNREACH,
Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN, Errno::EINVAL, Errno::ECONNRESET, Errno::ETIMEDOUT, Errno::EAGAIN,
Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, Gem::Net::HTTPBadResponse, Gem::Net::HTTPHeaderSyntaxError, Gem::Net::ProtocolError,
PersistentHTTP::Error, Zlib::BufError, Errno::EHOSTUNREACH Gem::Net::HTTP::Persistent::Error, Zlib::BufError, Errno::EHOSTUNREACH
].freeze ].freeze
def bundler_cert_store def bundler_cert_store

View File

@ -121,7 +121,7 @@ module Bundler
rescue NetworkDownError => e rescue NetworkDownError => e
raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"] raise unless Bundler.feature_flag.allow_offline_install? && headers["If-None-Match"]
ui.warn "Using the cached data for the new index because of a network error: #{e}" ui.warn "Using the cached data for the new index because of a network error: #{e}"
Net::HTTPNotModified.new(nil, nil, nil) Gem::Net::HTTPNotModified.new(nil, nil, nil)
end end
end end
end end

View File

@ -20,33 +20,35 @@ module Bundler
Bundler.ui.debug("HTTP #{response.code} #{response.message} #{filtered_uri}") Bundler.ui.debug("HTTP #{response.code} #{response.message} #{filtered_uri}")
case response case response
when Net::HTTPSuccess, Net::HTTPNotModified when Gem::Net::HTTPSuccess, Gem::Net::HTTPNotModified
response response
when Net::HTTPRedirection when Gem::Net::HTTPRedirection
new_uri = Bundler::URI.parse(response["location"]) new_uri = Bundler::URI.parse(response["location"])
if new_uri.host == uri.host if new_uri.host == uri.host
new_uri.user = uri.user new_uri.user = uri.user
new_uri.password = uri.password new_uri.password = uri.password
end end
fetch(new_uri, headers, counter + 1) fetch(new_uri, headers, counter + 1)
when Net::HTTPRequestedRangeNotSatisfiable when Gem::Net::HTTPRequestedRangeNotSatisfiable
new_headers = headers.dup new_headers = headers.dup
new_headers.delete("Range") new_headers.delete("Range")
new_headers["Accept-Encoding"] = "gzip" new_headers["Accept-Encoding"] = "gzip"
fetch(uri, new_headers) fetch(uri, new_headers)
when Net::HTTPRequestEntityTooLarge when Gem::Net::HTTPRequestEntityTooLarge
raise FallbackError, response.body raise FallbackError, response.body
when Net::HTTPTooManyRequests when Gem::Net::HTTPTooManyRequests
raise TooManyRequestsError, response.body raise TooManyRequestsError, response.body
when Net::HTTPUnauthorized when Gem::Net::HTTPUnauthorized
raise BadAuthenticationError, uri.host if uri.userinfo raise BadAuthenticationError, uri.host if uri.userinfo
raise AuthenticationRequiredError, uri.host raise AuthenticationRequiredError, uri.host
when Net::HTTPForbidden when Gem::Net::HTTPForbidden
raise AuthenticationForbiddenError, uri.host raise AuthenticationForbiddenError, uri.host
when Net::HTTPNotFound when Gem::Net::HTTPNotFound
raise FallbackError, "Net::HTTPNotFound: #{filtered_uri}" raise FallbackError, "Gem::Net::HTTPNotFound: #{filtered_uri}"
else else
raise HTTPError, "#{response.class}#{": #{response.body}" unless response.body.empty?}" message = "Gem::#{response.class.name.gsub(/\AGem::/, "")}"
message += ": #{response.body}" unless response.body.empty?
raise HTTPError, message
end end
end end
@ -56,7 +58,7 @@ module Bundler
filtered_uri = URICredentialsFilter.credential_filtered_uri(uri) filtered_uri = URICredentialsFilter.credential_filtered_uri(uri)
Bundler.ui.debug "HTTP GET #{filtered_uri}" Bundler.ui.debug "HTTP GET #{filtered_uri}"
req = Net::HTTP::Get.new uri.request_uri, headers req = Gem::Net::HTTP::Get.new uri.request_uri, headers
if uri.user if uri.user
user = CGI.unescape(uri.user) user = CGI.unescape(uri.user)
password = uri.password ? CGI.unescape(uri.password) : nil password = uri.password ? CGI.unescape(uri.password) : nil

View File

@ -1,4 +1,4 @@
require 'net/http' require_relative '../../../../../vendored_net_http'
require_relative '../../../../uri/lib/uri' require_relative '../../../../uri/lib/uri'
require 'cgi' # for escaping require 'cgi' # for escaping
require_relative '../../../../connection_pool/lib/connection_pool' require_relative '../../../../connection_pool/lib/connection_pool'
@ -6,9 +6,9 @@ require_relative '../../../../connection_pool/lib/connection_pool'
autoload :OpenSSL, 'openssl' autoload :OpenSSL, 'openssl'
## ##
# Persistent connections for Net::HTTP # Persistent connections for Gem::Net::HTTP
# #
# Bundler::Persistent::Net::HTTP::Persistent maintains persistent connections across all the # Gem::Net::HTTP::Persistent maintains persistent connections across all the
# servers you wish to talk to. For each host:port you communicate with a # servers you wish to talk to. For each host:port you communicate with a
# single persistent connection is created. # single persistent connection is created.
# #
@ -20,23 +20,23 @@ autoload :OpenSSL, 'openssl'
# #
# Example: # Example:
# #
# require 'bundler/vendor/net-http-persistent/lib/net/http/persistent' # require 'bundler/vendor/net-http/lib/net/http/persistent'
# #
# uri = Bundler::URI 'http://example.com/awesome/web/service' # uri = Bundler::URI 'http://example.com/awesome/web/service'
# #
# http = Bundler::Persistent::Net::HTTP::Persistent.new # http = Gem::Net::HTTP::Persistent.new
# #
# # perform a GET # # perform a GET
# response = http.request uri # response = http.request uri
# #
# # or # # or
# #
# get = Net::HTTP::Get.new uri.request_uri # get = Gem::Net::HTTP::Get.new uri.request_uri
# response = http.request get # response = http.request get
# #
# # create a POST # # create a POST
# post_uri = uri + 'create' # post_uri = uri + 'create'
# post = Net::HTTP::Post.new post_uri.path # post = Gem::Net::HTTP::Post.new post_uri.path
# post.set_form_data 'some' => 'cool data' # post.set_form_data 'some' => 'cool data'
# #
# # perform the POST, the Bundler::URI is always required # # perform the POST, the Bundler::URI is always required
@ -92,7 +92,7 @@ autoload :OpenSSL, 'openssl'
# #
# === Segregation # === Segregation
# #
# Each Bundler::Persistent::Net::HTTP::Persistent instance has its own pool of connections. There # Each Gem::Net::HTTP::Persistent instance has its own pool of connections. There
# is no sharing with other instances (as was true in earlier versions). # is no sharing with other instances (as was true in earlier versions).
# #
# === Idle Timeout # === Idle Timeout
@ -131,7 +131,7 @@ autoload :OpenSSL, 'openssl'
# #
# === Connection Termination # === Connection Termination
# #
# If you are done using the Bundler::Persistent::Net::HTTP::Persistent instance you may shut down # If you are done using the Gem::Net::HTTP::Persistent instance you may shut down
# all the connections in the current thread with #shutdown. This is not # all the connections in the current thread with #shutdown. This is not
# recommended for normal use, it should only be used when it will be several # recommended for normal use, it should only be used when it will be several
# minutes before you make another HTTP request. # minutes before you make another HTTP request.
@ -141,7 +141,7 @@ autoload :OpenSSL, 'openssl'
# Ruby will automatically garbage collect and shutdown your HTTP connections # Ruby will automatically garbage collect and shutdown your HTTP connections
# when the thread terminates. # when the thread terminates.
class Bundler::Persistent::Net::HTTP::Persistent class Gem::Net::HTTP::Persistent
## ##
# The beginning of Time # The beginning of Time
@ -172,12 +172,12 @@ class Bundler::Persistent::Net::HTTP::Persistent
end end
## ##
# The version of Bundler::Persistent::Net::HTTP::Persistent you are using # The version of Gem::Net::HTTP::Persistent you are using
VERSION = '4.0.2' VERSION = '4.0.2'
## ##
# Error class for errors raised by Bundler::Persistent::Net::HTTP::Persistent. Various # Error class for errors raised by Gem::Net::HTTP::Persistent. Various
# SystemCallErrors are re-raised with a human-readable message under this # SystemCallErrors are re-raised with a human-readable message under this
# class. # class.
@ -200,7 +200,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
uri = Bundler::URI uri unless Bundler::URI::Generic === uri uri = Bundler::URI uri unless Bundler::URI::Generic === uri
uri += '/' uri += '/'
req = Net::HTTP::Head.new uri.request_uri req = Gem::Net::HTTP::Head.new uri.request_uri
http = new 'net-http-persistent detect_idle_timeout' http = new 'net-http-persistent detect_idle_timeout'
@ -214,7 +214,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
$stderr.puts "HEAD #{uri} => #{response.code}" if $DEBUG $stderr.puts "HEAD #{uri} => #{response.code}" if $DEBUG
unless Net::HTTPOK === response then unless Gem::Net::HTTPOK === response then
raise Error, "bad response code #{response.code} detecting idle timeout" raise Error, "bad response code #{response.code} detecting idle timeout"
end end
@ -238,7 +238,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
attr_reader :certificate attr_reader :certificate
## ##
# For Net::HTTP parity # For Gem::Net::HTTP parity
alias cert certificate alias cert certificate
@ -266,7 +266,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
attr_reader :ciphers attr_reader :ciphers
## ##
# Sends debug_output to this IO via Net::HTTP#set_debug_output. # Sends debug_output to this IO via Gem::Net::HTTP#set_debug_output.
# #
# Never use this method in production code, it causes a serious security # Never use this method in production code, it causes a serious security
# hole. # hole.
@ -279,7 +279,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
attr_reader :generation # :nodoc: attr_reader :generation # :nodoc:
## ##
# Headers that are added to every request using Net::HTTP#add_field # Headers that are added to every request using Gem::Net::HTTP#add_field
attr_reader :headers attr_reader :headers
@ -304,7 +304,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
## ##
# Number of retries to perform if a request fails. # Number of retries to perform if a request fails.
# #
# See also #max_retries=, Net::HTTP#max_retries=. # See also #max_retries=, Gem::Net::HTTP#max_retries=.
attr_reader :max_retries attr_reader :max_retries
@ -325,12 +325,12 @@ class Bundler::Persistent::Net::HTTP::Persistent
attr_reader :name attr_reader :name
## ##
# Seconds to wait until a connection is opened. See Net::HTTP#open_timeout # Seconds to wait until a connection is opened. See Gem::Net::HTTP#open_timeout
attr_accessor :open_timeout attr_accessor :open_timeout
## ##
# Headers that are added to every request using Net::HTTP#[]= # Headers that are added to every request using Gem::Net::HTTP#[]=
attr_reader :override_headers attr_reader :override_headers
@ -340,7 +340,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
attr_reader :private_key attr_reader :private_key
## ##
# For Net::HTTP parity # For Gem::Net::HTTP parity
alias key private_key alias key private_key
@ -360,12 +360,12 @@ class Bundler::Persistent::Net::HTTP::Persistent
attr_reader :pool # :nodoc: attr_reader :pool # :nodoc:
## ##
# Seconds to wait until reading one block. See Net::HTTP#read_timeout # Seconds to wait until reading one block. See Gem::Net::HTTP#read_timeout
attr_accessor :read_timeout attr_accessor :read_timeout
## ##
# Seconds to wait until writing one block. See Net::HTTP#write_timeout # Seconds to wait until writing one block. See Gem::Net::HTTP#write_timeout
attr_accessor :write_timeout attr_accessor :write_timeout
@ -450,7 +450,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
attr_reader :verify_mode attr_reader :verify_mode
## ##
# Creates a new Bundler::Persistent::Net::HTTP::Persistent. # Creates a new Gem::Net::HTTP::Persistent.
# #
# Set a +name+ for fun. Your library name should be good enough, but this # Set a +name+ for fun. Your library name should be good enough, but this
# otherwise has no purpose. # otherwise has no purpose.
@ -492,8 +492,8 @@ class Bundler::Persistent::Net::HTTP::Persistent
@socket_options << [Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1] if @socket_options << [Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1] if
Socket.const_defined? :TCP_NODELAY Socket.const_defined? :TCP_NODELAY
@pool = Bundler::Persistent::Net::HTTP::Persistent::Pool.new size: pool_size do |http_args| @pool = Gem::Net::HTTP::Persistent::Pool.new size: pool_size do |http_args|
Bundler::Persistent::Net::HTTP::Persistent::Connection.new Net::HTTP, http_args, @ssl_generation Gem::Net::HTTP::Persistent::Connection.new Gem::Net::HTTP, http_args, @ssl_generation
end end
@certificate = nil @certificate = nil
@ -529,7 +529,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
reconnect_ssl reconnect_ssl
end end
# For Net::HTTP parity # For Gem::Net::HTTP parity
alias cert= certificate= alias cert= certificate=
## ##
@ -648,7 +648,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
end end
## ##
# Starts the Net::HTTP +connection+ # Starts the Gem::Net::HTTP +connection+
def start http def start http
http.set_debug_output @debug_output if @debug_output http.set_debug_output @debug_output if @debug_output
@ -666,7 +666,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
end end
## ##
# Finishes the Net::HTTP +connection+ # Finishes the Gem::Net::HTTP +connection+
def finish connection def finish connection
connection.finish connection.finish
@ -716,7 +716,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
reconnect_ssl reconnect_ssl
end end
# For Net::HTTP parity # For Gem::Net::HTTP parity
alias key= private_key= alias key= private_key=
## ##
@ -835,7 +835,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
end end
## ##
# Finishes then restarts the Net::HTTP +connection+ # Finishes then restarts the Gem::Net::HTTP +connection+
def reset connection def reset connection
http = connection.http http = connection.http
@ -854,13 +854,13 @@ class Bundler::Persistent::Net::HTTP::Persistent
end end
## ##
# Makes a request on +uri+. If +req+ is nil a Net::HTTP::Get is performed # Makes a request on +uri+. If +req+ is nil a Gem::Net::HTTP::Get is performed
# against +uri+. # against +uri+.
# #
# If a block is passed #request behaves like Net::HTTP#request (the body of # If a block is passed #request behaves like Gem::Net::HTTP#request (the body of
# the response will not have been read). # the response will not have been read).
# #
# +req+ must be a Net::HTTPGenericRequest subclass (see Net::HTTP for a list). # +req+ must be a Gem::Net::HTTPGenericRequest subclass (see Gem::Net::HTTP for a list).
def request uri, req = nil, &block def request uri, req = nil, &block
uri = Bundler::URI uri uri = Bundler::URI uri
@ -903,7 +903,7 @@ class Bundler::Persistent::Net::HTTP::Persistent
def request_setup req_or_uri # :nodoc: def request_setup req_or_uri # :nodoc:
req = if req_or_uri.respond_to? 'request_uri' then req = if req_or_uri.respond_to? 'request_uri' then
Net::HTTP::Get.new req_or_uri.request_uri Gem::Net::HTTP::Get.new req_or_uri.request_uri
else else
req_or_uri req_or_uri
end end

View File

@ -1,8 +1,8 @@
## ##
# A Net::HTTP connection wrapper that holds extra information for managing the # A Gem::Net::HTTP connection wrapper that holds extra information for managing the
# connection's lifetime. # connection's lifetime.
class Bundler::Persistent::Net::HTTP::Persistent::Connection # :nodoc: class Gem::Net::HTTP::Persistent::Connection # :nodoc:
attr_accessor :http attr_accessor :http
@ -28,7 +28,7 @@ class Bundler::Persistent::Net::HTTP::Persistent::Connection # :nodoc:
alias_method :close, :finish alias_method :close, :finish
def reset def reset
@last_use = Bundler::Persistent::Net::HTTP::Persistent::EPOCH @last_use = Gem::Net::HTTP::Persistent::EPOCH
@requests = 0 @requests = 0
end end

View File

@ -1,4 +1,4 @@
class Bundler::Persistent::Net::HTTP::Persistent::Pool < Bundler::ConnectionPool # :nodoc: class Gem::Net::HTTP::Persistent::Pool < Bundler::ConnectionPool # :nodoc:
attr_reader :available # :nodoc: attr_reader :available # :nodoc:
attr_reader :key # :nodoc: attr_reader :key # :nodoc:
@ -6,7 +6,7 @@ class Bundler::Persistent::Net::HTTP::Persistent::Pool < Bundler::ConnectionPool
def initialize(options = {}, &block) def initialize(options = {}, &block)
super super
@available = Bundler::Persistent::Net::HTTP::Persistent::TimedStackMulti.new(@size, &block) @available = Gem::Net::HTTP::Persistent::TimedStackMulti.new(@size, &block)
@key = "current-#{@available.object_id}" @key = "current-#{@available.object_id}"
end end

View File

@ -1,4 +1,4 @@
class Bundler::Persistent::Net::HTTP::Persistent::TimedStackMulti < Bundler::ConnectionPool::TimedStack # :nodoc: class Gem::Net::HTTP::Persistent::TimedStackMulti < Bundler::ConnectionPool::TimedStack # :nodoc:
## ##
# Returns a new hash that has arrays for keys # Returns a new hash that has arrays for keys

View File

@ -0,0 +1,8 @@
# frozen_string_literal: true
begin
require "rubygems/net/http"
rescue LoadError
require "net/http"
Gem::Net = Net
end

View File

@ -9,7 +9,3 @@ module Bundler
end end
end end
require_relative "vendor/net-http-persistent/lib/net/http/persistent" require_relative "vendor/net-http-persistent/lib/net/http/persistent"
module Bundler
PersistentHTTP = Persistent::Net::HTTP::Persistent
end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require "net/http" require "bundler/vendored_net_http"
require "bundler/compact_index_client" require "bundler/compact_index_client"
require "bundler/compact_index_client/updater" require "bundler/compact_index_client/updater"
require "tmpdir" require "tmpdir"
@ -64,8 +64,8 @@ RSpec.describe Bundler::CompactIndexClient::Updater do
it "does nothing if etags match" do it "does nothing if etags match" do
expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response) expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
allow(response).to receive(:is_a?).with(Net::HTTPPartialContent) { false } allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { false }
allow(response).to receive(:is_a?).with(Net::HTTPNotModified) { true } allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { true }
updater.update(remote_path, local_path, etag_path) updater.update(remote_path, local_path, etag_path)
@ -77,8 +77,8 @@ RSpec.describe Bundler::CompactIndexClient::Updater do
expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response) expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" } allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
allow(response).to receive(:[]).with("ETag") { "NewEtag" } allow(response).to receive(:[]).with("ETag") { "NewEtag" }
allow(response).to receive(:is_a?).with(Net::HTTPPartialContent) { true } allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
allow(response).to receive(:is_a?).with(Net::HTTPNotModified) { false } allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { false }
allow(response).to receive(:body) { "c123" } allow(response).to receive(:body) { "c123" }
updater.update(remote_path, local_path, etag_path) updater.update(remote_path, local_path, etag_path)
@ -102,7 +102,7 @@ RSpec.describe Bundler::CompactIndexClient::Updater do
it "tries the request again if the partial response fails digest check" do it "tries the request again if the partial response fails digest check" do
allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" } allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" }
allow(response).to receive(:body) { "the beginning of the file changed" } allow(response).to receive(:body) { "the beginning of the file changed" }
allow(response).to receive(:is_a?).with(Net::HTTPPartialContent) { true } allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response) expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
full_response = double(:full_response, body: full_body, is_a?: false) full_response = double(:full_response, body: full_body, is_a?: false)
@ -129,8 +129,8 @@ RSpec.describe Bundler::CompactIndexClient::Updater do
it "saves only the etag_path if generated etag matches" do it "saves only the etag_path if generated etag matches" do
expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response) expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
allow(response).to receive(:is_a?).with(Net::HTTPPartialContent) { false } allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { false }
allow(response).to receive(:is_a?).with(Net::HTTPNotModified) { true } allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { true }
updater.update(remote_path, local_path, etag_path) updater.update(remote_path, local_path, etag_path)
@ -142,8 +142,8 @@ RSpec.describe Bundler::CompactIndexClient::Updater do
expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response) expect(fetcher).to receive(:call).once.with(remote_path, headers).and_return(response)
allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" } allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:#{digest}:" }
allow(response).to receive(:[]).with("ETag") { "OpaqueEtag" } allow(response).to receive(:[]).with("ETag") { "OpaqueEtag" }
allow(response).to receive(:is_a?).with(Net::HTTPPartialContent) { true } allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
allow(response).to receive(:is_a?).with(Net::HTTPNotModified) { false } allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { false }
allow(response).to receive(:body) { "c123" } allow(response).to receive(:body) { "c123" }
updater.update(remote_path, local_path, etag_path) updater.update(remote_path, local_path, etag_path)
@ -157,8 +157,8 @@ RSpec.describe Bundler::CompactIndexClient::Updater do
allow(response).to receive(:[]).with("Repr-Digest") { nil } allow(response).to receive(:[]).with("Repr-Digest") { nil }
allow(response).to receive(:[]).with("Digest") { nil } allow(response).to receive(:[]).with("Digest") { nil }
allow(response).to receive(:[]).with("ETag") { "OpaqueEtag" } allow(response).to receive(:[]).with("ETag") { "OpaqueEtag" }
allow(response).to receive(:is_a?).with(Net::HTTPPartialContent) { false } allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { false }
allow(response).to receive(:is_a?).with(Net::HTTPNotModified) { false } allow(response).to receive(:is_a?).with(Gem::Net::HTTPNotModified) { false }
allow(response).to receive(:body) { full_body } allow(response).to receive(:body) { full_body }
updater.update(remote_path, local_path, etag_path) updater.update(remote_path, local_path, etag_path)
@ -170,7 +170,7 @@ RSpec.describe Bundler::CompactIndexClient::Updater do
it "tries the request again if the partial response fails digest check" do it "tries the request again if the partial response fails digest check" do
allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" } allow(response).to receive(:[]).with("Repr-Digest") { "sha-256=:baddigest:" }
allow(response).to receive(:body) { "the beginning of the file changed" } allow(response).to receive(:body) { "the beginning of the file changed" }
allow(response).to receive(:is_a?).with(Net::HTTPPartialContent) { true } allow(response).to receive(:is_a?).with(Gem::Net::HTTPPartialContent) { true }
expect(fetcher).to receive(:call).once.with(remote_path, headers) do expect(fetcher).to receive(:call).once.with(remote_path, headers) do
# During the failed first request, we simulate another process writing the etag. # During the failed first request, we simulate another process writing the etag.
# This ensures the second request doesn't generate the md5 etag again but just uses whatever is written. # This ensures the second request doesn't generate the md5 etag again but just uses whatever is written.

View File

@ -27,7 +27,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
end end
context "logging" do context "logging" do
let(:http_response) { Net::HTTPSuccess.new("1.1", 200, "Success") } let(:http_response) { Gem::Net::HTTPSuccess.new("1.1", 200, "Success") }
it "should log the HTTP response code and message to debug" do it "should log the HTTP response code and message to debug" do
expect(Bundler).to receive_message_chain(:ui, :debug).with("HTTP 200 Success #{uri}") expect(Bundler).to receive_message_chain(:ui, :debug).with("HTTP 200 Success #{uri}")
@ -35,8 +35,8 @@ RSpec.describe Bundler::Fetcher::Downloader do
end end
end end
context "when the request response is a Net::HTTPRedirection" do context "when the request response is a Gem::Net::HTTPRedirection" do
let(:http_response) { Net::HTTPRedirection.new(httpv, 308, "Moved") } let(:http_response) { Gem::Net::HTTPRedirection.new(httpv, 308, "Moved") }
before { http_response["location"] = "http://www.redirect-uri.com/api/v2/endpoint" } before { http_response["location"] = "http://www.redirect-uri.com/api/v2/endpoint" }
@ -59,24 +59,24 @@ RSpec.describe Bundler::Fetcher::Downloader do
end end
end end
context "when the request response is a Net::HTTPSuccess" do context "when the request response is a Gem::Net::HTTPSuccess" do
let(:http_response) { Net::HTTPSuccess.new("1.1", 200, "Success") } let(:http_response) { Gem::Net::HTTPSuccess.new("1.1", 200, "Success") }
it "should return the response body" do it "should return the response body" do
expect(subject.fetch(uri, options, counter)).to eq(http_response) expect(subject.fetch(uri, options, counter)).to eq(http_response)
end end
end end
context "when the request response is a Net::HTTPRequestEntityTooLarge" do context "when the request response is a Gem::Net::HTTPRequestEntityTooLarge" do
let(:http_response) { Net::HTTPRequestEntityTooLarge.new("1.1", 413, "Too Big") } let(:http_response) { Gem::Net::HTTPRequestEntityTooLarge.new("1.1", 413, "Too Big") }
it "should raise a Bundler::Fetcher::FallbackError with the response body" do it "should raise a Bundler::Fetcher::FallbackError with the response body" do
expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::FallbackError, "Body with info") expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::FallbackError, "Body with info")
end end
end end
context "when the request response is a Net::HTTPUnauthorized" do context "when the request response is a Gem::Net::HTTPUnauthorized" do
let(:http_response) { Net::HTTPUnauthorized.new("1.1", 401, "Unauthorized") } let(:http_response) { Gem::Net::HTTPUnauthorized.new("1.1", 401, "Unauthorized") }
it "should raise a Bundler::Fetcher::AuthenticationRequiredError with the uri host" do it "should raise a Bundler::Fetcher::AuthenticationRequiredError with the uri host" do
expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::AuthenticationRequiredError, expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::Fetcher::AuthenticationRequiredError,
@ -98,8 +98,8 @@ RSpec.describe Bundler::Fetcher::Downloader do
end end
end end
context "when the request response is a Net::HTTPForbidden" do context "when the request response is a Gem::Net::HTTPForbidden" do
let(:http_response) { Net::HTTPForbidden.new("1.1", 403, "Forbidden") } let(:http_response) { Gem::Net::HTTPForbidden.new("1.1", 403, "Forbidden") }
let(:uri) { Bundler::URI("http://user:password@www.uri-to-fetch.com") } let(:uri) { Bundler::URI("http://user:password@www.uri-to-fetch.com") }
it "should raise a Bundler::Fetcher::AuthenticationForbiddenError with the uri host" do it "should raise a Bundler::Fetcher::AuthenticationForbiddenError with the uri host" do
@ -108,12 +108,12 @@ RSpec.describe Bundler::Fetcher::Downloader do
end end
end end
context "when the request response is a Net::HTTPNotFound" do context "when the request response is a Gem::Net::HTTPNotFound" do
let(:http_response) { Net::HTTPNotFound.new("1.1", 404, "Not Found") } let(:http_response) { Gem::Net::HTTPNotFound.new("1.1", 404, "Not Found") }
it "should raise a Bundler::Fetcher::FallbackError with Net::HTTPNotFound" do it "should raise a Bundler::Fetcher::FallbackError with Gem::Net::HTTPNotFound" do
expect { subject.fetch(uri, options, counter) }. expect { subject.fetch(uri, options, counter) }.
to raise_error(Bundler::Fetcher::FallbackError, "Net::HTTPNotFound: http://www.uri-to-fetch.com/api/v2/endpoint") to raise_error(Bundler::Fetcher::FallbackError, "Gem::Net::HTTPNotFound: http://www.uri-to-fetch.com/api/v2/endpoint")
end end
context "when the there are credentials provided in the request" do context "when the there are credentials provided in the request" do
@ -121,16 +121,16 @@ RSpec.describe Bundler::Fetcher::Downloader do
it "should raise a Bundler::Fetcher::FallbackError that doesn't contain the password" do it "should raise a Bundler::Fetcher::FallbackError that doesn't contain the password" do
expect { subject.fetch(uri, options, counter) }. expect { subject.fetch(uri, options, counter) }.
to raise_error(Bundler::Fetcher::FallbackError, "Net::HTTPNotFound: http://username@www.uri-to-fetch.com/api/v2/endpoint") to raise_error(Bundler::Fetcher::FallbackError, "Gem::Net::HTTPNotFound: http://username@www.uri-to-fetch.com/api/v2/endpoint")
end end
end end
end end
context "when the request response is some other type" do context "when the request response is some other type" do
let(:http_response) { Net::HTTPBadGateway.new("1.1", 500, "Fatal Error") } let(:http_response) { Gem::Net::HTTPBadGateway.new("1.1", 500, "Fatal Error") }
it "should raise a Bundler::HTTPError with the response class and body" do it "should raise a Bundler::HTTPError with the response class and body" do
expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::HTTPError, "Net::HTTPBadGateway: Body with info") expect { subject.fetch(uri, options, counter) }.to raise_error(Bundler::HTTPError, "Gem::Net::HTTPBadGateway: Body with info")
end end
end end
end end
@ -140,7 +140,7 @@ RSpec.describe Bundler::Fetcher::Downloader do
let(:response) { double(:response) } let(:response) { double(:response) }
before do before do
allow(Net::HTTP::Get).to receive(:new).with("/api/v2/endpoint", options).and_return(net_http_get) allow(Gem::Net::HTTP::Get).to receive(:new).with("/api/v2/endpoint", options).and_return(net_http_get)
allow(connection).to receive(:request).with(uri, net_http_get).and_return(response) allow(connection).to receive(:request).with(uri, net_http_get).and_return(response)
end end

View File

@ -167,7 +167,7 @@ RSpec.describe Bundler::Fetcher do
let(:version) { "1.3.17" } let(:version) { "1.3.17" }
let(:platform) { "platform" } let(:platform) { "platform" }
let(:downloader) { double("downloader") } let(:downloader) { double("downloader") }
let(:body) { double(Net::HTTP::Get, body: downloaded_data) } let(:body) { double(Gem::Net::HTTP::Get, body: downloaded_data) }
context "when attempting to load a Gem::Specification" do context "when attempting to load a Gem::Specification" do
let(:spec) { Gem::Specification.new(name, version) } let(:spec) { Gem::Specification.new(name, version) }

View File

@ -206,7 +206,7 @@ RSpec.describe "compact index api" do
expect(the_bundle).to include_gems "rack 1.0.0" expect(the_bundle).to include_gems "rack 1.0.0"
end end
it "handles host redirects without Net::HTTP::Persistent" do it "handles host redirects without Gem::Net::HTTP::Persistent" do
gemfile <<-G gemfile <<-G
source "#{source_uri}" source "#{source_uri}"
gem "rack" gem "rack"
@ -739,7 +739,7 @@ RSpec.describe "compact index api" do
# Install a monkeypatch that reproduces the effects of openssl raising # Install a monkeypatch that reproduces the effects of openssl raising
# a certificate validation error when RubyGems tries to connect. # a certificate validation error when RubyGems tries to connect.
gemfile <<-G gemfile <<-G
class Net::HTTP class Gem::Net::HTTP
def start def start
raise OpenSSL::SSL::SSLError, "certificate verify failed" raise OpenSSL::SSL::SSLError, "certificate verify failed"
end end

View File

@ -197,7 +197,7 @@ RSpec.describe "gemcutter's dependency API" do
expect(the_bundle).to include_gems "rack 1.0.0" expect(the_bundle).to include_gems "rack 1.0.0"
end end
it "handles host redirects without Net::HTTP::Persistent" do it "handles host redirects without Gem::Net::HTTP::Persistent" do
gemfile <<-G gemfile <<-G
source "#{source_uri}" source "#{source_uri}"
gem "rack" gem "rack"
@ -723,7 +723,7 @@ RSpec.describe "gemcutter's dependency API" do
# Install a monkeypatch that reproduces the effects of openssl raising # Install a monkeypatch that reproduces the effects of openssl raising
# a certificate validation error when RubyGems tries to connect. # a certificate validation error when RubyGems tries to connect.
gemfile <<-G gemfile <<-G
class Net::HTTP class Gem::Net::HTTP
def start def start
raise OpenSSL::SSL::SSLError, "certificate verify failed" raise OpenSSL::SSL::SSLError, "certificate verify failed"
end end

View File

@ -1,11 +1,11 @@
# frozen_string_literal: true # frozen_string_literal: true
require "net/http" require "bundler/vendored_net_http"
class Fail < Net::HTTP class Fail < Gem::Net::HTTP
# Net::HTTP uses a @newimpl instance variable to decide whether # Gem::Net::HTTP uses a @newimpl instance variable to decide whether
# to use a legacy implementation. Since we are subclassing # to use a legacy implementation. Since we are subclassing
# Net::HTTP, we must set it # Gem::Net::HTTP, we must set it
@newimpl = true @newimpl = true
def request(req, body = nil, &block) def request(req, body = nil, &block)
@ -23,5 +23,5 @@ end
require_relative "helpers/artifice" require_relative "helpers/artifice"
# Replace Net::HTTP with our failing subclass # Replace Gem::Net::HTTP with our failing subclass
Artifice.replace_net_http(::Fail) Artifice.replace_net_http(::Fail)

View File

@ -4,7 +4,7 @@
module Artifice module Artifice
# Activate Artifice with a particular Rack endpoint. # Activate Artifice with a particular Rack endpoint.
# #
# Calling this method will replace the Net::HTTP system # Calling this method will replace the Gem::Net::HTTP system
# with a replacement that routes all requests to the # with a replacement that routes all requests to the
# Rack endpoint. # Rack endpoint.
# #
@ -18,11 +18,11 @@ module Artifice
# Deactivate the Artifice replacement. # Deactivate the Artifice replacement.
def self.deactivate def self.deactivate
replace_net_http(::Net::HTTP) replace_net_http(::Gem::Net::HTTP)
end end
def self.replace_net_http(value) def self.replace_net_http(value)
::Net.class_eval do ::Gem::Net.class_eval do
remove_const(:HTTP) remove_const(:HTTP)
const_set(:HTTP, value) const_set(:HTTP, value)
end end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require "rack/test" require "rack/test"
require "net/http" require "bundler/vendored_net_http"
module Artifice module Artifice
module Net module Net
@ -16,25 +16,25 @@ module Artifice
end end
end end
class HTTP < ::Net::HTTP class HTTP < ::Gem::Net::HTTP
class << self class << self
attr_accessor :endpoint attr_accessor :endpoint
end end
# Net::HTTP uses a @newimpl instance variable to decide whether # Gem::Net::HTTP uses a @newimpl instance variable to decide whether
# to use a legacy implementation. Since we are subclassing # to use a legacy implementation. Since we are subclassing
# Net::HTTP, we must set it # Gem::Net::HTTP, we must set it
@newimpl = true @newimpl = true
# We don't need to connect, so blank out this method # We don't need to connect, so blank out this method
def connect def connect
end end
# Replace the Net::HTTP request method with a method # Replace the Gem::Net::HTTP request method with a method
# that converts the request into a Rack request and # that converts the request into a Rack request and
# dispatches it to the Rack endpoint. # dispatches it to the Rack endpoint.
# #
# @param [Net::HTTPRequest] req A Net::HTTPRequest # @param [Net::HTTPRequest] req A Gem::Net::HTTPRequest
# object, or one if its subclasses # object, or one if its subclasses
# @param [optional, String, #read] body This should # @param [optional, String, #read] body This should
# be sent as "rack.input". If it's a String, it will # be sent as "rack.input". If it's a String, it will
@ -42,7 +42,7 @@ module Artifice
# @return [Net::HTTPResponse] # @return [Net::HTTPResponse]
# #
# @yield [Net::HTTPResponse] If a block is provided, # @yield [Net::HTTPResponse] If a block is provided,
# this method will yield the Net::HTTPResponse to # this method will yield the Gem::Net::HTTPResponse to
# it after the body is read. # it after the body is read.
def request(req, body = nil, &block) def request(req, body = nil, &block)
rack_request = RackRequest.new(self.class.endpoint) rack_request = RackRequest.new(self.class.endpoint)
@ -63,10 +63,10 @@ module Artifice
private private
# This method takes a Rack response and creates a Net::HTTPResponse # This method takes a Rack response and creates a Gem::Net::HTTPResponse
# Instead of trying to mock HTTPResponse directly, we just convert # Instead of trying to mock HTTPResponse directly, we just convert
# the Rack response into a String that looks like a normal HTTP # the Rack response into a String that looks like a normal HTTP
# response and call Net::HTTPResponse.read_new # response and call Gem::Net::HTTPResponse.read_new
# #
# @param [Array(#to_i, Hash, #each)] response a Rack response # @param [Array(#to_i, Hash, #each)] response a Rack response
# @return [Net::HTTPResponse] # @return [Net::HTTPResponse]
@ -86,8 +86,8 @@ module Artifice
response_string << "" << body response_string << "" << body
response_io = ::Net::BufferedIO.new(StringIO.new(response_string.join("\n"))) response_io = ::Gem::Net::BufferedIO.new(StringIO.new(response_string.join("\n")))
res = ::Net::HTTPResponse.read_new(response_io) res = ::Gem::Net::HTTPResponse.read_new(response_io)
res.reading_body(response_io, true) do res.reading_body(response_io, true) do
yield res if block_given? yield res if block_given?

View File

@ -1,13 +1,13 @@
# frozen_string_literal: true # frozen_string_literal: true
require "net/http" require "bundler/vendored_net_http"
require_relative "../path" require_relative "../path"
CASSETTE_PATH = "#{Spec::Path.spec_dir}/support/artifice/vcr_cassettes".freeze CASSETTE_PATH = "#{Spec::Path.spec_dir}/support/artifice/vcr_cassettes".freeze
USED_CASSETTES_PATH = "#{Spec::Path.spec_dir}/support/artifice/used_cassettes.txt".freeze USED_CASSETTES_PATH = "#{Spec::Path.spec_dir}/support/artifice/used_cassettes.txt".freeze
CASSETTE_NAME = ENV.fetch("BUNDLER_SPEC_VCR_CASSETTE_NAME") { "realworld" } CASSETTE_NAME = ENV.fetch("BUNDLER_SPEC_VCR_CASSETTE_NAME") { "realworld" }
class BundlerVCRHTTP < Net::HTTP class BundlerVCRHTTP < Gem::Net::HTTP
class RequestHandler class RequestHandler
attr_reader :http, :request, :body, :response_block attr_reader :http, :request, :body, :response_block
def initialize(http, request, body = nil, &response_block) def initialize(http, request, body = nil, &response_block)
@ -41,8 +41,8 @@ class BundlerVCRHTTP < Net::HTTP
def recorded_response def recorded_response
File.open(request_pair_paths.last, "rb:ASCII-8BIT") do |response_file| File.open(request_pair_paths.last, "rb:ASCII-8BIT") do |response_file|
response_io = ::Net::BufferedIO.new(response_file) response_io = ::Gem::Net::BufferedIO.new(response_file)
::Net::HTTPResponse.read_new(response_io).tap do |response| ::Gem::Net::HTTPResponse.read_new(response_io).tap do |response|
response.decode_content = request.decode_content if request.respond_to?(:decode_content) response.decode_content = request.decode_content if request.respond_to?(:decode_content)
response.uri = request.uri response.uri = request.uri
@ -148,5 +148,5 @@ end
require_relative "helpers/artifice" require_relative "helpers/artifice"
# Replace Net::HTTP with our VCR subclass # Replace Gem::Net::HTTP with our VCR subclass
Artifice.replace_net_http(BundlerVCRHTTP) Artifice.replace_net_http(BundlerVCRHTTP)