rest-client 1.6.7 → 1.8.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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +14 -0
  5. data/AUTHORS +81 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE +21 -0
  8. data/README.rdoc +63 -24
  9. data/Rakefile +85 -35
  10. data/bin/restclient +9 -8
  11. data/history.md +63 -1
  12. data/lib/restclient/abstract_response.rb +44 -15
  13. data/lib/restclient/exceptions.rb +20 -10
  14. data/lib/restclient/payload.rb +21 -18
  15. data/lib/restclient/platform.rb +30 -0
  16. data/lib/restclient/raw_response.rb +3 -2
  17. data/lib/restclient/request.rb +368 -63
  18. data/lib/restclient/resource.rb +3 -4
  19. data/lib/restclient/response.rb +2 -5
  20. data/lib/restclient/version.rb +7 -0
  21. data/lib/restclient/windows/root_certs.rb +105 -0
  22. data/lib/restclient/windows.rb +8 -0
  23. data/lib/restclient.rb +6 -15
  24. data/rest-client.gemspec +30 -0
  25. data/rest-client.windows.gemspec +19 -0
  26. data/spec/integration/capath_digicert/244b5494.0 +19 -0
  27. data/spec/integration/capath_digicert/81b9768f.0 +19 -0
  28. data/spec/integration/capath_digicert/README +8 -0
  29. data/spec/integration/capath_digicert/digicert.crt +19 -0
  30. data/spec/integration/capath_verisign/415660c1.0 +14 -0
  31. data/spec/integration/capath_verisign/7651b327.0 +14 -0
  32. data/spec/integration/capath_verisign/README +8 -0
  33. data/spec/integration/capath_verisign/verisign.crt +14 -0
  34. data/spec/integration/certs/digicert.crt +19 -0
  35. data/spec/{integration_spec.rb → integration/integration_spec.rb} +10 -13
  36. data/spec/integration/request_spec.rb +86 -7
  37. data/spec/spec_helper.rb +2 -0
  38. data/spec/{abstract_response_spec.rb → unit/abstract_response_spec.rb} +18 -15
  39. data/spec/{exceptions_spec.rb → unit/exceptions_spec.rb} +17 -20
  40. data/spec/unit/master_shake.jpg +0 -0
  41. data/spec/{payload_spec.rb → unit/payload_spec.rb} +42 -31
  42. data/spec/unit/raw_response_spec.rb +18 -0
  43. data/spec/{request2_spec.rb → unit/request2_spec.rb} +6 -14
  44. data/spec/unit/request_spec.rb +917 -0
  45. data/spec/{resource_spec.rb → unit/resource_spec.rb} +27 -31
  46. data/spec/{response_spec.rb → unit/response_spec.rb} +63 -57
  47. data/spec/{restclient_spec.rb → unit/restclient_spec.rb} +8 -2
  48. data/spec/unit/windows/root_certs_spec.rb +22 -0
  49. metadata +210 -112
  50. data/VERSION +0 -1
  51. data/lib/restclient/net_http_ext.rb +0 -55
  52. data/spec/base.rb +0 -16
  53. data/spec/integration/certs/equifax.crt +0 -19
  54. data/spec/master_shake.jpg +0 -0
  55. data/spec/raw_response_spec.rb +0 -17
  56. data/spec/request_spec.rb +0 -529
@@ -1,10 +1,11 @@
1
1
  require 'cgi'
2
+ require 'http-cookie'
2
3
 
3
4
  module RestClient
4
5
 
5
6
  module AbstractResponse
6
7
 
7
- attr_reader :net_http_res, :args
8
+ attr_reader :net_http_res, :args, :request
8
9
 
9
10
  # HTTP status code
10
11
  def code
@@ -22,11 +23,36 @@ module RestClient
22
23
  @raw_headers ||= @net_http_res.to_hash
23
24
  end
24
25
 
26
+ def response_set_vars(net_http_res, args, request)
27
+ @net_http_res = net_http_res
28
+ @args = args
29
+ @request = request
30
+ end
31
+
25
32
  # Hash of cookies extracted from response headers
26
33
  def cookies
27
- @cookies ||= (self.headers[:set_cookie] || {}).inject({}) do |out, cookie_content|
28
- out.merge parse_cookie(cookie_content)
34
+ hash = {}
35
+
36
+ cookie_jar.cookies.each do |cookie|
37
+ hash[cookie.name] = cookie.value
29
38
  end
39
+
40
+ hash
41
+ end
42
+
43
+ # Cookie jar extracted from response headers.
44
+ #
45
+ # @return [HTTP::CookieJar]
46
+ #
47
+ def cookie_jar
48
+ return @cookie_jar if @cookie_jar
49
+
50
+ jar = HTTP::CookieJar.new
51
+ headers.fetch(:set_cookie, []).each do |cookie|
52
+ jar.parse(cookie, @request.url)
53
+ end
54
+
55
+ @cookie_jar = jar
30
56
  end
31
57
 
32
58
  # Return the default behavior corresponding to the response code:
@@ -61,28 +87,31 @@ module RestClient
61
87
 
62
88
  # Follow a redirection
63
89
  def follow_redirection request = nil, result = nil, & block
90
+ new_args = @args.dup
91
+
64
92
  url = headers[:location]
65
93
  if url !~ /^http/
66
- url = URI.parse(args[:url]).merge(url).to_s
94
+ url = URI.parse(request.url).merge(url).to_s
67
95
  end
68
- args[:url] = url
96
+ new_args[:url] = url
69
97
  if request
70
98
  if request.max_redirects == 0
71
99
  raise MaxRedirectsReached
72
100
  end
73
- args[:password] = request.password
74
- args[:user] = request.user
75
- args[:headers] = request.headers
76
- args[:max_redirects] = request.max_redirects - 1
77
- # pass any cookie set in the result
78
- if result && result['set-cookie']
79
- args[:headers][:cookies] = (args[:headers][:cookies] || {}).merge(parse_cookie(result['set-cookie']))
80
- end
101
+ new_args[:password] = request.password
102
+ new_args[:user] = request.user
103
+ new_args[:headers] = request.headers
104
+ new_args[:max_redirects] = request.max_redirects - 1
105
+
106
+ # TODO: figure out what to do with original :cookie, :cookies values
107
+ new_args[:headers]['Cookie'] = HTTP::Cookie.cookie_value(
108
+ cookie_jar.cookies(new_args.fetch(:url)))
81
109
  end
82
- Request.execute args, &block
110
+
111
+ Request.execute(new_args, &block)
83
112
  end
84
113
 
85
- def AbstractResponse.beautify_headers(headers)
114
+ def self.beautify_headers(headers)
86
115
  headers.inject({}) do |out, (key, value)|
87
116
  out[key.gsub(/-/, '_').downcase.to_sym] = %w{ set-cookie }.include?(key.downcase) ? value : value.first
88
117
  out
@@ -21,7 +21,7 @@ module RestClient
21
21
  305 => 'Use Proxy', # http/1.1
22
22
  306 => 'Switch Proxy', # no longer used
23
23
  307 => 'Temporary Redirect', # http/1.1
24
-
24
+
25
25
  400 => 'Bad Request',
26
26
  401 => 'Unauthorized',
27
27
  402 => 'Payment Required',
@@ -40,13 +40,16 @@ module RestClient
40
40
  415 => 'Unsupported Media Type',
41
41
  416 => 'Requested Range Not Satisfiable',
42
42
  417 => 'Expectation Failed',
43
- 418 => 'I\'m A Teapot',
43
+ 418 => 'I\'m A Teapot', #RFC2324
44
44
  421 => 'Too Many Connections From This IP',
45
45
  422 => 'Unprocessable Entity', #WebDAV
46
46
  423 => 'Locked', #WebDAV
47
47
  424 => 'Failed Dependency', #WebDAV
48
48
  425 => 'Unordered Collection', #WebDAV
49
- 426 => 'Upgrade Required',
49
+ 426 => 'Upgrade Required',
50
+ 428 => 'Precondition Required', #RFC6585
51
+ 429 => 'Too Many Requests', #RFC6585
52
+ 431 => 'Request Header Fields Too Large', #RFC6585
50
53
  449 => 'Retry With', #Microsoft
51
54
  450 => 'Blocked By Windows Parental Controls', #Microsoft
52
55
 
@@ -59,7 +62,9 @@ module RestClient
59
62
  506 => 'Variant Also Negotiates',
60
63
  507 => 'Insufficient Storage', #WebDAV
61
64
  509 => 'Bandwidth Limit Exceeded', #Apache
62
- 510 => 'Not Extended'}
65
+ 510 => 'Not Extended',
66
+ 511 => 'Network Authentication Required', # RFC6585
67
+ }
63
68
 
64
69
  # Compatibility : make the Response act like a Net::HTTPResponse when needed
65
70
  module ResponseForException
@@ -81,10 +86,11 @@ module RestClient
81
86
  # probably an HTML error page) is e.response.
82
87
  class Exception < RuntimeError
83
88
  attr_accessor :response
84
- attr_writer :message
89
+ attr_writer :message
85
90
 
86
91
  def initialize response = nil, initial_response_code = nil
87
92
  @response = response
93
+ @message = nil
88
94
  @initial_response_code = initial_response_code
89
95
 
90
96
  # compatibility: this make the exception behave like a Net::HTTPResponse
@@ -111,7 +117,7 @@ module RestClient
111
117
  def to_s
112
118
  inspect
113
119
  end
114
-
120
+
115
121
  def message
116
122
  @message || self.class.name
117
123
  end
@@ -154,7 +160,9 @@ module RestClient
154
160
  # A redirect was encountered; caught by execute to retry with the new url.
155
161
  class Redirect < Exception
156
162
 
157
- message = 'Redirect'
163
+ def message
164
+ 'Redirect'
165
+ end
158
166
 
159
167
  attr_accessor :url
160
168
 
@@ -163,8 +171,10 @@ module RestClient
163
171
  end
164
172
  end
165
173
 
166
- class MaxRedirectsReached < Exception
167
- message = 'Maximum number of redirect reached'
174
+ class MaxRedirectsReached < Exception
175
+ def message
176
+ 'Maximum number of redirect reached'
177
+ end
168
178
  end
169
179
 
170
180
  # The server broke the connection prior to the request completing. Usually
@@ -185,8 +195,8 @@ module RestClient
185
195
  end
186
196
  end
187
197
 
188
- # backwards compatibility
189
198
  class RestClient::Request
199
+ # backwards compatibility
190
200
  Redirect = RestClient::Redirect
191
201
  Unauthorized = RestClient::Unauthorized
192
202
  RequestFailed = RestClient::RequestFailed
@@ -9,14 +9,14 @@ 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)
14
- elsif params
12
+ elsif params.is_a?(Hash)
15
13
  if params.delete(:multipart) == true || has_file?(params)
16
14
  Multipart.new(params)
17
15
  else
18
16
  UrlEncoded.new(params)
19
17
  end
18
+ elsif params.respond_to?(:read)
19
+ Streamed.new(params)
20
20
  else
21
21
  nil
22
22
  end
@@ -25,12 +25,12 @@ module RestClient
25
25
  def has_file?(params)
26
26
  params.any? do |_, v|
27
27
  case v
28
- when Hash
29
- has_file?(v)
30
- when Array
31
- has_file_array?(v)
32
- else
33
- v.respond_to?(:path) && v.respond_to?(:read)
28
+ when Hash
29
+ has_file?(v)
30
+ when Array
31
+ has_file_array?(v)
32
+ else
33
+ v.respond_to?(:path) && v.respond_to?(:read)
34
34
  end
35
35
  end
36
36
  end
@@ -38,13 +38,13 @@ module RestClient
38
38
  def has_file_array?(params)
39
39
  params.any? do |v|
40
40
  case v
41
- when Hash
42
- has_file?(v)
43
- when Array
44
- has_file_array?(v)
45
- else
46
- v.respond_to?(:path) && v.respond_to?(:read)
47
- end
41
+ when Hash
42
+ has_file?(v)
43
+ when Array
44
+ has_file_array?(v)
45
+ else
46
+ v.respond_to?(:path) && v.respond_to?(:read)
47
+ end
48
48
  end
49
49
  end
50
50
 
@@ -147,12 +147,15 @@ module RestClient
147
147
 
148
148
  # for UrlEncoded escape the keys
149
149
  def handle_key key
150
- URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
150
+ Parser.escape(key.to_s, Escape)
151
151
  end
152
152
 
153
153
  def headers
154
154
  super.merge({'Content-Type' => 'application/x-www-form-urlencoded'})
155
155
  end
156
+
157
+ Parser = URI.const_defined?(:Parser) ? URI::Parser.new : URI
158
+ Escape = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
156
159
  end
157
160
 
158
161
  class Multipart < Base
@@ -201,7 +204,7 @@ module RestClient
201
204
  s.write(" filename=\"#{v.respond_to?(:original_filename) ? v.original_filename : File.basename(v.path)}\"#{EOL}")
202
205
  s.write("Content-Type: #{v.respond_to?(:content_type) ? v.content_type : mime_for(v.path)}#{EOL}")
203
206
  s.write(EOL)
204
- while data = v.read(8124)
207
+ while (data = v.read(8124))
205
208
  s.write(data)
206
209
  end
207
210
  ensure
@@ -0,0 +1,30 @@
1
+ module RestClient
2
+ module Platform
3
+ # Return true if we are running on a darwin-based Ruby platform. This will
4
+ # be false for jruby even on OS X.
5
+ #
6
+ # @return [Boolean]
7
+ def self.mac_mri?
8
+ RUBY_PLATFORM.include?('darwin')
9
+ end
10
+
11
+ # Return true if we are running on Windows.
12
+ #
13
+ # @return [Boolean]
14
+ #
15
+ def self.windows?
16
+ # Ruby only sets File::ALT_SEPARATOR on Windows, and the Ruby standard
17
+ # library uses that to test what platform it's on.
18
+ !!File::ALT_SEPARATOR
19
+ end
20
+
21
+ # Return true if we are running on jruby.
22
+ #
23
+ # @return [Boolean]
24
+ #
25
+ def self.jruby?
26
+ # defined on mri >= 1.9
27
+ RUBY_ENGINE == 'jruby'
28
+ end
29
+ end
30
+ end
@@ -13,12 +13,13 @@ module RestClient
13
13
 
14
14
  include AbstractResponse
15
15
 
16
- attr_reader :file
16
+ attr_reader :file, :request
17
17
 
18
- def initialize tempfile, net_http_res, args
18
+ def initialize(tempfile, net_http_res, args, request)
19
19
  @net_http_res = net_http_res
20
20
  @args = args
21
21
  @file = tempfile
22
+ @request = request
22
23
  end
23
24
 
24
25
  def to_s