tech-angels-typhoeus 0.1.36

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.gitignore +2 -0
  2. data/README.textile +312 -0
  3. data/Rakefile +39 -0
  4. data/VERSION +1 -0
  5. data/benchmarks/profile.rb +25 -0
  6. data/benchmarks/vs_nethttp.rb +35 -0
  7. data/examples/twitter.rb +21 -0
  8. data/ext/typhoeus/.gitignore +5 -0
  9. data/ext/typhoeus/Makefile +157 -0
  10. data/ext/typhoeus/extconf.rb +65 -0
  11. data/ext/typhoeus/native.c +11 -0
  12. data/ext/typhoeus/native.h +21 -0
  13. data/ext/typhoeus/typhoeus_easy.c +207 -0
  14. data/ext/typhoeus/typhoeus_easy.h +19 -0
  15. data/ext/typhoeus/typhoeus_multi.c +225 -0
  16. data/ext/typhoeus/typhoeus_multi.h +16 -0
  17. data/lib/typhoeus.rb +55 -0
  18. data/lib/typhoeus/.gitignore +1 -0
  19. data/lib/typhoeus/easy.rb +329 -0
  20. data/lib/typhoeus/filter.rb +28 -0
  21. data/lib/typhoeus/hydra.rb +235 -0
  22. data/lib/typhoeus/multi.rb +35 -0
  23. data/lib/typhoeus/remote.rb +306 -0
  24. data/lib/typhoeus/remote_method.rb +108 -0
  25. data/lib/typhoeus/remote_proxy_object.rb +48 -0
  26. data/lib/typhoeus/request.rb +159 -0
  27. data/lib/typhoeus/response.rb +49 -0
  28. data/lib/typhoeus/service.rb +20 -0
  29. data/profilers/valgrind.rb +24 -0
  30. data/spec/fixtures/result_set.xml +60 -0
  31. data/spec/servers/app.rb +73 -0
  32. data/spec/spec.opts +2 -0
  33. data/spec/spec_helper.rb +11 -0
  34. data/spec/typhoeus/easy_spec.rb +236 -0
  35. data/spec/typhoeus/filter_spec.rb +35 -0
  36. data/spec/typhoeus/hydra_spec.rb +311 -0
  37. data/spec/typhoeus/multi_spec.rb +74 -0
  38. data/spec/typhoeus/remote_method_spec.rb +141 -0
  39. data/spec/typhoeus/remote_proxy_object_spec.rb +65 -0
  40. data/spec/typhoeus/remote_spec.rb +695 -0
  41. data/spec/typhoeus/request_spec.rb +169 -0
  42. data/spec/typhoeus/response_spec.rb +63 -0
  43. data/typhoeus.gemspec +112 -0
  44. metadata +203 -0
@@ -0,0 +1,108 @@
1
+ module Typhoeus
2
+ class RemoteMethod
3
+ attr_accessor :http_method, :options, :base_uri, :path, :on_success, :on_failure, :cache_ttl
4
+
5
+ def initialize(options = {})
6
+ @http_method = options.delete(:method) || :get
7
+ @options = options
8
+ @base_uri = options.delete(:base_uri)
9
+ @path = options.delete(:path)
10
+ @on_success = options[:on_success]
11
+ @on_failure = options[:on_failure]
12
+ @cache_responses = options.delete(:cache_responses)
13
+ @memoize_responses = options.delete(:memoize_responses) || @cache_responses
14
+ @cache_ttl = @cache_responses == true ? 0 : @cache_responses
15
+ @keys = nil
16
+
17
+ clear_cache
18
+ end
19
+
20
+ def cache_responses?
21
+ @cache_responses
22
+ end
23
+
24
+ def memoize_responses?
25
+ @memoize_responses
26
+ end
27
+
28
+ def args_options_key(args, options)
29
+ "#{args.to_s}+#{options.to_s}"
30
+ end
31
+
32
+ def calling(args, options)
33
+ @called_methods[args_options_key(args, options)] = true
34
+ end
35
+
36
+ def already_called?(args, options)
37
+ @called_methods.has_key? args_options_key(args, options)
38
+ end
39
+
40
+ def add_response_block(block, args, options)
41
+ @response_blocks[args_options_key(args, options)] << block
42
+ end
43
+
44
+ def call_response_blocks(result, args, options)
45
+ key = args_options_key(args, options)
46
+ @response_blocks[key].each {|block| block.call(result)}
47
+ @response_blocks.delete(key)
48
+ @called_methods.delete(key)
49
+ end
50
+
51
+ def clear_cache
52
+ @response_blocks = Hash.new {|h, k| h[k] = []}
53
+ @called_methods = {}
54
+ end
55
+
56
+ def merge_options(new_options)
57
+ merged = options.merge(new_options)
58
+ if options.has_key?(:params) && new_options.has_key?(:params)
59
+ merged[:params] = options[:params].merge(new_options[:params])
60
+ end
61
+ argument_names.each {|a| merged.delete(a)}
62
+ merged.delete(:on_success) if merged[:on_success].nil?
63
+ merged.delete(:on_failure) if merged[:on_failure].nil?
64
+ merged
65
+ end
66
+
67
+ def interpolate_path_with_arguments(args)
68
+ interpolated_path = @path
69
+ argument_names.each do |arg|
70
+ interpolated_path = interpolated_path.gsub(":#{arg}", args[arg].to_s)
71
+ end
72
+ interpolated_path
73
+ end
74
+
75
+ def argument_names
76
+ return @keys if @keys
77
+ pattern, keys = compile(@path)
78
+ @keys = keys.collect {|k| k.to_sym}
79
+ end
80
+
81
+ # rippped from Sinatra. clean up stuff we don't need later
82
+ def compile(path)
83
+ path ||= ""
84
+ keys = []
85
+ if path.respond_to? :to_str
86
+ special_chars = %w{. + ( )}
87
+ pattern =
88
+ path.gsub(/((:\w+)|[\*#{special_chars.join}])/) do |match|
89
+ case match
90
+ when "*"
91
+ keys << 'splat'
92
+ "(.*?)"
93
+ when *special_chars
94
+ Regexp.escape(match)
95
+ else
96
+ keys << $2[1..-1]
97
+ "([^/?&#]+)"
98
+ end
99
+ end
100
+ [/^#{pattern}$/, keys]
101
+ elsif path.respond_to? :match
102
+ [path, keys]
103
+ else
104
+ raise TypeError, path
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,48 @@
1
+ module Typhoeus
2
+ class RemoteProxyObject
3
+ instance_methods.each { |m| undef_method m unless m =~ /^__|object_id/ }
4
+
5
+ def initialize(clear_memoized_store_proc, easy, options = {})
6
+ @clear_memoized_store_proc = clear_memoized_store_proc
7
+ @easy = easy
8
+ @success = options[:on_success]
9
+ @failure = options[:on_failure]
10
+ @cache = options.delete(:cache)
11
+ @cache_key = options.delete(:cache_key)
12
+ @timeout = options.delete(:cache_timeout)
13
+ Typhoeus.add_easy_request(@easy)
14
+ end
15
+
16
+ def method_missing(sym, *args, &block)
17
+ unless @proxied_object
18
+ if @cache && @cache_key
19
+ @proxied_object = @cache.get(@cache_key) rescue nil
20
+ end
21
+
22
+ unless @proxied_object
23
+ Typhoeus.perform_easy_requests
24
+ response = Response.new(:code => @easy.response_code,
25
+ :headers => @easy.response_header,
26
+ :body => @easy.response_body,
27
+ :time => @easy.total_time_taken,
28
+ :requested_url => @easy.url,
29
+ :requested_http_method => @easy.method,
30
+ :start_time => @easy.start_time)
31
+ if @easy.response_code >= 200 && @easy.response_code < 300
32
+ Typhoeus.release_easy_object(@easy)
33
+ @proxied_object = @success.nil? ? response : @success.call(response)
34
+
35
+ if @cache && @cache_key
36
+ @cache.set(@cache_key, @proxied_object, @timeout)
37
+ end
38
+ else
39
+ @proxied_object = @failure.nil? ? response : @failure.call(response)
40
+ end
41
+ @clear_memoized_store_proc.call
42
+ end
43
+ end
44
+
45
+ @proxied_object.__send__(sym, *args, &block)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,159 @@
1
+ module Typhoeus
2
+ class Request
3
+ attr_accessor :method, :params, :body, :headers, :timeout, :user_agent, :response, :cache_timeout, :follow_location, :max_redirects, :proxy, :disable_ssl_peer_verification, :ssl_cert, :ssl_cert_type, :ssl_key, :ssl_key_type, :ssl_key_password, :ssl_cacert, :ssl_capath, :verbose
4
+
5
+
6
+ attr_reader :url
7
+
8
+ # Initialize a new Request
9
+ #
10
+ # Options:
11
+ # * +url+ : Endpoint (URL) of the request
12
+ # * +options+ : A hash containing options among :
13
+ # ** +:method+ : :get (default) / :post / :put
14
+ # ** +:params+ : params as a Hash
15
+ # ** +:body+
16
+ # ** +:timeout+ : timeout (ms)
17
+ # ** +:headers+ : headers as Hash
18
+ # ** +:user_agent+ : user agent (string)
19
+ # ** +:cache_timeout+ : cache timeout (ms)
20
+ # ** +:follow_location
21
+ # ** +:max_redirects
22
+ # ** +:proxy
23
+ # ** +:disable_ssl_peer_verification
24
+ # ** +:ssl_cert
25
+ # ** +:ssl_cert_type
26
+ # ** +:ssl_key
27
+ # ** +:ssl_key_type
28
+ # ** +:ssl_key_password
29
+ # ** +:ssl_cacert
30
+ # ** +:ssl_capath
31
+ # ** +:verbose
32
+ #
33
+ def initialize(url, options = {})
34
+ @method = options[:method] || :get
35
+ @params = options[:params]
36
+ @body = options[:body]
37
+ @timeout = options[:timeout]
38
+ @headers = options[:headers] || {}
39
+ @user_agent = options[:user_agent] || Typhoeus::USER_AGENT
40
+ @cache_timeout = options[:cache_timeout]
41
+ @follow_location = options[:follow_location]
42
+ @max_redirects = options[:max_redirects]
43
+ @proxy = options[:proxy]
44
+ @disable_ssl_peer_verification = options[:disable_ssl_peer_verification]
45
+ @ssl_cert = options[:ssl_cert]
46
+ @ssl_cert_type = options[:ssl_cert_type]
47
+ @ssl_key = options[:ssl_key]
48
+ @ssl_key_type = options[:ssl_key_type]
49
+ @ssl_key_password = options[:ssl_key_password]
50
+ @ssl_cacert = options[:ssl_cacert]
51
+ @ssl_capath = options[:ssl_capath]
52
+ @verbose = options[:verbose]
53
+
54
+ if @method == :post
55
+ @url = url
56
+ else
57
+ @url = @params ? "#{url}?#{params_string}" : url
58
+ end
59
+ @on_complete = nil
60
+ @after_complete = nil
61
+ @handled_response = nil
62
+ end
63
+
64
+ def host
65
+ slash_location = @url.index('/', 8)
66
+ if slash_location
67
+ @url.slice(0, slash_location)
68
+ else
69
+ query_string_location = @url.index('?')
70
+ return query_string_location ? @url.slice(0, query_string_location) : @url
71
+ end
72
+ end
73
+
74
+ def headers
75
+ @headers["User-Agent"] = @user_agent
76
+ @headers
77
+ end
78
+
79
+ def params_string
80
+ params.keys.sort { |a, b| a.to_s <=> b.to_s }.collect do |k|
81
+ value = params[k]
82
+ if value.is_a? Hash
83
+ value.keys.collect {|sk| Rack::Utils.escape("#{k}[#{sk}]") + "=" + Rack::Utils.escape(value[sk].to_s)}
84
+ elsif value.is_a? Array
85
+ key = Rack::Utils.escape(k.to_s)
86
+ value.collect { |v| "#{key}=#{Rack::Utils.escape(v.to_s)}" }.join('&')
87
+ else
88
+ "#{Rack::Utils.escape(k.to_s)}=#{Rack::Utils.escape(params[k].to_s)}"
89
+ end
90
+ end.flatten.join("&")
91
+ end
92
+
93
+ def on_complete(&block)
94
+ @on_complete = block
95
+ end
96
+
97
+ def on_complete=(proc)
98
+ @on_complete = proc
99
+ end
100
+
101
+ def after_complete(&block)
102
+ @after_complete = block
103
+ end
104
+
105
+ def after_complete=(proc)
106
+ @after_complete = proc
107
+ end
108
+
109
+ def call_handlers
110
+ if @on_complete
111
+ @handled_response = @on_complete.call(response)
112
+ call_after_complete
113
+ end
114
+ end
115
+
116
+ def call_after_complete
117
+ @after_complete.call(@handled_response) if @after_complete
118
+ end
119
+
120
+ def handled_response=(val)
121
+ @handled_response = val
122
+ end
123
+
124
+ def handled_response
125
+ @handled_response || response
126
+ end
127
+
128
+ def cache_key
129
+ Digest::SHA1.hexdigest(url)
130
+ end
131
+
132
+ def self.run(url, params)
133
+ r = new(url, params)
134
+ Typhoeus::Hydra.hydra.queue r
135
+ Typhoeus::Hydra.hydra.run
136
+ r.response
137
+ end
138
+
139
+ def self.get(url, params = {})
140
+ run(url, params.merge(:method => :get))
141
+ end
142
+
143
+ def self.post(url, params = {})
144
+ run(url, params.merge(:method => :post))
145
+ end
146
+
147
+ def self.put(url, params = {})
148
+ run(url, params.merge(:method => :put))
149
+ end
150
+
151
+ def self.delete(url, params = {})
152
+ run(url, params.merge(:method => :delete))
153
+ end
154
+
155
+ def self.head(url, params = {})
156
+ run(url, params.merge(:method => :head))
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,49 @@
1
+ module Typhoeus
2
+ class Response
3
+ attr_accessor :request
4
+ attr_reader :code, :headers, :body, :time,
5
+ :requested_url, :requested_remote_method,
6
+ :requested_http_method, :start_time,
7
+ :effective_url
8
+
9
+ def initialize(params = {})
10
+ @code = params[:code]
11
+ @headers = params[:headers]
12
+ @body = params[:body]
13
+ @time = params[:time]
14
+ @requested_url = params[:requested_url]
15
+ @requested_http_method = params[:requested_http_method]
16
+ @start_time = params[:start_time]
17
+ @request = params[:request]
18
+ @effective_url = params[:effective_url]
19
+ end
20
+
21
+ def headers_hash
22
+ headers.split("\n").map {|o| o.strip}.inject({}) do |hash, o|
23
+ if o.empty?
24
+ hash
25
+ else
26
+ i = o.index(":") || o.size
27
+ key = o.slice(0, i)
28
+ value = o.slice(i + 1, o.size)
29
+ value = value.strip unless value.nil?
30
+ if hash.has_key? key
31
+ hash[key] = [hash[key], value].flatten
32
+ else
33
+ hash[key] = value
34
+ end
35
+
36
+ hash
37
+ end
38
+ end
39
+ end
40
+
41
+ def success?
42
+ @code >= 200 && @code < 300
43
+ end
44
+
45
+ def modified?
46
+ @code != 304
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,20 @@
1
+ module Typhoeus
2
+ class Service
3
+ def initialize(host, port)
4
+ @host = host
5
+ @port = port
6
+ end
7
+
8
+ def get(resource, params)
9
+ end
10
+
11
+ def put(resource, params)
12
+ end
13
+
14
+ def post(resource, params)
15
+ end
16
+
17
+ def delete(resource, params)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ # go to ext/typhoeus and run ruby extconf.rb && make before running
3
+ # this.
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + "/../ext")
6
+ require File.dirname(__FILE__) + "/../lib/typhoeus"
7
+
8
+ klass = Class.new { include Typhoeus }
9
+
10
+ loops = ENV['LOOPS'].to_i
11
+ url = ARGV.first || (raise "requires URL!")
12
+
13
+ loops.times do |i|
14
+ puts "On loop #{i}" if i % 10 == 0
15
+ results = []
16
+ 5.times do
17
+ results << klass.get(url)
18
+ end
19
+
20
+ # fire requests
21
+ results[0].code
22
+ end
23
+
24
+ puts "Ran #{loops} loops on #{url}!"
@@ -0,0 +1,60 @@
1
+ <result_set>
2
+ <ttl>20</ttl>
3
+ <result>
4
+ <id>1</id>
5
+ <name>hello</name>
6
+ <description>
7
+ this is a long description for a text field of some kind.
8
+ this is a long description for a text field of some kind.
9
+ this is a long description for a text field of some kind.
10
+ this is a long description for a text field of some kind.
11
+ this is a long description for a text field of some kind.
12
+ this is a long description for a text field of some kind.
13
+ this is a long description for a text field of some kind.
14
+ this is a long description for a text field of some kind.
15
+ this is a long description for a text field of some kind.
16
+ this is a long description for a text field of some kind.
17
+ this is a long description for a text field of some kind.
18
+ this is a long description for a text field of some kind.
19
+ this is a long description for a text field of some kind.
20
+ </description>
21
+ </result>
22
+ <result>
23
+ <id>2</id>
24
+ <name>hello</name>
25
+ <description>
26
+ this is a long description for a text field of some kind.
27
+ this is a long description for a text field of some kind.
28
+ this is a long description for a text field of some kind.
29
+ this is a long description for a text field of some kind.
30
+ this is a long description for a text field of some kind.
31
+ this is a long description for a text field of some kind.
32
+ this is a long description for a text field of some kind.
33
+ this is a long description for a text field of some kind.
34
+ this is a long description for a text field of some kind.
35
+ this is a long description for a text field of some kind.
36
+ this is a long description for a text field of some kind.
37
+ this is a long description for a text field of some kind.
38
+ this is a long description for a text field of some kind.
39
+ </description>
40
+ </result>
41
+ <result>
42
+ <id>3</id>
43
+ <name>hello</name>
44
+ <description>
45
+ this is a long description for a text field of some kind.
46
+ this is a long description for a text field of some kind.
47
+ this is a long description for a text field of some kind.
48
+ this is a long description for a text field of some kind.
49
+ this is a long description for a text field of some kind.
50
+ this is a long description for a text field of some kind.
51
+ this is a long description for a text field of some kind.
52
+ this is a long description for a text field of some kind.
53
+ this is a long description for a text field of some kind.
54
+ this is a long description for a text field of some kind.
55
+ this is a long description for a text field of some kind.
56
+ this is a long description for a text field of some kind.
57
+ this is a long description for a text field of some kind.
58
+ </description>
59
+ </result>
60
+ </result_set>