dcu-typhoeus 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +93 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +455 -0
- data/Rakefile +23 -0
- data/lib/typhoeus/curl.rb +453 -0
- data/lib/typhoeus/easy/auth.rb +14 -0
- data/lib/typhoeus/easy/callbacks.rb +33 -0
- data/lib/typhoeus/easy/ffi_helper.rb +61 -0
- data/lib/typhoeus/easy/infos.rb +86 -0
- data/lib/typhoeus/easy/options.rb +115 -0
- data/lib/typhoeus/easy/proxy.rb +20 -0
- data/lib/typhoeus/easy/ssl.rb +82 -0
- data/lib/typhoeus/easy.rb +115 -0
- data/lib/typhoeus/filter.rb +28 -0
- data/lib/typhoeus/form.rb +61 -0
- data/lib/typhoeus/header.rb +54 -0
- data/lib/typhoeus/hydra/callbacks.rb +24 -0
- data/lib/typhoeus/hydra/connect_options.rb +61 -0
- data/lib/typhoeus/hydra/stubbing.rb +68 -0
- data/lib/typhoeus/hydra.rb +246 -0
- data/lib/typhoeus/hydra_mock.rb +131 -0
- data/lib/typhoeus/multi.rb +146 -0
- data/lib/typhoeus/param_processor.rb +43 -0
- data/lib/typhoeus/remote.rb +310 -0
- data/lib/typhoeus/remote_method.rb +108 -0
- data/lib/typhoeus/remote_proxy_object.rb +50 -0
- data/lib/typhoeus/request.rb +278 -0
- data/lib/typhoeus/response.rb +122 -0
- data/lib/typhoeus/utils.rb +58 -0
- data/lib/typhoeus/version.rb +3 -0
- data/lib/typhoeus.rb +57 -0
- metadata +179 -0
@@ -0,0 +1,115 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
module EasyFu
|
3
|
+
module Options
|
4
|
+
def write_function=(callback)
|
5
|
+
set_option(:writefunction, body_write_callback)
|
6
|
+
end
|
7
|
+
|
8
|
+
def header_function=(callback)
|
9
|
+
set_option(:headerfunction, header_write_callback)
|
10
|
+
end
|
11
|
+
|
12
|
+
def encoding=(encoding)
|
13
|
+
# Enable encoding/compression support
|
14
|
+
set_option(:encoding, encoding)
|
15
|
+
end
|
16
|
+
|
17
|
+
def interface=(interface)
|
18
|
+
@interface = interface
|
19
|
+
set_option(:interface, interface)
|
20
|
+
end
|
21
|
+
|
22
|
+
def verbose=(boolean)
|
23
|
+
set_option(:verbose, !!boolean ? 1 : 0)
|
24
|
+
end
|
25
|
+
|
26
|
+
def follow_location=(boolean)
|
27
|
+
if boolean
|
28
|
+
set_option(:followlocation, 1)
|
29
|
+
else
|
30
|
+
set_option(:followlocation, 0)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def max_redirects=(redirects)
|
35
|
+
set_option(:maxredirs, redirects)
|
36
|
+
end
|
37
|
+
|
38
|
+
def connect_timeout=(milliseconds)
|
39
|
+
@connect_timeout = milliseconds
|
40
|
+
set_option(:nosignal, 1)
|
41
|
+
set_option(:connecttimeout_ms, milliseconds)
|
42
|
+
end
|
43
|
+
|
44
|
+
def timeout=(milliseconds)
|
45
|
+
@timeout = milliseconds
|
46
|
+
set_option(:nosignal, 1)
|
47
|
+
set_option(:timeout_ms, milliseconds)
|
48
|
+
end
|
49
|
+
|
50
|
+
def request_body=(request_body)
|
51
|
+
@request_body = request_body
|
52
|
+
if method == :put
|
53
|
+
@request_body_read = 0
|
54
|
+
set_option(:infilesize, Utils.bytesize(@request_body))
|
55
|
+
set_option(:readfunction, read_callback)
|
56
|
+
else
|
57
|
+
self.post_data = request_body
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def user_agent=(user_agent)
|
62
|
+
set_option(:useragent, user_agent)
|
63
|
+
end
|
64
|
+
|
65
|
+
def url=(url)
|
66
|
+
@url = url
|
67
|
+
set_option(:url, url)
|
68
|
+
end
|
69
|
+
|
70
|
+
def method=(method)
|
71
|
+
@method = method
|
72
|
+
if method == :get
|
73
|
+
set_option(:httpget, 1)
|
74
|
+
elsif method == :post
|
75
|
+
set_option(:httppost, 1)
|
76
|
+
self.post_data = ""
|
77
|
+
elsif method == :put
|
78
|
+
set_option(:upload, 1)
|
79
|
+
self.request_body = @request_body.to_s
|
80
|
+
elsif method == :head
|
81
|
+
set_option(:nobody, 1)
|
82
|
+
else
|
83
|
+
set_option(:customrequest, method.to_s.upcase)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def post_data=(data)
|
88
|
+
@post_data_set = true
|
89
|
+
set_option(:postfieldsize, Utils.bytesize(data))
|
90
|
+
set_option(:copypostfields, data)
|
91
|
+
end
|
92
|
+
|
93
|
+
def set_option(option, value)
|
94
|
+
case value
|
95
|
+
when String
|
96
|
+
Curl.easy_setopt_string(handle, option, value.to_s)
|
97
|
+
when Integer
|
98
|
+
Curl.easy_setopt_long(handle, option, value)
|
99
|
+
when Proc, ::FFI::Function
|
100
|
+
Curl.easy_setopt_callback(handle, option, value)
|
101
|
+
when Typhoeus::Form
|
102
|
+
Curl.easy_setopt(handle, option, value.first.read_pointer)
|
103
|
+
else
|
104
|
+
Curl.easy_setopt(handle, option, value) if value
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def set_headers
|
109
|
+
@header_list = nil
|
110
|
+
headers.each {|key, value| @header_list = Curl.slist_append(@header_list, "#{key}: #{value}") }
|
111
|
+
set_option(:httpheader, @header_list) unless headers.empty?
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
module EasyFu
|
3
|
+
module Proxy
|
4
|
+
def proxy=(proxy)
|
5
|
+
set_option(:proxy, proxy[:server])
|
6
|
+
set_option(:proxytype, Typhoeus::Easy::PROXY_TYPES[proxy[:type]]) if proxy[:type]
|
7
|
+
end
|
8
|
+
|
9
|
+
def proxy_auth=(authinfo)
|
10
|
+
set_option(:proxyuserpwd, proxy_credentials(authinfo))
|
11
|
+
set_option(:proxyauth, Typhoeus::Easy::PROXY_TYPES[proxy[:type]]) if authinfo[:method]
|
12
|
+
end
|
13
|
+
|
14
|
+
def proxy_credentials(authinfo)
|
15
|
+
"#{authinfo[:username]}:#{authinfo[:password]}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
module EasyFu
|
3
|
+
module SSL
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def valid_ssl_version(version)
|
10
|
+
Typhoeus::Easy::SSL_VERSIONS.key?(version.to_sym)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def ssl_version
|
15
|
+
@ssl_version
|
16
|
+
end
|
17
|
+
|
18
|
+
def ssl_version=(version)
|
19
|
+
raise "Invalid SSL version: '#{version}' supplied! Please supply one as listed in Typhoeus::Easy::SSL_VERSIONS" unless self.class.valid_ssl_version(version)
|
20
|
+
@ssl_version = version
|
21
|
+
|
22
|
+
set_option(:sslversion, Typhoeus::Easy::SSL_VERSIONS[version])
|
23
|
+
end
|
24
|
+
|
25
|
+
def disable_ssl_peer_verification
|
26
|
+
set_option(:verifypeer, 0)
|
27
|
+
end
|
28
|
+
|
29
|
+
def disable_ssl_host_verification
|
30
|
+
set_option(:verifyhost, 0)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Set SSL certificate
|
34
|
+
# " The string should be the file name of your certificate. "
|
35
|
+
# The default format is "PEM" and can be changed with ssl_cert_type=
|
36
|
+
def ssl_cert=(cert)
|
37
|
+
set_option(:sslcert, cert)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Set SSL certificate type
|
41
|
+
# " The string should be the format of your certificate. Supported formats are "PEM" and "DER" "
|
42
|
+
def ssl_cert_type=(cert_type)
|
43
|
+
raise "Invalid ssl cert type : '#{cert_type}'..." if cert_type and !%w(PEM DER p12).include?(cert_type)
|
44
|
+
set_option(:sslcerttype, cert_type)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Set SSL Key file
|
48
|
+
# " The string should be the file name of your private key. "
|
49
|
+
# The default format is "PEM" and can be changed with ssl_key_type=
|
50
|
+
#
|
51
|
+
def ssl_key=(key)
|
52
|
+
set_option(:sslkey, key)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Set SSL Key type
|
56
|
+
# " The string should be the format of your private key. Supported formats are "PEM", "DER" and "ENG". "
|
57
|
+
#
|
58
|
+
def ssl_key_type=(key_type)
|
59
|
+
raise "Invalid ssl key type : '#{key_type}'..." if key_type and !%w(PEM DER ENG).include?(key_type)
|
60
|
+
set_option(:sslkeytype, key_type)
|
61
|
+
end
|
62
|
+
|
63
|
+
def ssl_key_password=(key_password)
|
64
|
+
set_option(:keypasswd, key_password)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Set SSL CACERT
|
68
|
+
# " File holding one or more certificates to verify the peer with. "
|
69
|
+
#
|
70
|
+
def ssl_cacert=(cacert)
|
71
|
+
set_option(:cainfo, cacert)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Set CAPATH
|
75
|
+
# " directory holding multiple CA certificates to verify the peer with. The certificate directory must be prepared using the openssl c_rehash utility. "
|
76
|
+
#
|
77
|
+
def ssl_capath=(capath)
|
78
|
+
set_option(:capath, capath)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'typhoeus/easy/ffi_helper'
|
2
|
+
require 'typhoeus/easy/options'
|
3
|
+
require 'typhoeus/easy/ssl'
|
4
|
+
require 'typhoeus/easy/auth'
|
5
|
+
require 'typhoeus/easy/proxy'
|
6
|
+
require 'typhoeus/easy/callbacks'
|
7
|
+
require 'typhoeus/easy/infos'
|
8
|
+
|
9
|
+
module Typhoeus
|
10
|
+
class Easy
|
11
|
+
include Typhoeus::EasyFu::FFIHelper
|
12
|
+
include Typhoeus::EasyFu::Options
|
13
|
+
include Typhoeus::EasyFu::SSL
|
14
|
+
include Typhoeus::EasyFu::Auth
|
15
|
+
include Typhoeus::EasyFu::Proxy
|
16
|
+
include Typhoeus::EasyFu::Callbacks
|
17
|
+
include Typhoeus::EasyFu::Infos
|
18
|
+
|
19
|
+
OPTION_VALUES = Curl::Option.to_hash.dup
|
20
|
+
Curl::Option.to_hash.each {|key, value| OPTION_VALUES["CURLOPT_#{key.to_s.upcase}".to_sym] = value }
|
21
|
+
INFO_VALUES = Curl::Info.to_hash.dup
|
22
|
+
Curl::Info.to_hash.each {|key, value| INFO_VALUES["CURLINFO_#{key.to_s.upcase}".to_sym] = value }
|
23
|
+
AUTH_TYPES = Curl::Auth.to_hash.dup
|
24
|
+
Curl::Auth.to_hash.each {|key, value| AUTH_TYPES["CURLAUTH_#{key.to_s.upcase}".to_sym] = value }
|
25
|
+
PROXY_TYPES = Curl::Proxy.to_hash.dup
|
26
|
+
Curl::Proxy.to_hash.each {|key, value| PROXY_TYPES["CURLPROXY_#{key.to_s.upcase}".to_sym] = value }
|
27
|
+
SSL_VERSIONS = Curl::SSLVersion.to_hash.dup
|
28
|
+
Curl::SSLVersion.to_hash.each {|key, value| SSL_VERSIONS["CURL_SSLVERSION_#{key.to_s.upcase}".to_sym] = value }
|
29
|
+
|
30
|
+
attr_reader :url, :header_list
|
31
|
+
attr_accessor :start_time
|
32
|
+
|
33
|
+
def initialize
|
34
|
+
Curl.init
|
35
|
+
reset(true)
|
36
|
+
ObjectSpace.define_finalizer(self, self.class.finalizer(self))
|
37
|
+
end
|
38
|
+
|
39
|
+
def method
|
40
|
+
@method ||= :get
|
41
|
+
end
|
42
|
+
|
43
|
+
def headers
|
44
|
+
@header ||= {}
|
45
|
+
end
|
46
|
+
|
47
|
+
def response_body
|
48
|
+
@response_body ||= ""
|
49
|
+
end
|
50
|
+
|
51
|
+
def response_header
|
52
|
+
@response_header ||= ""
|
53
|
+
end
|
54
|
+
|
55
|
+
def headers=(hash)
|
56
|
+
@headers = hash
|
57
|
+
end
|
58
|
+
|
59
|
+
def params
|
60
|
+
@form.nil? ? {} : @form.params
|
61
|
+
end
|
62
|
+
|
63
|
+
def params=(params)
|
64
|
+
@form = Typhoeus::Form.new(params)
|
65
|
+
|
66
|
+
if method == :post
|
67
|
+
@form.process!
|
68
|
+
if @form.multipart?
|
69
|
+
set_option(:httppost, @form)
|
70
|
+
else
|
71
|
+
self.post_data = @form.to_s
|
72
|
+
end
|
73
|
+
else
|
74
|
+
self.url = "#{url}?#{@form.to_s}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def perform
|
79
|
+
set_headers()
|
80
|
+
@curl_return_code = Curl.easy_perform(handle)
|
81
|
+
resp_code = response_code()
|
82
|
+
if resp_code >= 200 && resp_code <= 299
|
83
|
+
success
|
84
|
+
else
|
85
|
+
failure
|
86
|
+
end
|
87
|
+
resp_code
|
88
|
+
end
|
89
|
+
|
90
|
+
def reset(fresh = nil)
|
91
|
+
unless fresh
|
92
|
+
@response_code = 0
|
93
|
+
@response_header = ""
|
94
|
+
@response_body = ""
|
95
|
+
@request_body = ""
|
96
|
+
|
97
|
+
if @header_list
|
98
|
+
Curl.slist_free_all(@header_list)
|
99
|
+
@header_list = nil
|
100
|
+
end
|
101
|
+
|
102
|
+
Curl.easy_reset(handle)
|
103
|
+
end
|
104
|
+
|
105
|
+
self.write_function = body_write_callback
|
106
|
+
self.header_function = header_write_callback
|
107
|
+
self.encoding = ''
|
108
|
+
self.ssl_version = :default
|
109
|
+
end
|
110
|
+
|
111
|
+
def curl_return_code=(code)
|
112
|
+
@curl_return_code = (code.class == Symbol ? code : Curl::EasyCode[code])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Filter
|
3
|
+
attr_reader :method_name
|
4
|
+
|
5
|
+
def initialize(method_name, options = {})
|
6
|
+
@method_name = method_name
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def apply_filter?(method_name)
|
11
|
+
if @options[:only]
|
12
|
+
if @options[:only].instance_of? Symbol
|
13
|
+
@options[:only] == method_name
|
14
|
+
else
|
15
|
+
@options[:only].include?(method_name)
|
16
|
+
end
|
17
|
+
elsif @options[:except]
|
18
|
+
if @options[:except].instance_of? Symbol
|
19
|
+
@options[:except] != method_name
|
20
|
+
else
|
21
|
+
!@options[:except].include?(method_name)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'mime/types'
|
2
|
+
|
3
|
+
module Typhoeus
|
4
|
+
class Form
|
5
|
+
attr_accessor :params
|
6
|
+
attr_reader :first, :traversal
|
7
|
+
|
8
|
+
def initialize(params = {})
|
9
|
+
@params = params
|
10
|
+
@first = ::FFI::MemoryPointer.new(:pointer)
|
11
|
+
@last = ::FFI::MemoryPointer.new(:pointer)
|
12
|
+
|
13
|
+
ObjectSpace.define_finalizer(self, self.class.finalizer(self))
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.finalizer(form)
|
17
|
+
proc { Curl.formfree(form.first) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def traversal
|
21
|
+
@traversal ||= Typhoeus::Utils.traverse_params_hash(params)
|
22
|
+
end
|
23
|
+
|
24
|
+
def formadd_param(name, contents)
|
25
|
+
Curl.formadd(@first, @last,
|
26
|
+
:form_option, :copyname, :pointer, name,
|
27
|
+
:form_option, :namelength, :long, Utils.bytesize(name),
|
28
|
+
:form_option, :copycontents, :pointer, contents,
|
29
|
+
:form_option, :contentslength, :long, Utils.bytesize(contents),
|
30
|
+
:form_option, :end)
|
31
|
+
end
|
32
|
+
private :formadd_param
|
33
|
+
|
34
|
+
def formadd_file(name, filename, contenttype, file)
|
35
|
+
Curl.formadd(@first, @last,
|
36
|
+
:form_option, :copyname, :pointer, name,
|
37
|
+
:form_option, :namelength, :long, Utils.bytesize(name),
|
38
|
+
:form_option, :file, :string, file,
|
39
|
+
:form_option, :filename, :string, filename,
|
40
|
+
:form_option, :contenttype, :string, contenttype,
|
41
|
+
:form_option, :end)
|
42
|
+
end
|
43
|
+
private :formadd_file
|
44
|
+
|
45
|
+
def process!
|
46
|
+
# add params
|
47
|
+
traversal[:params].each { |p| formadd_param(p[0], p[1]) }
|
48
|
+
|
49
|
+
# add files
|
50
|
+
traversal[:files].each { |file_args| formadd_file(*file_args) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def multipart?
|
54
|
+
!traversal[:files].empty?
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_s
|
58
|
+
Typhoeus::Utils.traversal_to_param_string(traversal, false)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Header < ::Hash
|
3
|
+
def initialize(constructor = {})
|
4
|
+
if constructor.is_a?(Hash)
|
5
|
+
super
|
6
|
+
update(constructor)
|
7
|
+
else
|
8
|
+
super(constructor)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def fetch(key, *extras)
|
13
|
+
super(convert_key(key), *extras)
|
14
|
+
end
|
15
|
+
|
16
|
+
def key?(key)
|
17
|
+
super(convert_key(key))
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](key)
|
21
|
+
super(convert_key(key))
|
22
|
+
end
|
23
|
+
|
24
|
+
def []=(key, value)
|
25
|
+
super(convert_key(key), value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def update(other_hash)
|
29
|
+
other_hash.each_pair do |key, value|
|
30
|
+
self[convert_key(key)] = value
|
31
|
+
end
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
alias_method :merge!, :update
|
36
|
+
|
37
|
+
def dup
|
38
|
+
self.class.new(Marshal.load(Marshal.dump(self)))
|
39
|
+
end
|
40
|
+
|
41
|
+
def merge(hash)
|
42
|
+
self.dup.update(hash)
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete(key)
|
46
|
+
super(convert_key(key))
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def convert_key(key)
|
51
|
+
key.to_s.split(/_|-/).map { |segment| segment.capitalize }.join("-")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Hydra
|
3
|
+
module Callbacks
|
4
|
+
def self.extended(base)
|
5
|
+
class << base
|
6
|
+
attr_accessor :global_hooks
|
7
|
+
end
|
8
|
+
base.global_hooks = Hash.new { |h, k| h[k] = [] }
|
9
|
+
end
|
10
|
+
|
11
|
+
def after_request_before_on_complete(&block)
|
12
|
+
global_hooks[:after_request_before_on_complete] << block
|
13
|
+
end
|
14
|
+
|
15
|
+
def run_global_hooks_for(name, request)
|
16
|
+
global_hooks[name].each { |hook| hook.call(request) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear_global_hooks
|
20
|
+
global_hooks.clear
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Hydra
|
3
|
+
class NetConnectNotAllowedError < StandardError; end
|
4
|
+
|
5
|
+
module ConnectOptions
|
6
|
+
def self.included(base)
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
# This method checks to see if we should raise an error on
|
11
|
+
# a request.
|
12
|
+
#
|
13
|
+
# @raises NetConnectNotAllowedError
|
14
|
+
def check_allow_net_connect!(request)
|
15
|
+
return if Typhoeus::Hydra.allow_net_connect?
|
16
|
+
return if Typhoeus::Hydra.ignore_hosts.include?(request.host_domain)
|
17
|
+
|
18
|
+
raise NetConnectNotAllowedError, "Real HTTP requests are not allowed. Unregistered request: #{request.inspect}"
|
19
|
+
end
|
20
|
+
private :check_allow_net_connect!
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
def self.extended(base)
|
24
|
+
class << base
|
25
|
+
attr_accessor :allow_net_connect
|
26
|
+
attr_accessor :ignore_localhost
|
27
|
+
end
|
28
|
+
base.allow_net_connect = true
|
29
|
+
base.ignore_localhost = false
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns whether we allow external HTTP connections.
|
33
|
+
# Useful for mocking/tests.
|
34
|
+
#
|
35
|
+
# @return [boolean] true/false
|
36
|
+
def allow_net_connect?
|
37
|
+
allow_net_connect
|
38
|
+
end
|
39
|
+
|
40
|
+
def ignore_localhost?
|
41
|
+
ignore_localhost
|
42
|
+
end
|
43
|
+
|
44
|
+
def ignore_hosts
|
45
|
+
@ignore_hosts ||= []
|
46
|
+
|
47
|
+
if ignore_localhost?
|
48
|
+
@ignore_hosts + Typhoeus::Request::LOCALHOST_ALIASES
|
49
|
+
else
|
50
|
+
@ignore_hosts
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def ignore_hosts=(hosts)
|
55
|
+
@ignore_hosts = hosts
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
class Hydra
|
3
|
+
module Stubbing
|
4
|
+
module SharedMethods
|
5
|
+
def stub(method, url, options = {})
|
6
|
+
stubs << HydraMock.new(url, method, options)
|
7
|
+
stubs.last
|
8
|
+
end
|
9
|
+
|
10
|
+
def clear_stubs
|
11
|
+
self.stubs = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def register_stub_finder(&block)
|
15
|
+
stub_finders << block
|
16
|
+
end
|
17
|
+
|
18
|
+
def find_stub_from_request(request)
|
19
|
+
stub_finders.each do |finder|
|
20
|
+
if response = finder.call(request)
|
21
|
+
mock = HydraMock.new(/.*/, :any)
|
22
|
+
mock.and_return(response)
|
23
|
+
return mock
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
stubs.detect { |stub| stub.matches?(request) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def stub_finders
|
31
|
+
@stub_finders ||= []
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.extended(base)
|
35
|
+
class << base
|
36
|
+
attr_accessor :stubs
|
37
|
+
end
|
38
|
+
base.stubs = []
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.included(base)
|
43
|
+
base.extend(SharedMethods)
|
44
|
+
base.class_eval do
|
45
|
+
attr_accessor :stubs
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def assign_to_stub(request)
|
50
|
+
m = find_stub_from_request(request)
|
51
|
+
|
52
|
+
# Fallback to global stubs.
|
53
|
+
m ||= self.class.find_stub_from_request(request)
|
54
|
+
|
55
|
+
if m
|
56
|
+
m.add_request(request)
|
57
|
+
@active_stubs << m
|
58
|
+
m
|
59
|
+
else
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
private :assign_to_stub
|
64
|
+
|
65
|
+
include SharedMethods
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|