rest 2.7.2 → 3.0.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.
@@ -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