typhoeus 0.3.3 → 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.markdown → CHANGELOG.md} +21 -12
- data/LICENSE +2 -0
- data/README.md +455 -0
- data/Rakefile +6 -26
- data/lib/typhoeus.rb +4 -6
- data/lib/typhoeus/curl.rb +453 -0
- data/lib/typhoeus/easy.rb +60 -358
- 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 +90 -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/form.rb +30 -1
- data/lib/typhoeus/{normalized_header_hash.rb → header.rb} +2 -6
- data/lib/typhoeus/hydra.rb +9 -12
- data/lib/typhoeus/hydra_mock.rb +2 -2
- data/lib/typhoeus/multi.rb +118 -9
- data/lib/typhoeus/param_processor.rb +43 -0
- data/lib/typhoeus/request.rb +18 -21
- data/lib/typhoeus/response.rb +5 -4
- data/lib/typhoeus/utils.rb +14 -27
- data/lib/typhoeus/version.rb +1 -1
- metadata +155 -152
- data/Gemfile.lock +0 -37
- data/ext/typhoeus/.gitignore +0 -7
- data/ext/typhoeus/extconf.rb +0 -65
- data/ext/typhoeus/native.c +0 -12
- data/ext/typhoeus/native.h +0 -22
- data/ext/typhoeus/typhoeus_easy.c +0 -232
- data/ext/typhoeus/typhoeus_easy.h +0 -20
- data/ext/typhoeus/typhoeus_form.c +0 -59
- data/ext/typhoeus/typhoeus_form.h +0 -13
- data/ext/typhoeus/typhoeus_multi.c +0 -217
- data/ext/typhoeus/typhoeus_multi.h +0 -16
- data/lib/typhoeus/.gitignore +0 -1
- data/lib/typhoeus/service.rb +0 -20
- data/spec/fixtures/placeholder.gif +0 -0
- data/spec/fixtures/placeholder.txt +0 -1
- data/spec/fixtures/placeholder.ukn +0 -0
- data/spec/fixtures/result_set.xml +0 -60
- data/spec/servers/app.rb +0 -97
- data/spec/spec_helper.rb +0 -19
- data/spec/support/typhoeus_localhost_server.rb +0 -58
- data/spec/typhoeus/easy_spec.rb +0 -391
- data/spec/typhoeus/filter_spec.rb +0 -35
- data/spec/typhoeus/form_spec.rb +0 -117
- data/spec/typhoeus/hydra_mock_spec.rb +0 -300
- data/spec/typhoeus/hydra_spec.rb +0 -602
- data/spec/typhoeus/multi_spec.rb +0 -74
- data/spec/typhoeus/normalized_header_hash_spec.rb +0 -41
- data/spec/typhoeus/remote_method_spec.rb +0 -141
- data/spec/typhoeus/remote_proxy_object_spec.rb +0 -65
- data/spec/typhoeus/remote_spec.rb +0 -695
- data/spec/typhoeus/request_spec.rb +0 -387
- data/spec/typhoeus/response_spec.rb +0 -192
- data/spec/typhoeus/utils_spec.rb +0 -22
- data/typhoeus.gemspec +0 -33
@@ -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,90 @@
|
|
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 redirect_count
|
70
|
+
get_info_long(:redirect_count)
|
71
|
+
end
|
72
|
+
|
73
|
+
def curl_return_code
|
74
|
+
Curl::EasyCode[@curl_return_code]
|
75
|
+
end
|
76
|
+
|
77
|
+
def curl_error_message(code = @curl_return_code)
|
78
|
+
code ? Curl.easy_strerror(code) : nil
|
79
|
+
end
|
80
|
+
|
81
|
+
def curl_version
|
82
|
+
Curl.version
|
83
|
+
end
|
84
|
+
|
85
|
+
def supports_zlib?
|
86
|
+
!!(curl_version.match(/zlib/))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
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
|
+
|
@@ -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
|
data/lib/typhoeus/form.rb
CHANGED
@@ -3,16 +3,45 @@ require 'mime/types'
|
|
3
3
|
module Typhoeus
|
4
4
|
class Form
|
5
5
|
attr_accessor :params
|
6
|
-
attr_reader :traversal
|
6
|
+
attr_reader :first, :traversal
|
7
7
|
|
8
8
|
def initialize(params = {})
|
9
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) }
|
10
18
|
end
|
11
19
|
|
12
20
|
def traversal
|
13
21
|
@traversal ||= Typhoeus::Utils.traverse_params_hash(params)
|
14
22
|
end
|
15
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
|
+
|
16
45
|
def process!
|
17
46
|
# add params
|
18
47
|
traversal[:params].each { |p| formadd_param(p[0], p[1]) }
|