hhry-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.rb +57 -0
- data/lib/typhoeus/curl.rb +453 -0
- data/lib/typhoeus/easy.rb +115 -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/filter.rb +28 -0
- data/lib/typhoeus/form.rb +61 -0
- data/lib/typhoeus/header.rb +54 -0
- data/lib/typhoeus/hydra.rb +246 -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_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
- metadata +178 -0
@@ -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,14 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
module EasyFu
|
3
|
+
module Auth
|
4
|
+
def auth=(authinfo)
|
5
|
+
set_option(:userpwd, auth_credentials(authinfo))
|
6
|
+
set_option(:httpauth, Typhoeus::Easy::AUTH_TYPES[authinfo[:method]]) if authinfo[:method]
|
7
|
+
end
|
8
|
+
|
9
|
+
def auth_credentials(authinfo)
|
10
|
+
"#{authinfo[:username]}:#{authinfo[:password]}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
module EasyFu
|
3
|
+
module Callbacks
|
4
|
+
# gets called when finished and response code is not 2xx,
|
5
|
+
# or curl returns an error code.
|
6
|
+
def success
|
7
|
+
@success.call(self) if @success
|
8
|
+
end
|
9
|
+
|
10
|
+
def on_success(&block)
|
11
|
+
@success = block
|
12
|
+
end
|
13
|
+
|
14
|
+
def on_success=(block)
|
15
|
+
@success = block
|
16
|
+
end
|
17
|
+
|
18
|
+
# gets called when finished and response code is 300-599
|
19
|
+
# or curl returns an error code
|
20
|
+
def failure
|
21
|
+
@failure.call(self) if @failure
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_failure(&block)
|
25
|
+
@failure = block
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_failure=(block)
|
29
|
+
@failure = block
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
module EasyFu
|
3
|
+
module FFIHelper
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def finalizer(easy)
|
10
|
+
proc {
|
11
|
+
Curl.slist_free_all(easy.header_list) if easy.header_list
|
12
|
+
Curl.easy_cleanup(easy.handle)
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def handle
|
18
|
+
@handle ||= Curl.easy_init
|
19
|
+
end
|
20
|
+
|
21
|
+
def body_write_callback
|
22
|
+
@body_write_callback ||= proc {|stream, size, num, object|
|
23
|
+
response_body << stream.read_string(size * num)
|
24
|
+
size * num
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def header_write_callback
|
29
|
+
@header_write_callback ||= proc {|stream, size, num, object|
|
30
|
+
response_header << stream.read_string(size * num)
|
31
|
+
size * num
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def read_callback
|
36
|
+
@read_callback ||= proc {|stream, size, num, object|
|
37
|
+
size = size * num
|
38
|
+
left = Utils.bytesize(@request_body) - @request_body_read
|
39
|
+
size = left if size > left
|
40
|
+
if size > 0
|
41
|
+
stream.write_string(Utils.byteslice(@request_body, @request_body_read, size), size)
|
42
|
+
@request_body_read += size
|
43
|
+
end
|
44
|
+
size
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def string_ptr
|
49
|
+
@string_ptr ||= ::FFI::MemoryPointer.new(:pointer)
|
50
|
+
end
|
51
|
+
|
52
|
+
def long_ptr
|
53
|
+
@long_ptr ||= ::FFI::MemoryPointer.new(:long)
|
54
|
+
end
|
55
|
+
|
56
|
+
def double_ptr
|
57
|
+
@double_ptr ||= ::FFI::MemoryPointer.new(:double)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Typhoeus
|
2
|
+
module EasyFu
|
3
|
+
module Infos
|
4
|
+
def get_info_string(option)
|
5
|
+
if Curl.easy_getinfo(@handle, option, string_ptr) == :ok
|
6
|
+
string_ptr.read_pointer.read_string
|
7
|
+
else nil
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_info_long(option)
|
12
|
+
if Curl.easy_getinfo(@handle, option, long_ptr) == :ok
|
13
|
+
long_ptr.read_long
|
14
|
+
else nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_info_double(option)
|
19
|
+
if Curl.easy_getinfo(@handle, option, double_ptr) == :ok
|
20
|
+
double_ptr.read_double
|
21
|
+
else nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def auth_methods
|
26
|
+
get_info_long(:httpauth_avail)
|
27
|
+
end
|
28
|
+
|
29
|
+
def total_time_taken
|
30
|
+
get_info_double(:total_time)
|
31
|
+
end
|
32
|
+
|
33
|
+
def start_transfer_time
|
34
|
+
get_info_double(:starttransfer_time)
|
35
|
+
end
|
36
|
+
|
37
|
+
def app_connect_time
|
38
|
+
get_info_double(:appconnect_time)
|
39
|
+
end
|
40
|
+
|
41
|
+
def pretransfer_time
|
42
|
+
get_info_double(:pretransfer_time)
|
43
|
+
end
|
44
|
+
|
45
|
+
def connect_time
|
46
|
+
get_info_double(:connect_time)
|
47
|
+
end
|
48
|
+
|
49
|
+
def name_lookup_time
|
50
|
+
get_info_double(:namelookup_time)
|
51
|
+
end
|
52
|
+
|
53
|
+
def effective_url
|
54
|
+
get_info_string(:effective_url)
|
55
|
+
end
|
56
|
+
|
57
|
+
def primary_ip
|
58
|
+
get_info_string(:primary_ip)
|
59
|
+
end
|
60
|
+
|
61
|
+
def response_code
|
62
|
+
get_info_long(:response_code)
|
63
|
+
end
|
64
|
+
|
65
|
+
def timed_out?
|
66
|
+
@curl_return_code == :operation_timedout
|
67
|
+
end
|
68
|
+
|
69
|
+
def curl_return_code
|
70
|
+
Curl::EasyCode[@curl_return_code]
|
71
|
+
end
|
72
|
+
|
73
|
+
def curl_error_message(code = @curl_return_code)
|
74
|
+
code ? Curl.easy_strerror(code) : nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def curl_version
|
78
|
+
Curl.version
|
79
|
+
end
|
80
|
+
|
81
|
+
def supports_zlib?
|
82
|
+
!!(curl_version.match(/zlib/))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -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
|
+
|