rest-client 1.6.14

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.

Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +3 -0
  5. data/AUTHORS +75 -0
  6. data/Gemfile +7 -0
  7. data/README.rdoc +300 -0
  8. data/Rakefile +49 -0
  9. data/bin/restclient +93 -0
  10. data/history.md +160 -0
  11. data/lib/rest-client.rb +2 -0
  12. data/lib/rest_client.rb +2 -0
  13. data/lib/restclient.rb +170 -0
  14. data/lib/restclient/abstract_response.rb +106 -0
  15. data/lib/restclient/exceptions.rb +198 -0
  16. data/lib/restclient/net_http_ext.rb +55 -0
  17. data/lib/restclient/payload.rb +240 -0
  18. data/lib/restclient/platform.rb +29 -0
  19. data/lib/restclient/raw_response.rb +34 -0
  20. data/lib/restclient/request.rb +360 -0
  21. data/lib/restclient/resource.rb +169 -0
  22. data/lib/restclient/response.rb +26 -0
  23. data/lib/restclient/version.rb +7 -0
  24. data/rest-client.gemspec +26 -0
  25. data/spec/abstract_response_spec.rb +85 -0
  26. data/spec/base.rb +13 -0
  27. data/spec/exceptions_spec.rb +98 -0
  28. data/spec/integration/capath_digicert/244b5494.0 +19 -0
  29. data/spec/integration/capath_digicert/81b9768f.0 +19 -0
  30. data/spec/integration/capath_digicert/README +8 -0
  31. data/spec/integration/capath_digicert/digicert.crt +19 -0
  32. data/spec/integration/certs/digicert.crt +19 -0
  33. data/spec/integration/certs/verisign.crt +14 -0
  34. data/spec/integration/request_spec.rb +75 -0
  35. data/spec/integration_spec.rb +38 -0
  36. data/spec/master_shake.jpg +0 -0
  37. data/spec/payload_spec.rb +244 -0
  38. data/spec/raw_response_spec.rb +17 -0
  39. data/spec/request2_spec.rb +35 -0
  40. data/spec/request_spec.rb +528 -0
  41. data/spec/resource_spec.rb +136 -0
  42. data/spec/response_spec.rb +169 -0
  43. data/spec/restclient_spec.rb +73 -0
  44. metadata +192 -0
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.dirname(__FILE__) + "/../lib"
4
+
5
+ require 'rubygems'
6
+ require 'restclient'
7
+ require 'yaml'
8
+
9
+ def usage(why = nil)
10
+ puts "failed for reason: #{why}" if why
11
+ puts "usage: restclient [get|put|post|delete] url|name [username] [password]"
12
+ puts " The verb is optional, if you leave it off you'll get an interactive shell."
13
+ puts " put and post both take the input body on stdin."
14
+ exit(1)
15
+ end
16
+
17
+ POSSIBLE_VERBS = ['get', 'put', 'post', 'delete']
18
+
19
+ if POSSIBLE_VERBS.include? ARGV.first
20
+ @verb = ARGV.shift
21
+ else
22
+ @verb = nil
23
+ end
24
+
25
+ @url = ARGV.shift || 'http://localhost:4567'
26
+
27
+ config = YAML.load(File.read(ENV['HOME'] + "/.restclient")) rescue {}
28
+
29
+ @url, @username, @password = if c = config[@url]
30
+ [c['url'], c['username'], c['password']]
31
+ else
32
+ [@url, * ARGV]
33
+ end
34
+
35
+ usage("invalid url '#{@url}") unless @url =~ /^https?/
36
+ usage("too few args") unless ARGV.size < 3
37
+
38
+ def r
39
+ @r ||= RestClient::Resource.new(@url, @username, @password)
40
+ end
41
+
42
+ r # force rc to load
43
+
44
+ if @verb
45
+ begin
46
+ if %w( put post ).include? @verb
47
+ puts r.send(@verb, STDIN.read)
48
+ else
49
+ puts r.send(@verb)
50
+ end
51
+ exit 0
52
+ rescue RestClient::Exception => e
53
+ puts e.response.body if e.respond_to? :response
54
+ raise
55
+ end
56
+ end
57
+
58
+ POSSIBLE_VERBS.each do |m|
59
+ eval <<-end_eval
60
+ def #{m}(path, *args, &b)
61
+ r[path].#{m}(*args, &b)
62
+ end
63
+ end_eval
64
+ end
65
+
66
+ def method_missing(s, * args, & b)
67
+ if POSSIBLE_VERBS.include? s
68
+ begin
69
+ r.send(s, *args, & b)
70
+ rescue RestClient::RequestFailed => e
71
+ print STDERR, e.response.body
72
+ raise e
73
+ end
74
+ else
75
+ super
76
+ end
77
+ end
78
+
79
+ require 'irb'
80
+ require 'irb/completion'
81
+
82
+ if File.exists? ".irbrc"
83
+ ENV['IRBRC'] = ".irbrc"
84
+ end
85
+
86
+ if File.exists?(File.expand_path(rcfile = "~/.restclientrc"))
87
+ load(rcfile)
88
+ end
89
+
90
+ ARGV.clear
91
+
92
+ IRB.start
93
+ exit!
@@ -0,0 +1,160 @@
1
+ # 1.6.14
2
+
3
+ - This release is unchanged from 1.6.9. It was published in order to supersede
4
+ the malicious 1.6.10-13 versions, even for users who are still pinning to the
5
+ legacy 1.6.x series. All users are encouraged to upgrade to rest-client 2.x.
6
+
7
+ # 1.6.10, 1.6.11, 1.6.12, 1.6.13 (CVE-2019-15224)
8
+
9
+ - These versions were pushed by a malicious actor and included a backdoor permitting
10
+ remote code execution in Rails environments.
11
+ - They were live for about five days before being yanked.
12
+ https://github.com/rest-client/rest-client/issues/713
13
+
14
+ # 1.6.9
15
+
16
+ - Move rdoc to a development dependency
17
+
18
+ # 1.6.8
19
+
20
+ - The 1.6.x series will be the last to support Ruby 1.8.7
21
+ - Pin mime-types to < 2.0 to maintain Ruby 1.8.7 support
22
+ - Add Gemfile, AUTHORS, add license to gemspec
23
+ - Point homepage at https://github.com/rest-client/rest-client
24
+ - Clean up and fix various tests and ruby warnings
25
+ - Backport `ssl_verify_callback` functionality from 1.7.0
26
+
27
+ # 1.6.7
28
+
29
+ - rebuild with 1.8.7 to avoid https://github.com/rubygems/rubygems/pull/57
30
+
31
+ # 1.6.6
32
+
33
+ - 1.6.5 was yanked
34
+
35
+ # 1.6.5
36
+
37
+ - RFC6265 requires single SP after ';' for separating parameters pairs in the 'Cookie:' header (patch provided by Hiroshi Nakamura)
38
+ - enable url parameters for all actions
39
+ - detect file parameters in arrays
40
+ - allow disabling the timeouts by passing -1 (patch provided by Sven Böhm)
41
+
42
+ # 1.6.4
43
+
44
+ - fix restclient script compatibility with 1.9.2
45
+ - fix unlinking temp file (patch provided by Evan Smith)
46
+ - monkeypatching ruby for http patch method (patch provided by Syl Turner)
47
+
48
+ # 1.6.3
49
+
50
+ - 1.6.2 was yanked
51
+
52
+ # 1.6.2
53
+
54
+ - add support for HEAD in resources (patch provided by tpresa)
55
+ - fix shell for 1.9.2
56
+ - workaround when some gem monkeypatch net/http (patch provided by Ian Warshak)
57
+ - DELETE requests should process parameters just like GET and HEAD
58
+ - adding :block_response parameter for manual processing
59
+ - limit number of redirections (patch provided by Chris Dinn)
60
+ - close and unlink the temp file created by playload (patch provided by Chris Green)
61
+ - make gemspec Rubygems 1.8 compatible (patch provided by David Backeus)
62
+ - added RestClient.reset_before_execution_procs (patch provided by Cloudify)
63
+ - added PATCH method (patch provided by Jeff Remer)
64
+ - hack for HTTP servers that use raw DEFLATE compression, see http://www.ruby-forum.com/topic/136825 (path provided by James Reeves)
65
+
66
+ # 1.6.1
67
+
68
+ - add response body in Exception#inspect
69
+ - add support for RestClient.options
70
+ - fix tests for 1.9.2 (patch provided by Niko Dittmann)
71
+ - block passing in Resource#[] (patch provided by Niko Dittmann)
72
+ - cookies set in a response should be kept in a redirect
73
+ - HEAD requests should process parameters just like GET (patch provided by Rob Eanes)
74
+ - exception message should never be nil (patch provided by Michael Klett)
75
+
76
+ # 1.6.0
77
+
78
+ - forgot to include rest-client.rb in the gem
79
+ - user, password and user-defined headers should survive a redirect
80
+ - added all missing status codes
81
+ - added parameter passing for get request using the :param key in header
82
+ - the warning about the logger when using a string was a bad idea
83
+ - multipart parameters names should not be escaped
84
+ - remove the cookie escaping introduced by migrating to CGI cookie parsing in 1.5.1
85
+ - add a streamed payload type (patch provided by Caleb Land)
86
+ - Exception#http_body works even when no response
87
+
88
+ # 1.5.1
89
+
90
+ - only converts headers keys which are Symbols
91
+ - use CGI for cookie parsing instead of custom code
92
+ - unescape user and password before using them (patch provided by Lars Gierth)
93
+ - expand ~ in ~/.restclientrc (patch provided by Mike Fletcher)
94
+ - ssl verification raise an exception when the ca certificate is incorrect (patch provided by Braintree)
95
+
96
+ # 1.5.0
97
+
98
+ - the response is now a String with the Response module a.k.a. the change in 1.4.0 was a mistake (Response.body is returning self for compatability)
99
+ - added AbstractResponse.to_i to improve semantic
100
+ - multipart Payloads ignores the name attribute if it's not set (patch provided by Tekin Suleyman)
101
+ - correctly takes into account user headers whose keys are strings (path provided by Cyril Rohr)
102
+ - use binary mode for payload temp file
103
+ - concatenate cookies with ';'
104
+ - fixed deeper parameter handling
105
+ - do not quote the boundary in the Content-Type header (patch provided by W. Andrew Loe III)
106
+
107
+ # 1.4.2
108
+
109
+ - fixed RestClient.add_before_execution_proc (patch provided by Nicholas Wieland)
110
+ - fixed error when an exception is raised without a response (patch provided by Caleb Land)
111
+
112
+ # 1.4.1
113
+
114
+ - fixed parameters managment when using hash
115
+
116
+ # 1.4.0
117
+
118
+ - Response is no more a String, and the mixin is replaced by an abstract_response, existing calls are redirected to response body with a warning.
119
+ - enable repeated parameters RestClient.post 'http://example.com/resource', :param1 => ['one', 'two', 'three'], => :param2 => 'foo' (patch provided by Rodrigo Panachi)
120
+ - fixed the redirect code concerning relative path and query string combination (patch provided by Kevin Read)
121
+ - redirection code moved to Response so redirection can be customized using the block syntax
122
+ - only get and head redirections are now followed by default, as stated in the specification
123
+ - added RestClient.add_before_execution_proc to hack the http request, like for oauth
124
+
125
+ The response change may be breaking in rare cases.
126
+
127
+ # 1.3.1
128
+
129
+ - added compatibility to enable responses in exception to act like Net::HTTPResponse
130
+
131
+ # 1.3.0
132
+
133
+ - a block can be used to process a request's result, this enable to handle custom error codes or paththrought (design by Cyril Rohr)
134
+ - cleaner log API, add a warning for some cases but should be compatible
135
+ - accept multiple "Set-Cookie" headers, see http://www.ietf.org/rfc/rfc2109.txt (patch provided by Cyril Rohr)
136
+ - remove "Content-Length" and "Content-Type" headers when following a redirection (patch provided by haarts)
137
+ - all http error codes have now a corresponding exception class and all of them contain the Reponse -> this means that the raised exception can be different
138
+ - changed "Content-Disposition: multipart/form-data" to "Content-Disposition: form-data" per RFC 2388 (patch provided by Kyle Crawford)
139
+
140
+ The only breaking change should be the exception classes, but as the new classes inherits from the existing ones, the breaking cases should be rare.
141
+
142
+ # 1.2.0
143
+
144
+ - formatting changed from tabs to spaces
145
+ - logged requests now include generated headers
146
+ - accept and content-type headers can now be specified using extentions: RestClient.post "http://example.com/resource", { 'x' => 1 }.to_json, :content_type => :json, :accept => :json
147
+ - should be 1.1.1 but renamed to 1.2.0 because 1.1.X versions has already been packaged on Debian
148
+
149
+ # 1.1.0
150
+
151
+ - new maintainer: Archiloque, the working repo is now at http://github.com/archiloque/rest-client
152
+ - a mailing list has been created at rest.client@librelist.com and an freenode irc channel #rest-client
153
+ - François Beausoleil' multipart code from http://github.com/francois/rest-client has been merged
154
+ - ability to use hash in hash as payload
155
+ - the mime-type code now rely on the mime-types gem http://mime-types.rubyforge.org/ instead of an internal partial list
156
+ - 204 response returns a Response instead of nil (patch provided by Elliott Draper)
157
+
158
+ All changes exept the last one should be fully compatible with the previous version.
159
+
160
+ NOTE: due to a dependency problem and to the last change, heroku users should update their heroku gem to >= 1.5.3 to be able to use this version.
@@ -0,0 +1,2 @@
1
+ # More logical way to require 'rest-client'
2
+ require File.dirname(__FILE__) + '/restclient'
@@ -0,0 +1,2 @@
1
+ # This file exists for backward compatbility with require 'rest_client'
2
+ require File.dirname(__FILE__) + '/restclient'
@@ -0,0 +1,170 @@
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__) + '/restclient/version'
13
+ require File.dirname(__FILE__) + '/restclient/platform'
14
+ require File.dirname(__FILE__) + '/restclient/exceptions'
15
+ require File.dirname(__FILE__) + '/restclient/request'
16
+ require File.dirname(__FILE__) + '/restclient/abstract_response'
17
+ require File.dirname(__FILE__) + '/restclient/response'
18
+ require File.dirname(__FILE__) + '/restclient/raw_response'
19
+ require File.dirname(__FILE__) + '/restclient/resource'
20
+ require File.dirname(__FILE__) + '/restclient/payload'
21
+ require File.dirname(__FILE__) + '/restclient/net_http_ext'
22
+
23
+ # This module's static methods are the entry point for using the REST client.
24
+ #
25
+ # # GET
26
+ # xml = RestClient.get 'http://example.com/resource'
27
+ # jpg = RestClient.get 'http://example.com/resource', :accept => 'image/jpg'
28
+ #
29
+ # # authentication and SSL
30
+ # RestClient.get 'https://user:password@example.com/private/resource'
31
+ #
32
+ # # POST or PUT with a hash sends parameters as a urlencoded form body
33
+ # RestClient.post 'http://example.com/resource', :param1 => 'one'
34
+ #
35
+ # # nest hash parameters
36
+ # RestClient.post 'http://example.com/resource', :nested => { :param1 => 'one' }
37
+ #
38
+ # # POST and PUT with raw payloads
39
+ # RestClient.post 'http://example.com/resource', 'the post body', :content_type => 'text/plain'
40
+ # RestClient.post 'http://example.com/resource.xml', xml_doc
41
+ # RestClient.put 'http://example.com/resource.pdf', File.read('my.pdf'), :content_type => 'application/pdf'
42
+ #
43
+ # # DELETE
44
+ # RestClient.delete 'http://example.com/resource'
45
+ #
46
+ # # retreive the response http code and headers
47
+ # res = RestClient.get 'http://example.com/some.jpg'
48
+ # res.code # => 200
49
+ # res.headers[:content_type] # => 'image/jpg'
50
+ #
51
+ # # HEAD
52
+ # RestClient.head('http://example.com').headers
53
+ #
54
+ # To use with a proxy, just set RestClient.proxy to the proper http proxy:
55
+ #
56
+ # RestClient.proxy = "http://proxy.example.com/"
57
+ #
58
+ # Or inherit the proxy from the environment:
59
+ #
60
+ # RestClient.proxy = ENV['http_proxy']
61
+ #
62
+ # For live tests of RestClient, try using http://rest-test.heroku.com, which echoes back information about the rest call:
63
+ #
64
+ # >> RestClient.put 'http://rest-test.heroku.com/resource', :foo => 'baz'
65
+ # => "PUT http://rest-test.heroku.com/resource with a 7 byte payload, content type application/x-www-form-urlencoded {\"foo\"=>\"baz\"}"
66
+ #
67
+ module RestClient
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 RestClient 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
+ # Create a log that respond to << like a logger
109
+ # param can be 'stdout', 'stderr', a string (then we will log to that file) or a logger (then we return it)
110
+ def self.create_log param
111
+ if param
112
+ if param.is_a? String
113
+ if param == 'stdout'
114
+ stdout_logger = Class.new do
115
+ def << obj
116
+ STDOUT.puts obj
117
+ end
118
+ end
119
+ stdout_logger.new
120
+ elsif param == 'stderr'
121
+ stderr_logger = Class.new do
122
+ def << obj
123
+ STDERR.puts obj
124
+ end
125
+ end
126
+ stderr_logger.new
127
+ else
128
+ file_logger = Class.new do
129
+ attr_writer :target_file
130
+
131
+ def << obj
132
+ File.open(@target_file, 'a') { |f| f.puts obj }
133
+ end
134
+ end
135
+ logger = file_logger.new
136
+ logger.target_file = param
137
+ logger
138
+ end
139
+ else
140
+ param
141
+ end
142
+ end
143
+ end
144
+
145
+ @@env_log = create_log ENV['RESTCLIENT_LOG']
146
+
147
+ @@log = nil
148
+
149
+ def self.log # :nodoc:
150
+ @@env_log || @@log
151
+ end
152
+
153
+ @@before_execution_procs = []
154
+
155
+ # Add a Proc to be called before each request in executed.
156
+ # The proc parameters will be the http request and the request params.
157
+ def self.add_before_execution_proc &proc
158
+ @@before_execution_procs << proc
159
+ end
160
+
161
+ # Reset the procs to be called before each request is executed.
162
+ def self.reset_before_execution_procs
163
+ @@before_execution_procs = []
164
+ end
165
+
166
+ def self.before_execution_procs # :nodoc:
167
+ @@before_execution_procs
168
+ end
169
+
170
+ end
@@ -0,0 +1,106 @@
1
+ require 'cgi'
2
+
3
+ module RestClient
4
+
5
+ module AbstractResponse
6
+
7
+ attr_reader :net_http_res, :args
8
+
9
+ # HTTP status code
10
+ def code
11
+ @code ||= @net_http_res.code.to_i
12
+ end
13
+
14
+ # A hash of the headers, beautified with symbols and underscores.
15
+ # e.g. "Content-type" will become :content_type.
16
+ def headers
17
+ @headers ||= AbstractResponse.beautify_headers(@net_http_res.to_hash)
18
+ end
19
+
20
+ # The raw headers.
21
+ def raw_headers
22
+ @raw_headers ||= @net_http_res.to_hash
23
+ end
24
+
25
+ # Hash of cookies extracted from response headers
26
+ def cookies
27
+ @cookies ||= (self.headers[:set_cookie] || {}).inject({}) do |out, cookie_content|
28
+ out.merge parse_cookie(cookie_content)
29
+ end
30
+ end
31
+
32
+ # Return the default behavior corresponding to the response code:
33
+ # 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
34
+ def return! request = nil, result = nil, & block
35
+ if (200..207).include? code
36
+ self
37
+ elsif [301, 302, 307].include? code
38
+ unless [:get, :head].include? args[:method]
39
+ raise Exceptions::EXCEPTIONS_MAP[code].new(self, code)
40
+ else
41
+ follow_redirection(request, result, & block)
42
+ end
43
+ elsif code == 303
44
+ args[:method] = :get
45
+ args.delete :payload
46
+ follow_redirection(request, result, & block)
47
+ elsif Exceptions::EXCEPTIONS_MAP[code]
48
+ raise Exceptions::EXCEPTIONS_MAP[code].new(self, code)
49
+ else
50
+ raise RequestFailed.new(self, code)
51
+ end
52
+ end
53
+
54
+ def to_i
55
+ code
56
+ end
57
+
58
+ def description
59
+ "#{code} #{STATUSES[code]} | #{(headers[:content_type] || '').gsub(/;.*$/, '')} #{size} bytes\n"
60
+ end
61
+
62
+ # Follow a redirection
63
+ def follow_redirection request = nil, result = nil, & block
64
+ url = headers[:location]
65
+ if url !~ /^http/
66
+ url = URI.parse(args[:url]).merge(url).to_s
67
+ end
68
+ args[:url] = url
69
+ if request
70
+ if request.max_redirects == 0
71
+ raise MaxRedirectsReached
72
+ 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
81
+ end
82
+ Request.execute args, &block
83
+ end
84
+
85
+ def AbstractResponse.beautify_headers(headers)
86
+ headers.inject({}) do |out, (key, value)|
87
+ out[key.gsub(/-/, '_').downcase.to_sym] = %w{ set-cookie }.include?(key.downcase) ? value : value.first
88
+ out
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ # Parse a cookie value and return its content in an Hash
95
+ def parse_cookie cookie_content
96
+ out = {}
97
+ CGI::Cookie::parse(cookie_content).each do |key, cookie|
98
+ unless ['expires', 'path'].include? key
99
+ out[CGI::escape(key)] = cookie.value[0] ? (CGI::escape(cookie.value[0]) || '') : ''
100
+ end
101
+ end
102
+ out
103
+ end
104
+ end
105
+
106
+ end