curb-fu 0.4.3

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.
@@ -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