1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
# frozen_string_literal: true
begin
require 'patron'
rescue LoadError
# patron not found
end
if defined?(::Patron::Session)
module WebMock
module HttpLibAdapters
class PatronAdapter < ::WebMock::HttpLibAdapter
adapter_for :patron
OriginalPatronSession = ::Patron::Session unless const_defined?(:OriginalPatronSession)
class WebMockPatronSession < ::Patron::Session
def handle_request(req)
request_signature =
WebMock::HttpLibAdapters::PatronAdapter.build_request_signature(req)
WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)
if webmock_response = WebMock::StubRegistry.instance.response_for_request(request_signature)
WebMock::HttpLibAdapters::PatronAdapter.
handle_file_name(req, webmock_response)
res = WebMock::HttpLibAdapters::PatronAdapter.
build_patron_response(webmock_response, default_response_charset)
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :patron}, request_signature, webmock_response)
res
elsif WebMock.net_connect_allowed?(request_signature.uri)
res = super
if WebMock::CallbackRegistry.any_callbacks?
webmock_response = WebMock::HttpLibAdapters::PatronAdapter.
build_webmock_response(res)
WebMock::CallbackRegistry.invoke_callbacks(
{lib: :patron, real_request: true}, request_signature,
webmock_response)
end
res
else
raise WebMock::NetConnectNotAllowedError.new(request_signature)
end
end
end
def self.enable!
Patron.send(:remove_const, :Session)
Patron.send(:const_set, :Session, WebMockPatronSession)
end
def self.disable!
Patron.send(:remove_const, :Session)
Patron.send(:const_set, :Session, OriginalPatronSession)
end
def self.handle_file_name(req, webmock_response)
if req.action == :get && req.file_name
begin
File.open(req.file_name, "w") do |f|
f.write webmock_response.body
end
rescue Errno::EACCES
raise ArgumentError.new("Unable to open specified file.")
end
end
end
def self.build_request_signature(req)
uri = WebMock::Util::URI.heuristic_parse(req.url)
uri.path = uri.normalized_path.gsub("[^:]//","/")
if [:put, :post, :patch].include?(req.action)
if req.file_name
if !File.exist?(req.file_name) || !File.readable?(req.file_name)
raise ArgumentError.new("Unable to open specified file.")
end
request_body = File.read(req.file_name)
elsif req.upload_data
request_body = req.upload_data
else
raise ArgumentError.new("Must provide either data or a filename when doing a PUT or POST")
end
end
headers = req.headers
if req.credentials
headers['Authorization'] = WebMock::Util::Headers.basic_auth_header(req.credentials)
end
request_signature = WebMock::RequestSignature.new(
req.action,
uri.to_s,
body: request_body,
headers: headers
)
request_signature
end
def self.build_patron_response(webmock_response, default_response_charset)
raise ::Patron::TimeoutError if webmock_response.should_timeout
webmock_response.raise_error_if_any
header_fields = (webmock_response.headers || []).map { |(k, vs)| Array(vs).map { |v| "#{k}: #{v}" } }.flatten
status_line = "HTTP/1.1 #{webmock_response.status[0]} #{webmock_response.status[1]}"
header_data = ([status_line] + header_fields).join("\r\n")
::Patron::Response.new(
"".dup,
webmock_response.status[0],
0,
header_data,
webmock_response.body.dup,
default_response_charset
)
end
def self.build_webmock_response(patron_response)
webmock_response = WebMock::Response.new
reason = patron_response.status_line.
scan(%r(\AHTTP/(\d+(?:\.\d+)?)\s+(\d\d\d)\s*([^\r\n]+)?))[0][2]
webmock_response.status = [patron_response.status, reason]
webmock_response.body = patron_response.body
webmock_response.headers = patron_response.headers
webmock_response
end
end
end
end
end
|