rest-client 1.5.1 → 1.6.0.a
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.
Potentially problematic release.
This version of rest-client might be problematic. Click here for more details.
- data/README.rdoc +13 -11
- data/VERSION +1 -1
- data/history.md +12 -0
- data/lib/rest-client.rb +2 -0
- data/lib/restclient.rb +0 -3
- data/lib/restclient/abstract_response.rb +14 -9
- data/lib/restclient/exceptions.rb +28 -6
- data/lib/restclient/payload.rb +33 -9
- data/lib/restclient/request.rb +42 -15
- data/spec/abstract_response_spec.rb +6 -1
- data/spec/payload_spec.rb +51 -0
- data/spec/request2_spec.rb +17 -0
- data/spec/request_spec.rb +2 -2
- data/spec/resource_spec.rb +10 -10
- data/spec/response_spec.rb +24 -5
- metadata +10 -6
data/README.rdoc
CHANGED
@@ -13,7 +13,9 @@ of specifying actions: get, put, post, delete.
|
|
13
13
|
|
14
14
|
RestClient.get 'http://example.com/resource'
|
15
15
|
|
16
|
-
RestClient.get '
|
16
|
+
RestClient.get 'http://example.com/resource', {:params => {:id => 50, 'foo' => 'bar'}}
|
17
|
+
|
18
|
+
RestClient.get 'https://user:password@example.com/private/resource', {:accept => :json}
|
17
19
|
|
18
20
|
RestClient.post 'http://example.com/resource', :param1 => 'one', :nested => { :param2 => 'two' }
|
19
21
|
|
@@ -77,8 +79,8 @@ See RestClient::Resource docs for details.
|
|
77
79
|
|
78
80
|
== Exceptions (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html)
|
79
81
|
|
80
|
-
* for results code between 200 and
|
81
|
-
* for results code 301
|
82
|
+
* for results code between 200 and 207 a RestClient::Response will be returned
|
83
|
+
* for results code 301, 302 or 307 the redirection will be followed if the request is a get or a head
|
82
84
|
* for result code 303 the redirection will be followed and the request transformed into a get
|
83
85
|
* for other cases a RestClient::Exception holding the Response will be raised, a specific exception class will be thrown for know error codes
|
84
86
|
|
@@ -98,11 +100,11 @@ A block can be passed to the RestClient method, this block will then be called w
|
|
98
100
|
Response.return! can be called to invoke the default response's behavior.
|
99
101
|
|
100
102
|
# Don't raise exceptions but return the response
|
101
|
-
RestClient.get('http://example.com/resource'){|response| response }
|
103
|
+
RestClient.get('http://example.com/resource'){|response, request| response }
|
102
104
|
➔ 404 Resource Not Found | text/html 282 bytes
|
103
105
|
|
104
106
|
# Manage a specific error code
|
105
|
-
RestClient.get('http://my-rest-service.com/resource'){ |response, &block|
|
107
|
+
RestClient.get('http://my-rest-service.com/resource'){ |response, request, &block|
|
106
108
|
case response.code
|
107
109
|
when 200
|
108
110
|
p "It worked !"
|
@@ -110,19 +112,19 @@ Response.return! can be called to invoke the default response's behavior.
|
|
110
112
|
when 423
|
111
113
|
raise SomeCustomExceptionIfYouWant
|
112
114
|
else
|
113
|
-
response.return! &block
|
115
|
+
response.return!(request, &block)
|
114
116
|
end
|
115
117
|
}
|
116
118
|
|
117
119
|
# Follow redirections for all request types and not only for get and head
|
118
|
-
# RFC : "If the 301
|
120
|
+
# RFC : "If the 301, 302 or 307 status code is received in response to a request other than GET or HEAD,
|
119
121
|
# the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user,
|
120
122
|
# since this might change the conditions under which the request was issued."
|
121
|
-
RestClient.get('http://my-rest-service.com/resource'){ |response, &block|
|
122
|
-
if [301, 302].include? response.code
|
123
|
-
response.follow_redirection &block
|
123
|
+
RestClient.get('http://my-rest-service.com/resource'){ |response, request, &block|
|
124
|
+
if [301, 302, 307].include? response.code
|
125
|
+
response.follow_redirection(request, &block)
|
124
126
|
else
|
125
|
-
response.return! &block
|
127
|
+
response.return!(request, &block)
|
126
128
|
end
|
127
129
|
}
|
128
130
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.6.0.a
|
data/history.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# 1.6.0
|
2
|
+
|
3
|
+
- forgot to include rest-client.rb in the gem
|
4
|
+
- user, password and user-defined headers should survive a redirect
|
5
|
+
- added all missing status codes
|
6
|
+
- added parameter passing for get request using the :param key in header
|
7
|
+
- the warning about the logger when using a string was a bad idea
|
8
|
+
- multipart parameters names should not be escaped
|
9
|
+
- remove the cookie escaping introduced by migrating to CGI cookie parsing in 1.5.1
|
10
|
+
- add a streamed payload type (patch provided by Caleb Land)
|
11
|
+
- Exception#http_body works even when no response
|
12
|
+
|
1
13
|
# 1.5.1
|
2
14
|
|
3
15
|
- only converts headers keys which are Symbols
|
data/lib/rest-client.rb
ADDED
data/lib/restclient.rb
CHANGED
@@ -92,9 +92,6 @@ module RestClient
|
|
92
92
|
# Value should be a logger but can can be stdout, stderr, or a filename.
|
93
93
|
# You can also configure logging by the environment variable RESTCLIENT_LOG.
|
94
94
|
def self.log= log
|
95
|
-
if log.is_a? String
|
96
|
-
warn "[warning] You should set the log with a logger"
|
97
|
-
end
|
98
95
|
@@log = create_log log
|
99
96
|
end
|
100
97
|
|
@@ -27,7 +27,7 @@ module RestClient
|
|
27
27
|
@cookies ||= (self.headers[:set_cookie] || {}).inject({}) do |out, cookie_content|
|
28
28
|
CGI::Cookie::parse(cookie_content).each do |key, cookie|
|
29
29
|
unless ['expires', 'path'].include? key
|
30
|
-
out[key] = cookie.value[0] || ''
|
30
|
+
out[CGI::escape(key)] = cookie.value[0] ? (CGI::escape(cookie.value[0]) || '') : ''
|
31
31
|
end
|
32
32
|
end
|
33
33
|
out
|
@@ -35,20 +35,20 @@ module RestClient
|
|
35
35
|
end
|
36
36
|
|
37
37
|
# Return the default behavior corresponding to the response code:
|
38
|
-
# the response itself for code in 200..206, redirection for 301 and
|
39
|
-
def return! &block
|
40
|
-
if (200..
|
38
|
+
# the response itself for code in 200..206, redirection for 301, 302 and 307 in get and head cases, redirection for 303 and an exception in other cases
|
39
|
+
def return! request = nil, &block
|
40
|
+
if (200..207).include? code
|
41
41
|
self
|
42
|
-
elsif [301, 302].include? code
|
42
|
+
elsif [301, 302, 307].include? code
|
43
43
|
unless [:get, :head].include? args[:method]
|
44
44
|
raise Exceptions::EXCEPTIONS_MAP[code], self
|
45
45
|
else
|
46
|
-
follow_redirection(&block)
|
46
|
+
follow_redirection(request, &block)
|
47
47
|
end
|
48
48
|
elsif code == 303
|
49
49
|
args[:method] = :get
|
50
50
|
args.delete :payload
|
51
|
-
follow_redirection(&block)
|
51
|
+
follow_redirection(request, &block)
|
52
52
|
elsif Exceptions::EXCEPTIONS_MAP[code]
|
53
53
|
raise Exceptions::EXCEPTIONS_MAP[code], self
|
54
54
|
else
|
@@ -65,18 +65,23 @@ module RestClient
|
|
65
65
|
end
|
66
66
|
|
67
67
|
# Follow a redirection
|
68
|
-
def follow_redirection &block
|
68
|
+
def follow_redirection request = nil, &block
|
69
69
|
url = headers[:location]
|
70
70
|
if url !~ /^http/
|
71
71
|
url = URI.parse(args[:url]).merge(url).to_s
|
72
72
|
end
|
73
73
|
args[:url] = url
|
74
|
+
if request
|
75
|
+
args[:password] = request.password
|
76
|
+
args[:user] = request.user
|
77
|
+
args[:headers] = request.headers
|
78
|
+
end
|
74
79
|
Request.execute args, &block
|
75
80
|
end
|
76
81
|
|
77
82
|
def AbstractResponse.beautify_headers(headers)
|
78
83
|
headers.inject({}) do |out, (key, value)|
|
79
|
-
out[key.gsub(/-/, '_').downcase.to_sym] = %w{set-cookie}.include?(key.downcase) ? value : value.first
|
84
|
+
out[key.gsub(/-/, '_').downcase.to_sym] = %w{ set-cookie }.include?(key.downcase) ? value : value.first
|
80
85
|
out
|
81
86
|
end
|
82
87
|
end
|
@@ -2,21 +2,29 @@ module RestClient
|
|
2
2
|
|
3
3
|
STATUSES = {100 => 'Continue',
|
4
4
|
101 => 'Switching Protocols',
|
5
|
+
102 => 'Processing', #WebDAV
|
6
|
+
|
5
7
|
200 => 'OK',
|
6
8
|
201 => 'Created',
|
7
9
|
202 => 'Accepted',
|
8
|
-
203 => 'Non-Authoritative Information',
|
10
|
+
203 => 'Non-Authoritative Information', # http/1.1
|
9
11
|
204 => 'No Content',
|
10
12
|
205 => 'Reset Content',
|
11
13
|
206 => 'Partial Content',
|
14
|
+
207 => 'Multi-Status', #WebDAV
|
15
|
+
|
12
16
|
300 => 'Multiple Choices',
|
13
17
|
301 => 'Moved Permanently',
|
14
18
|
302 => 'Found',
|
15
|
-
303 => 'See Other',
|
19
|
+
303 => 'See Other', # http/1.1
|
16
20
|
304 => 'Not Modified',
|
17
|
-
305 => 'Use Proxy',
|
21
|
+
305 => 'Use Proxy', # http/1.1
|
22
|
+
306 => 'Switch Proxy', # no longer used
|
23
|
+
307 => 'Temporary Redirect', # http/1.1
|
24
|
+
|
18
25
|
400 => 'Bad Request',
|
19
26
|
401 => 'Unauthorized',
|
27
|
+
402 => 'Payment Required',
|
20
28
|
403 => 'Forbidden',
|
21
29
|
404 => 'Resource Not Found',
|
22
30
|
405 => 'Method Not Allowed',
|
@@ -32,12 +40,26 @@ module RestClient
|
|
32
40
|
415 => 'Unsupported Media Type',
|
33
41
|
416 => 'Requested Range Not Satisfiable',
|
34
42
|
417 => 'Expectation Failed',
|
43
|
+
418 => 'I\'m A Teapot',
|
44
|
+
421 => 'Too Many Connections From This IP',
|
45
|
+
422 => 'Unprocessable Entity', #WebDAV
|
46
|
+
423 => 'Locked', #WebDAV
|
47
|
+
424 => 'Failed Dependency', #WebDAV
|
48
|
+
425 => 'Unordered Collection', #WebDAV
|
49
|
+
426 => 'Upgrade Required',
|
50
|
+
449 => 'Retry With', #Microsoft
|
51
|
+
450 => 'Blocked By Windows Parental Controls', #Microsoft
|
52
|
+
|
35
53
|
500 => 'Internal Server Error',
|
36
54
|
501 => 'Not Implemented',
|
37
55
|
502 => 'Bad Gateway',
|
38
56
|
503 => 'Service Unavailable',
|
39
57
|
504 => 'Gateway Timeout',
|
40
|
-
505 => 'HTTP Version Not Supported'
|
58
|
+
505 => 'HTTP Version Not Supported',
|
59
|
+
506 => 'Variant Also Negotiates',
|
60
|
+
507 => 'Insufficient Storage', #WebDAV
|
61
|
+
509 => 'Bandwidth Limit Exceeded', #Apache
|
62
|
+
510 => 'Not Extended'}
|
41
63
|
|
42
64
|
# Compatibility : make the Response act like a Net::HTTPResponse when needed
|
43
65
|
module ResponseForException
|
@@ -73,7 +95,7 @@ module RestClient
|
|
73
95
|
end
|
74
96
|
|
75
97
|
def http_body
|
76
|
-
@response.body
|
98
|
+
@response.body if @response
|
77
99
|
end
|
78
100
|
|
79
101
|
def inspect
|
@@ -111,7 +133,7 @@ module RestClient
|
|
111
133
|
klass = Class.new(superclass) do
|
112
134
|
send(:define_method, :message) {message}
|
113
135
|
end
|
114
|
-
klass_constant = const_set message.
|
136
|
+
klass_constant = const_set message.delete(' \-\''), klass
|
115
137
|
Exceptions::EXCEPTIONS_MAP[code] = klass_constant
|
116
138
|
end
|
117
139
|
|
data/lib/restclient/payload.rb
CHANGED
@@ -9,6 +9,8 @@ module RestClient
|
|
9
9
|
def generate(params)
|
10
10
|
if params.is_a?(String)
|
11
11
|
Base.new(params)
|
12
|
+
elsif params.respond_to?(:read)
|
13
|
+
Streamed.new(params)
|
12
14
|
elsif params
|
13
15
|
if params.delete(:multipart) == true || has_file?(params)
|
14
16
|
Multipart.new(params)
|
@@ -47,16 +49,12 @@ module RestClient
|
|
47
49
|
|
48
50
|
alias :to_s :read
|
49
51
|
|
50
|
-
def escape(v)
|
51
|
-
URI.escape(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
52
|
-
end
|
53
|
-
|
54
52
|
# Flatten parameters by converting hashes of hashes to flat hashes
|
55
53
|
# {keys1 => {keys2 => value}} will be transformed into [keys1[key2], value]
|
56
54
|
def flatten_params(params, parent_key = nil)
|
57
55
|
result = []
|
58
56
|
params.each do |key, value|
|
59
|
-
calculated_key = parent_key ? "#{parent_key}[#{
|
57
|
+
calculated_key = parent_key ? "#{parent_key}[#{handle_key(key)}]" : handle_key(key)
|
60
58
|
if value.is_a? Hash
|
61
59
|
result += flatten_params(value, calculated_key)
|
62
60
|
elsif value.is_a? Array
|
@@ -83,7 +81,7 @@ module RestClient
|
|
83
81
|
end
|
84
82
|
|
85
83
|
def headers
|
86
|
-
{
|
84
|
+
{'Content-Length' => size.to_s}
|
87
85
|
end
|
88
86
|
|
89
87
|
def size
|
@@ -108,16 +106,37 @@ module RestClient
|
|
108
106
|
|
109
107
|
end
|
110
108
|
|
109
|
+
class Streamed < Base
|
110
|
+
def build_stream(params = nil)
|
111
|
+
@stream = params
|
112
|
+
end
|
113
|
+
|
114
|
+
def size
|
115
|
+
if @stream.respond_to?(:size)
|
116
|
+
@stream.size
|
117
|
+
elsif @stream.is_a?(IO)
|
118
|
+
@stream.stat.size
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
alias :length :size
|
123
|
+
end
|
124
|
+
|
111
125
|
class UrlEncoded < Base
|
112
126
|
def build_stream(params = nil)
|
113
127
|
@stream = StringIO.new(flatten_params(params).collect do |entry|
|
114
|
-
"#{entry[0]}=#{
|
128
|
+
"#{entry[0]}=#{handle_key(entry[1])}"
|
115
129
|
end.join("&"))
|
116
130
|
@stream.seek(0)
|
117
131
|
end
|
118
132
|
|
133
|
+
# for UrlEncoded escape the keys
|
134
|
+
def handle_key key
|
135
|
+
URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
136
|
+
end
|
137
|
+
|
119
138
|
def headers
|
120
|
-
super.merge({
|
139
|
+
super.merge({'Content-Type' => 'application/x-www-form-urlencoded'})
|
121
140
|
end
|
122
141
|
end
|
123
142
|
|
@@ -139,7 +158,7 @@ module RestClient
|
|
139
158
|
|
140
159
|
last_index = x.length - 1
|
141
160
|
x.each_with_index do |a, index|
|
142
|
-
k, v = *a
|
161
|
+
k, v = * a
|
143
162
|
if v.respond_to?(:read) && v.respond_to?(:path)
|
144
163
|
create_file_field(@stream, k, v)
|
145
164
|
else
|
@@ -184,6 +203,11 @@ module RestClient
|
|
184
203
|
@boundary ||= rand(1_000_000).to_s
|
185
204
|
end
|
186
205
|
|
206
|
+
# for Multipart do not escape the keys
|
207
|
+
def handle_key key
|
208
|
+
key
|
209
|
+
end
|
210
|
+
|
187
211
|
def headers
|
188
212
|
super.merge({'Content-Type' => %Q{multipart/form-data; boundary=#{boundary}}})
|
189
213
|
end
|
data/lib/restclient/request.rb
CHANGED
@@ -27,14 +27,18 @@ module RestClient
|
|
27
27
|
:open_timeout, :raw_response, :verify_ssl, :ssl_client_cert,
|
28
28
|
:ssl_client_key, :ssl_ca_file, :processed_headers, :args
|
29
29
|
|
30
|
-
def self.execute(args, &block)
|
31
|
-
new(args).execute(&block)
|
30
|
+
def self.execute(args, & block)
|
31
|
+
new(args).execute(& block)
|
32
32
|
end
|
33
33
|
|
34
34
|
def initialize args
|
35
35
|
@method = args[:method] or raise ArgumentError, "must pass :method"
|
36
|
-
@url = args[:url] or raise ArgumentError, "must pass :url"
|
37
36
|
@headers = args[:headers] || {}
|
37
|
+
if args[:url]
|
38
|
+
@url = process_get_params(args[:url], headers)
|
39
|
+
else
|
40
|
+
raise ArgumentError, "must pass :url"
|
41
|
+
end
|
38
42
|
@cookies = @headers.delete(:cookies) || args[:cookies] || {}
|
39
43
|
@payload = Payload.generate(args[:payload])
|
40
44
|
@user = args[:user]
|
@@ -51,14 +55,37 @@ module RestClient
|
|
51
55
|
@args = args
|
52
56
|
end
|
53
57
|
|
54
|
-
def execute &block
|
58
|
+
def execute & block
|
55
59
|
uri = parse_url_with_auth(url)
|
56
|
-
transmit uri, net_http_request_class(method).new(uri.request_uri, processed_headers), payload, &block
|
60
|
+
transmit uri, net_http_request_class(method).new(uri.request_uri, processed_headers), payload, & block
|
61
|
+
end
|
62
|
+
|
63
|
+
# Extract the query parameters for get request and append them to the url
|
64
|
+
def process_get_params url, headers
|
65
|
+
if method == :get
|
66
|
+
get_params = {}
|
67
|
+
headers.delete_if do |key, value|
|
68
|
+
if 'params' == key.to_s.downcase && value.is_a?(Hash)
|
69
|
+
get_params.merge! value
|
70
|
+
true
|
71
|
+
else
|
72
|
+
false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
unless get_params.empty?
|
76
|
+
query_string = get_params.collect { |k, v| "#{k.to_s}=#{CGI::escape(v.to_s)}" }.join('&')
|
77
|
+
url + "?#{query_string}"
|
78
|
+
else
|
79
|
+
url
|
80
|
+
end
|
81
|
+
else
|
82
|
+
url
|
83
|
+
end
|
57
84
|
end
|
58
85
|
|
59
86
|
def make_headers user_headers
|
60
87
|
unless @cookies.empty?
|
61
|
-
user_headers[:cookie] = @cookies.map {|(key, val)| "#{key.to_s}=#{val}" }.sort.join(';')
|
88
|
+
user_headers[:cookie] = @cookies.map { |(key, val)| "#{key.to_s}=#{CGI::unescape(val)}" }.sort.join(';')
|
62
89
|
end
|
63
90
|
headers = stringify_headers(default_headers).merge(stringify_headers(user_headers))
|
64
91
|
headers.merge!(@payload.headers) if @payload
|
@@ -107,7 +134,7 @@ module RestClient
|
|
107
134
|
end
|
108
135
|
end
|
109
136
|
|
110
|
-
def transmit uri, req, payload, &block
|
137
|
+
def transmit uri, req, payload, & block
|
111
138
|
setup_credentials req
|
112
139
|
|
113
140
|
net = net_http_class.new(uri.host, uri.port)
|
@@ -139,7 +166,7 @@ module RestClient
|
|
139
166
|
net.start do |http|
|
140
167
|
res = http.request(req, payload) { |http_response| fetch_body(http_response) }
|
141
168
|
log_response res
|
142
|
-
process_result res, &block
|
169
|
+
process_result res, & block
|
143
170
|
end
|
144
171
|
rescue EOFError
|
145
172
|
raise RestClient::ServerBrokeConnection
|
@@ -179,7 +206,7 @@ module RestClient
|
|
179
206
|
http_response
|
180
207
|
end
|
181
208
|
|
182
|
-
def process_result res, &block
|
209
|
+
def process_result res, & block
|
183
210
|
if @raw_response
|
184
211
|
# We don't decode raw requests
|
185
212
|
response = RawResponse.new(@tf, res, args)
|
@@ -188,9 +215,9 @@ module RestClient
|
|
188
215
|
end
|
189
216
|
|
190
217
|
if block_given?
|
191
|
-
block.call
|
218
|
+
block.call(response, self, & block)
|
192
219
|
else
|
193
|
-
response.return!(&block)
|
220
|
+
response.return!(self, & block)
|
194
221
|
end
|
195
222
|
|
196
223
|
end
|
@@ -212,7 +239,7 @@ module RestClient
|
|
212
239
|
out = []
|
213
240
|
out << "RestClient.#{method} #{url.inspect}"
|
214
241
|
out << payload.short_inspect if payload
|
215
|
-
out << processed_headers.to_a.sort.map{|(k,v)| [k.inspect, v.inspect].join("=>")}.join(", ")
|
242
|
+
out << processed_headers.to_a.sort.map { |(k, v)| [k.inspect, v.inspect].join("=>") }.join(", ")
|
216
243
|
RestClient.log << out.join(', ') + "\n"
|
217
244
|
end
|
218
245
|
end
|
@@ -228,7 +255,7 @@ module RestClient
|
|
228
255
|
def stringify_headers headers
|
229
256
|
headers.inject({}) do |result, (key, value)|
|
230
257
|
if key.is_a? Symbol
|
231
|
-
key = key.to_s.split(/_/).map{|w| w.capitalize}.join('-')
|
258
|
+
key = key.to_s.split(/_/).map { |w| w.capitalize }.join('-')
|
232
259
|
end
|
233
260
|
if 'CONTENT-TYPE' == key.upcase
|
234
261
|
target_value = value.to_s
|
@@ -240,7 +267,7 @@ module RestClient
|
|
240
267
|
else
|
241
268
|
target_values = value.to_s.split ','
|
242
269
|
end
|
243
|
-
result[key] = target_values.map{ |ext| MIME::Types.type_for_extension(ext.to_s.strip)}.join(', ')
|
270
|
+
result[key] = target_values.map { |ext| MIME::Types.type_for_extension(ext.to_s.strip) }.join(', ')
|
244
271
|
else
|
245
272
|
result[key] = value.to_s
|
246
273
|
end
|
@@ -249,7 +276,7 @@ module RestClient
|
|
249
276
|
end
|
250
277
|
|
251
278
|
def default_headers
|
252
|
-
{
|
279
|
+
{:accept => '*/*; q=0.5, application/xml', :accept_encoding => 'gzip, deflate'}
|
253
280
|
end
|
254
281
|
|
255
282
|
end
|
@@ -53,7 +53,12 @@ describe RestClient::AbstractResponse do
|
|
53
53
|
|
54
54
|
it "extract strange cookies" do
|
55
55
|
@net_http_res.should_receive(:to_hash).and_return('set-cookie' => ['session_id=ZJ/HQVH6YE+rVkTpn0zvTQ==; path=/'])
|
56
|
-
@response.cookies.should == { 'session_id' => 'ZJ
|
56
|
+
@response.cookies.should == { 'session_id' => 'ZJ%2FHQVH6YE+rVkTpn0zvTQ%3D%3D' }
|
57
|
+
end
|
58
|
+
|
59
|
+
it "doesn't escape cookies" do
|
60
|
+
@net_http_res.should_receive(:to_hash).and_return('set-cookie' => ['session_id=BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca; path=/'])
|
61
|
+
@response.cookies.should == { 'session_id' => 'BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca' }
|
57
62
|
end
|
58
63
|
|
59
64
|
it "can access the net http result directly" do
|
data/spec/payload_spec.rb
CHANGED
@@ -14,6 +14,11 @@ describe RestClient::Payload do
|
|
14
14
|
RestClient::Payload::UrlEncoded.new({:foo => 'bar', :baz => 'qux'}).to_s)
|
15
15
|
end
|
16
16
|
|
17
|
+
it "should escape parameters" do
|
18
|
+
RestClient::Payload::UrlEncoded.new({'foo ' => 'bar'}).to_s.
|
19
|
+
should == "foo%20=bar"
|
20
|
+
end
|
21
|
+
|
17
22
|
it "should properly handle hashes as parameter" do
|
18
23
|
RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz' }}).to_s.
|
19
24
|
should == "foo[bar]=baz"
|
@@ -74,6 +79,17 @@ bar\r
|
|
74
79
|
EOS
|
75
80
|
end
|
76
81
|
|
82
|
+
it "should not escape parameters names" do
|
83
|
+
m = RestClient::Payload::Multipart.new([["bar ", "baz"]])
|
84
|
+
m.to_s.should == <<-EOS
|
85
|
+
--#{m.boundary}\r
|
86
|
+
Content-Disposition: form-data; name="bar "\r
|
87
|
+
\r
|
88
|
+
baz\r
|
89
|
+
--#{m.boundary}--\r
|
90
|
+
EOS
|
91
|
+
end
|
92
|
+
|
77
93
|
it "should form properly separated multipart data" do
|
78
94
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
79
95
|
m = RestClient::Payload::Multipart.new({:foo => f})
|
@@ -141,6 +157,33 @@ Content-Type: text/plain\r
|
|
141
157
|
|
142
158
|
end
|
143
159
|
|
160
|
+
context "streamed payloads" do
|
161
|
+
it "should properly determine the size of file payloads" do
|
162
|
+
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
163
|
+
payload = RestClient::Payload.generate(f)
|
164
|
+
payload.size.should == 22_545
|
165
|
+
payload.length.should == 22_545
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should properly determine the size of other kinds of streaming payloads" do
|
169
|
+
s = StringIO.new 'foo'
|
170
|
+
payload = RestClient::Payload.generate(s)
|
171
|
+
payload.size.should == 3
|
172
|
+
payload.length.should == 3
|
173
|
+
|
174
|
+
begin
|
175
|
+
f = Tempfile.new "rest-client"
|
176
|
+
f.write 'foo bar'
|
177
|
+
|
178
|
+
payload = RestClient::Payload.generate(f)
|
179
|
+
payload.size.should == 7
|
180
|
+
payload.length.should == 7
|
181
|
+
ensure
|
182
|
+
f.close
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
144
187
|
context "Payload generation" do
|
145
188
|
it "should recognize standard urlencoded params" do
|
146
189
|
RestClient::Payload.generate({"foo" => 'bar'}).should be_kind_of(RestClient::Payload::UrlEncoded)
|
@@ -164,5 +207,13 @@ Content-Type: text/plain\r
|
|
164
207
|
RestClient::Payload.generate({"foo" => {"file" => f}}).should be_kind_of(RestClient::Payload::Multipart)
|
165
208
|
end
|
166
209
|
|
210
|
+
it "should recognize file payloads that can be streamed" do
|
211
|
+
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
212
|
+
RestClient::Payload.generate(f).should be_kind_of(RestClient::Payload::Streamed)
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should recognize other payloads that can be streamed" do
|
216
|
+
RestClient::Payload.generate(StringIO.new('foo')).should be_kind_of(RestClient::Payload::Streamed)
|
217
|
+
end
|
167
218
|
end
|
168
219
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/base'
|
2
|
+
|
3
|
+
require 'webmock/rspec'
|
4
|
+
include WebMock
|
5
|
+
|
6
|
+
describe RestClient::Request do
|
7
|
+
|
8
|
+
it "manage params for get requests" do
|
9
|
+
stub_request(:get, 'http://some/resource?a=b&c=d').with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar'}).to_return(:body => 'foo', :status => 200)
|
10
|
+
RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => {:a => :b, 'c' => 'd'}}).body.should == 'foo'
|
11
|
+
|
12
|
+
stub_request(:get, 'http://some/resource').with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'Foo'=>'bar', 'params' => 'a'}).to_return(:body => 'foo', :status => 200)
|
13
|
+
RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :headers => {:foo => :bar, :params => :a}).body.should == 'foo'
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
data/spec/request_spec.rb
CHANGED
@@ -59,7 +59,7 @@ describe RestClient::Request do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
it "doesn't classify successful requests as failed" do
|
62
|
-
203.upto(
|
62
|
+
203.upto(207) do |code|
|
63
63
|
res = mock("result")
|
64
64
|
res.stub!(:code).and_return(code.to_s)
|
65
65
|
res.stub!(:body).and_return("")
|
@@ -276,7 +276,7 @@ describe RestClient::Request do
|
|
276
276
|
describe "block usage" do
|
277
277
|
it "returns what asked to" do
|
278
278
|
res = mock('response', :code => '401', :[] => ['content-encoding' => ''], :body => '' )
|
279
|
-
@request.process_result(res){|response| "foo"}.should == "foo"
|
279
|
+
@request.process_result(res){|response, request| "foo"}.should == "foo"
|
280
280
|
end
|
281
281
|
end
|
282
282
|
|
data/spec/resource_spec.rb
CHANGED
@@ -5,32 +5,32 @@ include WebMock
|
|
5
5
|
|
6
6
|
describe RestClient::Resource do
|
7
7
|
before do
|
8
|
-
@resource = RestClient::Resource.new('http://some/resource', :user => 'jane', :password => 'mypass', :headers => {
|
8
|
+
@resource = RestClient::Resource.new('http://some/resource', :user => 'jane', :password => 'mypass', :headers => {'X-Something' => '1'})
|
9
9
|
end
|
10
10
|
|
11
11
|
context "Resource delegation" do
|
12
12
|
it "GET" do
|
13
|
-
RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {
|
13
|
+
RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
|
14
14
|
@resource.get
|
15
15
|
end
|
16
16
|
|
17
17
|
it "POST" do
|
18
|
-
RestClient::Request.should_receive(:execute).with(:method => :post, :url => 'http://some/resource', :payload => 'abc', :headers => {
|
18
|
+
RestClient::Request.should_receive(:execute).with(:method => :post, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
|
19
19
|
@resource.post 'abc', :content_type => 'image/jpg'
|
20
20
|
end
|
21
21
|
|
22
22
|
it "PUT" do
|
23
|
-
RestClient::Request.should_receive(:execute).with(:method => :put, :url => 'http://some/resource', :payload => 'abc', :headers => {
|
23
|
+
RestClient::Request.should_receive(:execute).with(:method => :put, :url => 'http://some/resource', :payload => 'abc', :headers => {:content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
|
24
24
|
@resource.put 'abc', :content_type => 'image/jpg'
|
25
25
|
end
|
26
26
|
|
27
27
|
it "DELETE" do
|
28
|
-
RestClient::Request.should_receive(:execute).with(:method => :delete, :url => 'http://some/resource', :headers => {
|
28
|
+
RestClient::Request.should_receive(:execute).with(:method => :delete, :url => 'http://some/resource', :headers => {'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
|
29
29
|
@resource.delete
|
30
30
|
end
|
31
31
|
|
32
32
|
it "overrides resource headers" do
|
33
|
-
RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {
|
33
|
+
RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {'X-Something' => '2'}, :user => 'jane', :password => 'mypass')
|
34
34
|
@resource.get 'X-Something' => '2'
|
35
35
|
end
|
36
36
|
end
|
@@ -79,20 +79,20 @@ describe RestClient::Resource do
|
|
79
79
|
describe 'block' do
|
80
80
|
it 'can use block when creating the resource' do
|
81
81
|
stub_request(:get, 'www.example.com').to_return(:body => '', :status => 404)
|
82
|
-
resource = RestClient::Resource.new('www.example.com'){|response| 'foo'}
|
82
|
+
resource = RestClient::Resource.new('www.example.com') { |response, request| 'foo' }
|
83
83
|
resource.get.should == 'foo'
|
84
84
|
end
|
85
85
|
|
86
86
|
it 'can use block when executing the resource' do
|
87
87
|
stub_request(:get, 'www.example.com').to_return(:body => '', :status => 404)
|
88
88
|
resource = RestClient::Resource.new('www.example.com')
|
89
|
-
resource.get{|response| 'foo'}.should == 'foo'
|
89
|
+
resource.get { |response, request| 'foo' }.should == 'foo'
|
90
90
|
end
|
91
91
|
|
92
92
|
it 'execution block override resource block' do
|
93
93
|
stub_request(:get, 'www.example.com').to_return(:body => '', :status => 404)
|
94
|
-
resource = RestClient::Resource.new('www.example.com'){|response| 'foo'}
|
95
|
-
resource.get{|response| 'bar'}.should == 'bar'
|
94
|
+
resource = RestClient::Resource.new('www.example.com') { |response, request| 'foo' }
|
95
|
+
resource.get { |response, request| 'bar' }.should == 'bar'
|
96
96
|
end
|
97
97
|
|
98
98
|
end
|
data/spec/response_spec.rb
CHANGED
@@ -6,6 +6,7 @@ include WebMock
|
|
6
6
|
describe RestClient::Response do
|
7
7
|
before do
|
8
8
|
@net_http_res = mock('net http response', :to_hash => {"Status" => ["200 OK"]}, :code => 200)
|
9
|
+
@request = mock('http request', :user => nil, :password => nil)
|
9
10
|
@response = RestClient::Response.create('abc', @net_http_res, {})
|
10
11
|
end
|
11
12
|
|
@@ -59,13 +60,13 @@ describe RestClient::Response do
|
|
59
60
|
(200..206).each do |code|
|
60
61
|
net_http_res = mock('net http response', :code => '200')
|
61
62
|
response = RestClient::Response.create('abc', net_http_res, {})
|
62
|
-
response.return!
|
63
|
+
response.return! @request
|
63
64
|
end
|
64
65
|
end
|
65
66
|
|
66
67
|
it "should throw an exception for other codes" do
|
67
68
|
RestClient::Exceptions::EXCEPTIONS_MAP.each_key do |code|
|
68
|
-
unless (200..
|
69
|
+
unless (200..207).include? code
|
69
70
|
net_http_res = mock('net http response', :code => code.to_i)
|
70
71
|
response = RestClient::Response.create('abc', net_http_res, {})
|
71
72
|
lambda { response.return!}.should raise_error
|
@@ -83,16 +84,34 @@ describe RestClient::Response do
|
|
83
84
|
RestClient::Request.execute(:url => 'http://some/resource', :method => :get).body.should == 'Foo'
|
84
85
|
end
|
85
86
|
|
86
|
-
it "
|
87
|
+
it "follows a redirection and keep the parameters" do
|
88
|
+
stub_request(:get, 'http://foo:bar@some/resource').with(:headers => {'Accept' => 'application/json'}).to_return(:body => '', :status => 301, :headers => {'Location' => 'http://new/resource'})
|
89
|
+
stub_request(:get, 'http://foo:bar@new/resource').with(:headers => {'Accept' => 'application/json'}).to_return(:body => 'Foo')
|
90
|
+
RestClient::Request.execute(:url => 'http://some/resource', :method => :get, :user => 'foo', :password => 'bar', :headers => {:accept => :json}).body.should == 'Foo'
|
91
|
+
end
|
92
|
+
|
93
|
+
it "doesn't follow a 301 when the request is a post" do
|
87
94
|
net_http_res = mock('net http response', :code => 301)
|
88
95
|
response = RestClient::Response.create('abc', net_http_res, {:method => :post})
|
89
|
-
lambda { response.return!}.should raise_error(RestClient::MovedPermanently)
|
96
|
+
lambda { response.return!(@request)}.should raise_error(RestClient::MovedPermanently)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "doesn't follow a 302 when the request is a post" do
|
100
|
+
net_http_res = mock('net http response', :code => 302)
|
101
|
+
response = RestClient::Response.create('abc', net_http_res, {:method => :post})
|
102
|
+
lambda { response.return!(@request)}.should raise_error(RestClient::Found)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "doesn't follow a 307 when the request is a post" do
|
106
|
+
net_http_res = mock('net http response', :code => 307)
|
107
|
+
response = RestClient::Response.create('abc', net_http_res, {:method => :post})
|
108
|
+
lambda { response.return!(@request)}.should raise_error(RestClient::TemporaryRedirect)
|
90
109
|
end
|
91
110
|
|
92
111
|
it "doesn't follow a redirection when the request is a put" do
|
93
112
|
net_http_res = mock('net http response', :code => 301)
|
94
113
|
response = RestClient::Response.create('abc', net_http_res, {:method => :put})
|
95
|
-
lambda { response.return!}.should raise_error(RestClient::MovedPermanently)
|
114
|
+
lambda { response.return!(@request)}.should raise_error(RestClient::MovedPermanently)
|
96
115
|
end
|
97
116
|
|
98
117
|
it "follows a redirection when the request is a post and result is a 303" do
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 10
|
5
|
+
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
|
8
|
+
- 6
|
9
|
+
- 0
|
10
|
+
- a
|
11
|
+
version: 1.6.0.a
|
11
12
|
platform: ruby
|
12
13
|
authors:
|
13
14
|
- Adam Wiggins
|
@@ -16,7 +17,7 @@ autorequire:
|
|
16
17
|
bindir: bin
|
17
18
|
cert_chain: []
|
18
19
|
|
19
|
-
date: 2010-
|
20
|
+
date: 2010-06-28 00:00:00 +02:00
|
20
21
|
default_executable: restclient
|
21
22
|
dependencies:
|
22
23
|
- !ruby/object:Gem::Dependency
|
@@ -49,6 +50,7 @@ files:
|
|
49
50
|
- VERSION
|
50
51
|
- bin/restclient
|
51
52
|
- lib/rest_client.rb
|
53
|
+
- lib/rest-client.rb
|
52
54
|
- lib/restclient.rb
|
53
55
|
- lib/restclient/exceptions.rb
|
54
56
|
- lib/restclient/abstract_response.rb
|
@@ -66,6 +68,7 @@ files:
|
|
66
68
|
- spec/payload_spec.rb
|
67
69
|
- spec/raw_response_spec.rb
|
68
70
|
- spec/request_spec.rb
|
71
|
+
- spec/request2_spec.rb
|
69
72
|
- spec/resource_spec.rb
|
70
73
|
- spec/response_spec.rb
|
71
74
|
- spec/restclient_spec.rb
|
@@ -115,6 +118,7 @@ test_files:
|
|
115
118
|
- spec/payload_spec.rb
|
116
119
|
- spec/raw_response_spec.rb
|
117
120
|
- spec/request_spec.rb
|
121
|
+
- spec/request2_spec.rb
|
118
122
|
- spec/resource_spec.rb
|
119
123
|
- spec/response_spec.rb
|
120
124
|
- spec/restclient_spec.rb
|