rest-client 1.5.1 → 1.6.0.a

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rest-client might be problematic. Click here for more details.

@@ -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 'https://user:password@example.com/private/resource'
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 206 a RestClient::Response will be returned
81
- * for results code 301 and 302 the redirection will be followed if the request is a get or a head
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 (or 302) status code is received in response to a request other than GET or HEAD,
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.5.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
@@ -0,0 +1,2 @@
1
+ # More logical way to require 'rest-client'
2
+ require File.dirname(__FILE__) + '/restclient'
@@ -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 302 in get and head cases, redirection for 303 and an exception in other cases
39
- def return! &block
40
- if (200..206).include? code
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.gsub(/ /, '').gsub(/-/, ''), klass
136
+ klass_constant = const_set message.delete(' \-\''), klass
115
137
  Exceptions::EXCEPTIONS_MAP[code] = klass_constant
116
138
  end
117
139
 
@@ -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}[#{escape key}]" : escape(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
- { 'Content-Length' => size.to_s }
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]}=#{escape(entry[1])}"
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({ 'Content-Type' => 'application/x-www-form-urlencoded' })
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
@@ -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 response, &block
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
- { :accept => '*/*; q=0.5, application/xml', :accept_encoding => 'gzip, deflate' }
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/HQVH6YE rVkTpn0zvTQ==' }
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
@@ -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
+
@@ -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(206) do |code|
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
 
@@ -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 => { 'X-Something' => '1'})
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 => { 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
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 => { :content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
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 => { :content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
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 => { 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
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 => { 'X-Something' => '2'}, :user => 'jane', :password => 'mypass')
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
@@ -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..206).include? code
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 "doesn't follow a redirection when the request is a post" do
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: 1
5
- prerelease: false
4
+ hash: 10
5
+ prerelease: true
6
6
  segments:
7
7
  - 1
8
- - 5
9
- - 1
10
- version: 1.5.1
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-03-13 00:00:00 +01:00
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