curb-fu 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,64 @@
1
+ dir = File.dirname(__FILE__)
2
+ $:.unshift(dir) unless $:.include?(dir)
3
+ require 'curb-fu/response'
4
+ require 'curb-fu/request'
5
+ require 'curb-fu/entity'
6
+ require 'curb-fu/authentication'
7
+ require 'curb-fu/core_ext'
8
+ require 'curb-fu/test'
9
+
10
+ module CurbFu
11
+ class << self
12
+ def get(*args)
13
+ CurbFu::Request.get(*args)
14
+ end
15
+
16
+ def post(*args)
17
+ CurbFu::Request.post(*args)
18
+ end
19
+
20
+ def put(*args)
21
+ CurbFu::Request.put(*args)
22
+ end
23
+
24
+ def delete(*args)
25
+ CurbFu::Request.delete(*args)
26
+ end
27
+
28
+ attr_accessor :stubs
29
+
30
+ def stubs=(val)
31
+ if val
32
+ @stubs = {}
33
+ val.each do |hostname, rack_app|
34
+ stub(hostname, rack_app)
35
+ end
36
+
37
+ unless CurbFu::Request.include?(CurbFu::Request::Test)
38
+ CurbFu::Request.send(:include, CurbFu::Request::Test)
39
+ end
40
+ else
41
+ @stubs = nil
42
+ end
43
+ end
44
+
45
+ def stub(hostname, rack_app)
46
+ raise "You must use CurbFu.stubs= to define initial stubs before using stub()" if @stubs.nil?
47
+ @stubs[hostname] = CurbFu::Request::Test::Interface.new(rack_app, hostname)
48
+ end
49
+
50
+ def stubs
51
+ @stubs
52
+ end
53
+
54
+ def debug=(val)
55
+ @debug = val ? true : false
56
+ end
57
+
58
+ def debug?
59
+ @debug
60
+ end
61
+
62
+
63
+ end
64
+ end
@@ -0,0 +1,5 @@
1
+ module CurbFu
2
+ module Authentication
3
+ BASIC = Curl::CURLAUTH_BASIC
4
+ end
5
+ end
@@ -0,0 +1,59 @@
1
+ require 'cgi'
2
+
3
+ ##
4
+ # ActiveSupport look alike for to_param. Very useful.
5
+ module CurbFu
6
+ module HashExtensions
7
+ def self.included(base)
8
+ base.send(:include, InstanceMethods) unless base.methods.include?(:to_param)
9
+ #base.extend(ClassMethods)
10
+ end
11
+
12
+ module InstanceMethods
13
+ def to_param(prefix)
14
+ collect do |k, v|
15
+ key_prefix = prefix ? "#{prefix}[#{k}]" : k
16
+ v.to_param(key_prefix)
17
+ end.join("&")
18
+ end
19
+ end
20
+ end
21
+
22
+ module ObjectExtensions
23
+ def self.included(base)
24
+ base.send(:include, InstanceMethods) unless base.methods.include?(:to_param)
25
+ #base.extend(ClassMethods)
26
+ end
27
+
28
+ module InstanceMethods
29
+ def to_param(prefix)
30
+ value = CGI::escape(to_s)
31
+ "#{prefix}=#{value}"
32
+ end
33
+ end
34
+ end
35
+
36
+ module ArrayExtensions
37
+ def self.included(base)
38
+ base.send(:include, InstanceMethods) unless base.methods.include?(:to_param)
39
+ #base.extend(ClassMethods)
40
+ end
41
+
42
+ module InstanceMethods
43
+ def to_param(prefix)
44
+ prefix = "#{prefix}[]"
45
+ collect { |item| "#{item.to_param(prefix)}" }.join('&')
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ class Hash
52
+ include CurbFu::HashExtensions
53
+ end
54
+ class Array
55
+ include CurbFu::ArrayExtensions
56
+ end
57
+ class Object
58
+ include CurbFu::ObjectExtensions
59
+ end
@@ -0,0 +1,54 @@
1
+ require 'json'
2
+ require 'uri'
3
+
4
+ module CurbFu
5
+ class Entity
6
+ attr_accessor :content_type, :data
7
+
8
+ def initialze(data)
9
+ self.data = data
10
+ end
11
+
12
+ def data
13
+ @data ||= ''
14
+ end
15
+
16
+ def to_request_data
17
+ return data if data.is_a?(String)
18
+
19
+ case content_type
20
+ when :uri then
21
+ to_uri
22
+ when 'application/json',:json then
23
+ to_json
24
+ # when 'application/xml',:xml then to_xml
25
+ when 'text/www-form-urlencoded',:form,:url then
26
+ to_www_form_url_encoded
27
+ end
28
+ end
29
+
30
+ # def to_xml
31
+ # "XML"
32
+ # end
33
+
34
+ def to_uri
35
+ strings = data.inject([]) do |acc, (name, value)|
36
+ acc << "#{name.to_s}=#{value}"
37
+ acc
38
+ end
39
+ URI.escape(strings.join('&'))
40
+ end
41
+
42
+ def to_json
43
+ data.to_json
44
+ end
45
+
46
+ def to_www_form_url_encoded
47
+ strings = data.inject([]) do |acc, (name, value)|
48
+ acc << "#{CGI.escape(name.to_s)}=#{CGI.escape(value)}"
49
+ acc
50
+ end
51
+ strings.join('&')
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'curb'
3
+ require 'curb-fu/request/common'
4
+ require 'curb-fu/request/base'
5
+ require 'curb-fu/request/parameter'
6
+ require 'curb-fu/request/test'
7
+
8
+ module CurbFu
9
+ class Request
10
+ extend Base
11
+ end
12
+ end
@@ -0,0 +1,118 @@
1
+ module CurbFu
2
+ class Request
3
+ module Base
4
+ include Common
5
+
6
+ def build(url_params, query_params = {})
7
+ curb = Curl::Easy.new(build_url(url_params, query_params))
8
+
9
+ headers = global_headers
10
+
11
+ unless url_params.is_a?(String)
12
+ curb.userpwd = "#{url_params[:username]}:#{url_params[:password]}" if url_params[:username]
13
+ if url_params[:authtype]
14
+ curb.http_auth_types = url_params[:authtype]
15
+ elsif url_params[:username]
16
+ curb.http_auth_types = CurbFu::Authentication::BASIC
17
+ end
18
+
19
+ headers = headers.merge(url_params[:headers]) unless url_params[:headers].nil?
20
+ headers["Expect"] = '' unless url_params[:headers] && url_params[:headers]["Expect"]
21
+ end
22
+
23
+ curb.headers = headers
24
+ curb.timeout = @timeout
25
+
26
+ curb
27
+ end
28
+
29
+ # Set headers to be used for every request
30
+ # * headers: hash of header names and values
31
+ def global_headers=(headers)
32
+ @global_headers = headers
33
+ end
34
+
35
+ # Headers to be used for every request
36
+ # Returns: hash of header names and values
37
+ def global_headers
38
+ @global_headers ||= {}
39
+ end
40
+
41
+ def get(url, params = {})
42
+ curb = self.build(url, params)
43
+ curb.http_get
44
+ CurbFu::Response::Base.from_curb_response(curb)
45
+ end
46
+
47
+ def put(url, params = {})
48
+ curb = self.build(url, params)
49
+ curb.http_put("")
50
+ CurbFu::Response::Base.from_curb_response(curb)
51
+ end
52
+
53
+ def post(url, params = {})
54
+ fields = create_post_fields(params)
55
+ fields = [fields] if fields.is_a?(String)
56
+
57
+ curb = self.build(url)
58
+ curb.http_post(*fields)
59
+ CurbFu::Response::Base.from_curb_response(curb)
60
+ end
61
+
62
+ def post_file(url, params = {}, filez = {})
63
+ fields = create_post_fields(params)
64
+ fields += create_file_fields(filez)
65
+
66
+ curb = self.build(url)
67
+ curb.multipart_form_post = true
68
+
69
+ begin
70
+ curb.http_post(*fields)
71
+ rescue Curl::Err::InvalidPostFieldError => e
72
+ field_list = (params.merge(filez)).inject([]) { |list, (name, value)| list << "#{name} => #{value.to_s[0..49].inspect}"; list }
73
+ raise e, "There was an attempt to post invalid fields. The fields were:\n#{field_list.join("\n")}"
74
+ end
75
+ CurbFu::Response::Base.from_curb_response(curb)
76
+ end
77
+
78
+ def delete(url)
79
+ curb = self.build(url)
80
+ curb.http_delete
81
+ CurbFu::Response::Base.from_curb_response(curb)
82
+ end
83
+
84
+ private
85
+ def create_post_fields(params)
86
+ return params if params.is_a? String
87
+
88
+ fields = []
89
+ params.each do |name, value|
90
+ value_string = value if value.is_a?(String)
91
+ value_string = value.join(',') if value.is_a?(Array)
92
+ value_string ||= value.to_s
93
+
94
+ fields << Curl::PostField.content(name.to_s,value_string)
95
+ end
96
+ return fields
97
+ end
98
+
99
+ def create_put_fields(params)
100
+ return params if params.is_a? String
101
+
102
+ params.inject([]) do |list, (k,v)|
103
+ v = v.is_a?(Array) ? v.join(',') : v
104
+ list << "#{k}=#{v}"
105
+ list
106
+ end.join('&')
107
+ end
108
+
109
+ def create_file_fields(filez)
110
+ fields = []
111
+ filez.each do |name, path|
112
+ fields << Curl::PostField.file(name, path)
113
+ end
114
+ fields
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,34 @@
1
+ module CurbFu
2
+ class Request
3
+ module Common
4
+ def timeout=(val)
5
+ @timeout = val
6
+ end
7
+
8
+ def timeout
9
+ @timeout.nil? ? 10 : @timeout
10
+ end
11
+
12
+ def build_url(url_params, query_params = {})
13
+ if url_params.is_a? String
14
+ built_url = url_params
15
+ else
16
+ built_url = "http://#{url_params[:host]}"
17
+ built_url += ":" + url_params[:port].to_s if url_params[:port]
18
+ built_url += url_params[:path] if url_params[:path]
19
+ end
20
+
21
+ # TODO: update for use with CurbFu::Entity
22
+ if query_params.is_a? String
23
+ built_url += query_params
24
+ elsif !query_params.empty?
25
+ built_url += "?"
26
+ built_url += query_params.collect do |name, value|
27
+ CurbFu::Request::Parameter.new(name, value).to_uri_param
28
+ end.join('&')
29
+ end
30
+ built_url
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,33 @@
1
+ module CurbFu
2
+ class Request
3
+ class Parameter
4
+ attr_accessor :name, :value
5
+
6
+ def initialize(name, value)
7
+ self.name = name
8
+ self.value = value
9
+ end
10
+
11
+ def self.build_uri_params(param_hash)
12
+ param_hash.to_param
13
+ end
14
+
15
+ def self.build_post_fields(param_hash)
16
+ param_hash.to_post_fields
17
+ end
18
+
19
+ def to_uri_param
20
+ value.to_param(name)
21
+ end
22
+
23
+ def to_curl_post_field
24
+ field_string = value.to_param(name)
25
+ fields = field_string.split('&').collect do |field_value_pair|
26
+ field_name, field_value = field_value_pair.split('=')
27
+ Curl::PostField.content(field_name, CGI::unescape(field_value))
28
+ end
29
+ fields.length == 1 ? fields[0] : fields
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,153 @@
1
+ require 'rack/test'
2
+
3
+ module CurbFu
4
+ class Request
5
+ module Test
6
+ include Common
7
+
8
+ def self.included(target)
9
+ target.extend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+ def get(url, params = {})
14
+ request_options = build_request_options(url)
15
+ params = hashify_params(params) if params.is_a?(String)
16
+ respond(request_options[:interface], :get, request_options[:url],
17
+ params, request_options[:headers], request_options[:username], request_options[:password])
18
+ end
19
+
20
+ def post(url, params = {})
21
+ request_options = build_request_options(url)
22
+ respond(request_options[:interface], :post, request_options[:url],
23
+ params, request_options[:headers], request_options[:username], request_options[:password])
24
+ end
25
+
26
+ def post_file(url, params = {}, filez = {})
27
+ request_options = build_request_options(url)
28
+ uploaded_files = filez.inject({}) do |hsh, (name, path)|
29
+ hsh[name] = Rack::Test::UploadedFile.new(path)
30
+ hsh
31
+ end
32
+ respond(request_options[:interface], :post, request_options[:url],
33
+ params.merge(uploaded_files), request_options[:headers], request_options[:username], request_options[:password])
34
+ end
35
+
36
+ def put(url, params = {})
37
+ request_options = build_request_options(url)
38
+ respond(request_options[:interface], :put, request_options[:url],
39
+ params, request_options[:headers], request_options[:username], request_options[:password])
40
+ end
41
+
42
+ def delete(url, params = {})
43
+ request_options = build_request_options(url)
44
+ params = hashify_params(params) if params.is_a?(String)
45
+ respond(request_options[:interface], :delete, request_options[:url],
46
+ params, request_options[:headers], request_options[:username], request_options[:password])
47
+ end
48
+
49
+ def hashify_params(param_string)
50
+ param_string.sub!(/^\?/,'')
51
+ param_string.split('&').inject({}) do |hsh, pair|
52
+ key, value = pair.split('=')
53
+
54
+ if key.match(/(.+)\[\]$/)
55
+ key = $1
56
+ hsh[key] ||= []
57
+ hsh[key] << value
58
+ elsif key.match(/([^\[]+)\[(.+)\]$/)
59
+ key = $1
60
+ subkey = $2
61
+ hsh[key] ||= {}
62
+ hsh[key].update( subkey => value )
63
+ else
64
+ hsh[key] = value
65
+ end
66
+
67
+ hsh
68
+ end
69
+ end
70
+
71
+ def build_request_options(url)
72
+ options = {}
73
+ options[:headers] = (url.is_a?(String)) ? nil : url.delete(:headers)
74
+ options[:url] = build_url(url)
75
+ options[:username], options[:password] = get_auth(url)
76
+ options[:interface] = get_interface(url)
77
+ options
78
+ end
79
+
80
+ def respond(interface, operation, url, params, headers, username = nil, password = nil)
81
+ if interface.nil?
82
+ raise Curl::Err::ConnectionFailedError
83
+ else
84
+ unless headers.nil?
85
+ process_headers(headers).each do |name, value|
86
+ interface.header(name, value)
87
+ end
88
+ end
89
+ interface.authorize(username, password) unless username.nil?
90
+ puts "sending #{operation} to #{url} with params #{params.inspect} using interface #{interface.inspect}" if CurbFu.debug?
91
+ begin
92
+ response = interface.send(operation, url, params, 'SERVER_NAME' => interface.hostname)
93
+ rescue => e
94
+ puts "Caught error: #{e}, #{e.backtrace.join("\n")}" if CurbFu.debug?
95
+ raise e
96
+ end
97
+ CurbFu::Response::Base.from_rack_response(response)
98
+ end
99
+ end
100
+
101
+ def process_headers(headers)
102
+ headers.inject({}) do |accum, (header_name, value)|
103
+ key = header_name.gsub("-", "_").upcase
104
+ key = "HTTP_" + key unless key =~ /^HTTP_/
105
+ accum[key] = value
106
+ accum
107
+ end
108
+ end
109
+
110
+ def get_interface(url)
111
+ if url.is_a?(Hash)
112
+ host = url[:host]
113
+ else
114
+ host = parse_hostname(url)
115
+ end
116
+ match_host(host)
117
+ end
118
+
119
+ def parse_hostname(uri)
120
+ parsed_hostname = URI.parse(uri)
121
+ parsed_hostname.host || parsed_hostname.path
122
+ end
123
+
124
+ def match_host(host)
125
+ match = CurbFu.stubs.find do |(hostname, interface)|
126
+ hostname == host
127
+ end
128
+ match.last unless match.nil?
129
+ end
130
+
131
+ def get_auth(url)
132
+ username = password = nil
133
+ if url.is_a?(Hash) && url[:username]
134
+ username = url[:username]
135
+ password = url[:password]
136
+ end
137
+ [username, password]
138
+ end
139
+ end
140
+
141
+ class Interface
142
+ include Rack::Test::Methods
143
+
144
+ attr_accessor :app, :hostname
145
+
146
+ def initialize(app, hostname = 'example.org')
147
+ self.app = app
148
+ self.hostname = hostname
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end