rest 2.7.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,173 @@
1
+ module Rest
2
+ module InternalClient
3
+ # A class that can be instantiated for access to a RESTful resource,
4
+ # including authentication.
5
+ #
6
+ # Example:
7
+ #
8
+ # resource = InternalClient::Resource.new('http://some/resource')
9
+ # jpg = resource.get(:accept => 'image/jpg')
10
+ #
11
+ # With HTTP basic authentication:
12
+ #
13
+ # resource = InternalClient::Resource.new('http://protected/resource', :user => 'user', :password => 'password')
14
+ # resource.delete
15
+ #
16
+ # With a timeout (seconds):
17
+ #
18
+ # InternalClient::Resource.new('http://slow', :timeout => 10)
19
+ #
20
+ # With an open timeout (seconds):
21
+ #
22
+ # InternalClient::Resource.new('http://behindfirewall', :open_timeout => 10)
23
+ #
24
+ # You can also use resources to share common headers. For headers keys,
25
+ # symbols are converted to strings. Example:
26
+ #
27
+ # resource = InternalClient::Resource.new('http://some/resource', :headers => { :client_version => 1 })
28
+ #
29
+ # This header will be transported as X-Client-Version (notice the X prefix,
30
+ # capitalization and hyphens)
31
+ #
32
+ # Use the [] syntax to allocate subresources:
33
+ #
34
+ # site = InternalClient::Resource.new('http://example.com', :user => 'adam', :password => 'mypasswd')
35
+ # site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain'
36
+ #
37
+ class Resource
38
+ attr_reader :url, :options, :block
39
+
40
+ def initialize(url, options={}, backwards_compatibility=nil, &block)
41
+ @url = url
42
+ @block = block
43
+ if options.class == Hash
44
+ @options = options
45
+ else # compatibility with previous versions
46
+ @options = {:user => options, :password => backwards_compatibility}
47
+ end
48
+ end
49
+
50
+ def get(additional_headers={}, &block)
51
+ headers = (options[:headers] || {}).merge(additional_headers)
52
+ Request.execute(options.merge(
53
+ :method => :get,
54
+ :url => url,
55
+ :headers => headers), &(block || @block))
56
+ end
57
+
58
+ def head(additional_headers={}, &block)
59
+ headers = (options[:headers] || {}).merge(additional_headers)
60
+ Request.execute(options.merge(
61
+ :method => :head,
62
+ :url => url,
63
+ :headers => headers), &(block || @block))
64
+ end
65
+
66
+ def post(payload, additional_headers={}, &block)
67
+ headers = (options[:headers] || {}).merge(additional_headers)
68
+ Request.execute(options.merge(
69
+ :method => :post,
70
+ :url => url,
71
+ :payload => payload,
72
+ :headers => headers), &(block || @block))
73
+ end
74
+
75
+ def put(payload, additional_headers={}, &block)
76
+ headers = (options[:headers] || {}).merge(additional_headers)
77
+ Request.execute(options.merge(
78
+ :method => :put,
79
+ :url => url,
80
+ :payload => payload,
81
+ :headers => headers), &(block || @block))
82
+ end
83
+
84
+ def patch(payload, additional_headers={}, &block)
85
+ headers = (options[:headers] || {}).merge(additional_headers)
86
+ Request.execute(options.merge(
87
+ :method => :patch,
88
+ :url => url,
89
+ :payload => payload,
90
+ :headers => headers), &(block || @block))
91
+ end
92
+
93
+ def delete(additional_headers={}, &block)
94
+ headers = (options[:headers] || {}).merge(additional_headers)
95
+ Request.execute(options.merge(
96
+ :method => :delete,
97
+ :url => url,
98
+ :headers => headers), &(block || @block))
99
+ end
100
+
101
+ def to_s
102
+ url
103
+ end
104
+
105
+ def user
106
+ options[:user]
107
+ end
108
+
109
+ def password
110
+ options[:password]
111
+ end
112
+
113
+ def headers
114
+ options[:headers] || {}
115
+ end
116
+
117
+ def timeout
118
+ options[:timeout]
119
+ end
120
+
121
+ def open_timeout
122
+ options[:open_timeout]
123
+ end
124
+
125
+ # Construct a subresource, preserving authentication.
126
+ #
127
+ # Example:
128
+ #
129
+ # site = InternalClient::Resource.new('http://example.com', 'adam', 'mypasswd')
130
+ # site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain'
131
+ #
132
+ # This is especially useful if you wish to define your site in one place and
133
+ # call it in multiple locations:
134
+ #
135
+ # def orders
136
+ # InternalClient::Resource.new('http://example.com/orders', 'admin', 'mypasswd')
137
+ # end
138
+ #
139
+ # orders.get # GET http://example.com/orders
140
+ # orders['1'].get # GET http://example.com/orders/1
141
+ # orders['1/items'].delete # DELETE http://example.com/orders/1/items
142
+ #
143
+ # Nest resources as far as you want:
144
+ #
145
+ # site = InternalClient::Resource.new('http://example.com')
146
+ # posts = site['posts']
147
+ # first_post = posts['1']
148
+ # comments = first_post['comments']
149
+ # comments.post 'Hello', :content_type => 'text/plain'
150
+ #
151
+ def [](suburl, &new_block)
152
+ case
153
+ when block_given? then
154
+ self.class.new(concat_urls(url, suburl), options, &new_block)
155
+ when block then
156
+ self.class.new(concat_urls(url, suburl), options, &block)
157
+ else
158
+ self.class.new(concat_urls(url, suburl), options)
159
+ end
160
+ end
161
+
162
+ def concat_urls(url, suburl) # :nodoc:
163
+ url = url.to_s
164
+ suburl = suburl.to_s
165
+ if url.slice(-1, 1) == '/' or suburl.slice(0, 1) == '/'
166
+ url + suburl
167
+ else
168
+ "#{url}/#{suburl}"
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,28 @@
1
+ module Rest
2
+ module InternalClient
3
+
4
+ # A Response from InternalClient, you can access the response body, the code or the headers.
5
+ #
6
+ module Response
7
+
8
+ include AbstractResponse
9
+
10
+ attr_accessor :args, :net_http_res
11
+
12
+ attr_writer :body
13
+
14
+ def body
15
+ self
16
+ end
17
+
18
+ def Response.create body, net_http_res, args
19
+ result = body || ''
20
+ result.extend Response
21
+ result.net_http_res = net_http_res
22
+ result.args = args
23
+ result
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,177 @@
1
+ require 'uri'
2
+ require 'zlib'
3
+ require 'stringio'
4
+
5
+ begin
6
+ require 'net/https'
7
+ rescue LoadError => e
8
+ raise e unless RUBY_PLATFORM =~ /linux/
9
+ raise LoadError, "no such file to load -- net/https. Try running apt-get install libopenssl-ruby"
10
+ end
11
+
12
+ require File.dirname(__FILE__) + '/internal/exceptions'
13
+ require File.dirname(__FILE__) + '/internal/request'
14
+ require File.dirname(__FILE__) + '/internal/abstract_response'
15
+ require File.dirname(__FILE__) + '/internal/response'
16
+ require File.dirname(__FILE__) + '/internal/raw_response'
17
+ require File.dirname(__FILE__) + '/internal/resource'
18
+ require File.dirname(__FILE__) + '/internal/payload'
19
+ require File.dirname(__FILE__) + '/internal/net_http_ext'
20
+ require File.dirname(__FILE__) + '/internal/mimes'
21
+
22
+ # This module's static methods are the entry point for using the REST client.
23
+ #
24
+ # # GET
25
+ # xml = InternalClient.get 'http://example.com/resource'
26
+ # jpg = InternalClient.get 'http://example.com/resource', :accept => 'image/jpg'
27
+ #
28
+ # # authentication and SSL
29
+ # InternalClient.get 'https://user:password@example.com/private/resource'
30
+ #
31
+ # # POST or PUT with a hash sends parameters as a urlencoded form body
32
+ # InternalClient.post 'http://example.com/resource', :param1 => 'one'
33
+ #
34
+ # # nest hash parameters
35
+ # InternalClient.post 'http://example.com/resource', :nested => { :param1 => 'one' }
36
+ #
37
+ # # POST and PUT with raw payloads
38
+ # InternalClient.post 'http://example.com/resource', 'the post body', :content_type => 'text/plain'
39
+ # InternalClient.post 'http://example.com/resource.xml', xml_doc
40
+ # InternalClient.put 'http://example.com/resource.pdf', File.read('my.pdf'), :content_type => 'application/pdf'
41
+ #
42
+ # # DELETE
43
+ # InternalClient.delete 'http://example.com/resource'
44
+ #
45
+ # # retreive the response http code and headers
46
+ # res = InternalClient.get 'http://example.com/some.jpg'
47
+ # res.code # => 200
48
+ # res.headers[:content_type] # => 'image/jpg'
49
+ #
50
+ # # HEAD
51
+ # InternalClient.head('http://example.com').headers
52
+ #
53
+ # To use with a proxy, just set InternalClient.proxy to the proper http proxy:
54
+ #
55
+ # InternalClient.proxy = "http://proxy.example.com/"
56
+ #
57
+ # Or inherit the proxy from the environment:
58
+ #
59
+ # InternalClient.proxy = ENV['http_proxy']
60
+ #
61
+ # For live tests of InternalClient, try using http://rest-test.heroku.com, which echoes back information about the rest call:
62
+ #
63
+ # >> InternalClient.put 'http://rest-test.heroku.com/resource', :foo => 'baz'
64
+ # => "PUT http://rest-test.heroku.com/resource with a 7 byte payload, content type application/x-www-form-urlencoded {\"foo\"=>\"baz\"}"
65
+ #
66
+ module Rest
67
+ module InternalClient
68
+
69
+ def self.get(url, headers={}, &block)
70
+ Request.execute(:method => :get, :url => url, :headers => headers, &block)
71
+ end
72
+
73
+ def self.post(url, payload, headers={}, &block)
74
+ Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers, &block)
75
+ end
76
+
77
+ def self.patch(url, payload, headers={}, &block)
78
+ Request.execute(:method => :patch, :url => url, :payload => payload, :headers => headers, &block)
79
+ end
80
+
81
+ def self.put(url, payload, headers={}, &block)
82
+ Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers, &block)
83
+ end
84
+
85
+ def self.delete(url, headers={}, &block)
86
+ Request.execute(:method => :delete, :url => url, :headers => headers, &block)
87
+ end
88
+
89
+ def self.head(url, headers={}, &block)
90
+ Request.execute(:method => :head, :url => url, :headers => headers, &block)
91
+ end
92
+
93
+ def self.options(url, headers={}, &block)
94
+ Request.execute(:method => :options, :url => url, :headers => headers, &block)
95
+ end
96
+
97
+ class << self
98
+ attr_accessor :proxy
99
+ end
100
+
101
+ # Setup the log for InternalClient calls.
102
+ # Value should be a logger but can can be stdout, stderr, or a filename.
103
+ # You can also configure logging by the environment variable RESTCLIENT_LOG.
104
+ def self.log= log
105
+ @@log = create_log log
106
+ end
107
+
108
+ def self.version
109
+ version_path = File.dirname(__FILE__) + "/../VERSION"
110
+ return File.read(version_path).chomp if File.file?(version_path)
111
+ "0.0.0"
112
+ end
113
+
114
+ # Create a log that respond to << like a logger
115
+ # param can be 'stdout', 'stderr', a string (then we will log to that file) or a logger (then we return it)
116
+ def self.create_log param
117
+ if param
118
+ if param.is_a? String
119
+ if param == 'stdout'
120
+ stdout_logger = Class.new do
121
+ def << obj
122
+ STDOUT.puts obj
123
+ end
124
+ end
125
+ stdout_logger.new
126
+ elsif param == 'stderr'
127
+ stderr_logger = Class.new do
128
+ def << obj
129
+ STDERR.puts obj
130
+ end
131
+ end
132
+ stderr_logger.new
133
+ else
134
+ file_logger = Class.new do
135
+ attr_writer :target_file
136
+
137
+ def << obj
138
+ File.open(@target_file, 'a') { |f| f.puts obj }
139
+ end
140
+ end
141
+ logger = file_logger.new
142
+ logger.target_file = param
143
+ logger
144
+ end
145
+ else
146
+ param
147
+ end
148
+ end
149
+ end
150
+
151
+ @@env_log = create_log ENV['RESTCLIENT_LOG']
152
+
153
+ @@log = nil
154
+
155
+ def self.log # :nodoc:
156
+ @@env_log || @@log
157
+ end
158
+
159
+ @@before_execution_procs = []
160
+
161
+ # Add a Proc to be called before each request in executed.
162
+ # The proc parameters will be the http request and the request params.
163
+ def self.add_before_execution_proc &proc
164
+ @@before_execution_procs << proc
165
+ end
166
+
167
+ # Reset the procs to be called before each request is executed.
168
+ def self.reset_before_execution_procs
169
+ @@before_execution_procs = []
170
+ end
171
+
172
+ def self.before_execution_procs # :nodoc:
173
+ @@before_execution_procs
174
+ end
175
+
176
+ end
177
+ end
@@ -0,0 +1,127 @@
1
+ require_relative 'internal_client/internal_client'
2
+
3
+ module Rest
4
+
5
+ module Wrappers
6
+ class InternalClientExceptionWrapper < HttpError
7
+ attr_reader :ex
8
+
9
+ def initialize(ex)
10
+ super(ex.response, ex.http_code)
11
+ @ex = ex
12
+ end
13
+ end
14
+
15
+ class InternalClientResponseWrapper < BaseResponseWrapper
16
+ def initialize(response)
17
+ @response = response
18
+ end
19
+
20
+ def code
21
+ @response.code
22
+ end
23
+
24
+ def body
25
+ @response.body
26
+ end
27
+
28
+ def headers_orig
29
+ @response.headers
30
+ end
31
+
32
+ end
33
+
34
+ class InternalClientWrapper < BaseWrapper
35
+
36
+ def default_headers
37
+ {}
38
+ end
39
+
40
+ def get(url, req_hash={})
41
+ response = nil
42
+ begin
43
+ req_hash[:method] = :get
44
+ req_hash[:url] = url
45
+ req_hash[:headers] ||= default_headers
46
+ req_hash[:headers][:params] = req_hash[:params] if req_hash[:params]
47
+ #p req_hash
48
+ r2 = Rest::InternalClient::Request.execute(req_hash)
49
+ response = InternalClientResponseWrapper.new(r2)
50
+ rescue Rest::InternalClient::Exception => ex
51
+ #p ex
52
+ #if ex.http_code == 404
53
+ # return InternalClientResponseWrapper.new(ex.response)
54
+ #end
55
+ raise InternalClientExceptionWrapper.new(ex)
56
+ end
57
+ response
58
+ end
59
+
60
+ def post(url, req_hash={})
61
+ response = nil
62
+ begin
63
+ req_hash[:method] = :post
64
+ req_hash[:url] = url
65
+ b = req_hash[:body]
66
+ if b
67
+ if b.is_a?(Hash)
68
+ b = b.to_json
69
+ end
70
+ req_hash[:payload] = b
71
+ end
72
+ r2 = Rest::InternalClient::Request.execute(req_hash)
73
+ response = InternalClientResponseWrapper.new(r2)
74
+ rescue Rest::InternalClient::Exception => ex
75
+ raise InternalClientExceptionWrapper.new(ex)
76
+ end
77
+ response
78
+ end
79
+
80
+ def put(url, req_hash={})
81
+ response = nil
82
+ begin
83
+ req_hash[:method] = :put
84
+ req_hash[:url] = url
85
+ req_hash[:payload] = req_hash[:body] if req_hash[:body]
86
+ r2 = Rest::InternalClient::Request.execute(req_hash)
87
+ response = InternalClientResponseWrapper.new(r2)
88
+ rescue Rest::InternalClient::Exception => ex
89
+ raise InternalClientExceptionWrapper.new(ex)
90
+ end
91
+ response
92
+ end
93
+
94
+ def patch(url, req_hash={})
95
+ response = nil
96
+ begin
97
+ req_hash[:method] = :patch
98
+ req_hash[:url] = url
99
+ req_hash[:payload] = req_hash[:body] if req_hash[:body]
100
+ r2 = Rest::InternalClient::Request.execute(req_hash)
101
+ response = InternalClientResponseWrapper.new(r2)
102
+ rescue Rest::InternalClient::Exception => ex
103
+ raise InternalClientExceptionWrapper.new(ex)
104
+ end
105
+ response
106
+ end
107
+
108
+
109
+ def delete(url, req_hash={})
110
+ response = nil
111
+ begin
112
+ req_hash[:method] = :delete
113
+ req_hash[:url] = url
114
+ req_hash[:payload] = req_hash[:body] if req_hash[:body]
115
+ r2 = Rest::InternalClient::Request.execute(req_hash)
116
+ response = InternalClientResponseWrapper.new(r2)
117
+ # todo: make generic exception
118
+ rescue Rest::InternalClient::Exception => ex
119
+ raise InternalClientExceptionWrapper.new(ex)
120
+ end
121
+ response
122
+ end
123
+ end
124
+
125
+ end
126
+
127
+ end