rest-client 1.6.0

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.

@@ -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,161 @@
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/exceptions'
13
+ require File.dirname(__FILE__) + '/restclient/request'
14
+ require File.dirname(__FILE__) + '/restclient/abstract_response'
15
+ require File.dirname(__FILE__) + '/restclient/response'
16
+ require File.dirname(__FILE__) + '/restclient/raw_response'
17
+ require File.dirname(__FILE__) + '/restclient/resource'
18
+ require File.dirname(__FILE__) + '/restclient/payload'
19
+ require File.dirname(__FILE__) + '/restclient/net_http_ext'
20
+
21
+ # This module's static methods are the entry point for using the REST client.
22
+ #
23
+ # # GET
24
+ # xml = RestClient.get 'http://example.com/resource'
25
+ # jpg = RestClient.get 'http://example.com/resource', :accept => 'image/jpg'
26
+ #
27
+ # # authentication and SSL
28
+ # RestClient.get 'https://user:password@example.com/private/resource'
29
+ #
30
+ # # POST or PUT with a hash sends parameters as a urlencoded form body
31
+ # RestClient.post 'http://example.com/resource', :param1 => 'one'
32
+ #
33
+ # # nest hash parameters
34
+ # RestClient.post 'http://example.com/resource', :nested => { :param1 => 'one' }
35
+ #
36
+ # # POST and PUT with raw payloads
37
+ # RestClient.post 'http://example.com/resource', 'the post body', :content_type => 'text/plain'
38
+ # RestClient.post 'http://example.com/resource.xml', xml_doc
39
+ # RestClient.put 'http://example.com/resource.pdf', File.read('my.pdf'), :content_type => 'application/pdf'
40
+ #
41
+ # # DELETE
42
+ # RestClient.delete 'http://example.com/resource'
43
+ #
44
+ # # retreive the response http code and headers
45
+ # res = RestClient.get 'http://example.com/some.jpg'
46
+ # res.code # => 200
47
+ # res.headers[:content_type] # => 'image/jpg'
48
+ #
49
+ # # HEAD
50
+ # RestClient.head('http://example.com').headers
51
+ #
52
+ # To use with a proxy, just set RestClient.proxy to the proper http proxy:
53
+ #
54
+ # RestClient.proxy = "http://proxy.example.com/"
55
+ #
56
+ # Or inherit the proxy from the environment:
57
+ #
58
+ # RestClient.proxy = ENV['http_proxy']
59
+ #
60
+ # For live tests of RestClient, try using http://rest-test.heroku.com, which echoes back information about the rest call:
61
+ #
62
+ # >> RestClient.put 'http://rest-test.heroku.com/resource', :foo => 'baz'
63
+ # => "PUT http://rest-test.heroku.com/resource with a 7 byte payload, content type application/x-www-form-urlencoded {\"foo\"=>\"baz\"}"
64
+ #
65
+ module RestClient
66
+
67
+ def self.get(url, headers={}, &block)
68
+ Request.execute(:method => :get, :url => url, :headers => headers, &block)
69
+ end
70
+
71
+ def self.post(url, payload, headers={}, &block)
72
+ Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers, &block)
73
+ end
74
+
75
+ def self.put(url, payload, headers={}, &block)
76
+ Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers, &block)
77
+ end
78
+
79
+ def self.delete(url, headers={}, &block)
80
+ Request.execute(:method => :delete, :url => url, :headers => headers, &block)
81
+ end
82
+
83
+ def self.head(url, headers={}, &block)
84
+ Request.execute(:method => :head, :url => url, :headers => headers, &block)
85
+ end
86
+
87
+ class << self
88
+ attr_accessor :proxy
89
+ end
90
+
91
+ # Setup the log for RestClient calls.
92
+ # Value should be a logger but can can be stdout, stderr, or a filename.
93
+ # You can also configure logging by the environment variable RESTCLIENT_LOG.
94
+ def self.log= log
95
+ @@log = create_log log
96
+ end
97
+
98
+ def self.version
99
+ version_path = File.dirname(__FILE__) + "/../VERSION"
100
+ return File.read(version_path).chomp if File.file?(version_path)
101
+ "0.0.0"
102
+ end
103
+
104
+ # Create a log that respond to << like a logger
105
+ # param can be 'stdout', 'stderr', a string (then we will log to that file) or a logger (then we return it)
106
+ def self.create_log param
107
+ if param
108
+ if param.is_a? String
109
+ if param == 'stdout'
110
+ stdout_logger = Class.new do
111
+ def << obj
112
+ STDOUT.puts obj
113
+ end
114
+ end
115
+ stdout_logger.new
116
+ elsif param == 'stderr'
117
+ stderr_logger = Class.new do
118
+ def << obj
119
+ STDERR.puts obj
120
+ end
121
+ end
122
+ stderr_logger.new
123
+ else
124
+ file_logger = Class.new do
125
+ attr_writer :target_file
126
+
127
+ def << obj
128
+ File.open(@target_file, 'a') { |f| f.puts obj }
129
+ end
130
+ end
131
+ logger = file_logger.new
132
+ logger.target_file = param
133
+ logger
134
+ end
135
+ else
136
+ param
137
+ end
138
+ end
139
+ end
140
+
141
+ @@env_log = create_log ENV['RESTCLIENT_LOG']
142
+
143
+ @@log = nil
144
+
145
+ def self.log # :nodoc:
146
+ @@env_log || @@log
147
+ end
148
+
149
+ @@before_execution_procs = []
150
+
151
+ # Add a Proc to be called before each request in executed.
152
+ # The proc parameters will be the http request and the request params.
153
+ def self.add_before_execution_proc &proc
154
+ @@before_execution_procs << proc
155
+ end
156
+
157
+ def self.before_execution_procs # :nodoc:
158
+ @@before_execution_procs
159
+ end
160
+
161
+ end
@@ -0,0 +1,89 @@
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
+ CGI::Cookie::parse(cookie_content).each do |key, cookie|
29
+ unless ['expires', 'path'].include? key
30
+ out[CGI::escape(key)] = cookie.value[0] ? (CGI::escape(cookie.value[0]) || '') : ''
31
+ end
32
+ end
33
+ out
34
+ end
35
+ end
36
+
37
+ # Return the default behavior corresponding to the response 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
+ self
42
+ elsif [301, 302, 307].include? code
43
+ unless [:get, :head].include? args[:method]
44
+ raise Exceptions::EXCEPTIONS_MAP[code], self
45
+ else
46
+ follow_redirection(request, &block)
47
+ end
48
+ elsif code == 303
49
+ args[:method] = :get
50
+ args.delete :payload
51
+ follow_redirection(request, &block)
52
+ elsif Exceptions::EXCEPTIONS_MAP[code]
53
+ raise Exceptions::EXCEPTIONS_MAP[code], self
54
+ else
55
+ raise RequestFailed, self
56
+ end
57
+ end
58
+
59
+ def to_i
60
+ code
61
+ end
62
+
63
+ def description
64
+ "#{code} #{STATUSES[code]} | #{(headers[:content_type] || '').gsub(/;.*$/, '')} #{size} bytes\n"
65
+ end
66
+
67
+ # Follow a redirection
68
+ def follow_redirection request = nil, &block
69
+ url = headers[:location]
70
+ if url !~ /^http/
71
+ url = URI.parse(args[:url]).merge(url).to_s
72
+ end
73
+ args[:url] = url
74
+ if request
75
+ args[:password] = request.password
76
+ args[:user] = request.user
77
+ args[:headers] = request.headers
78
+ end
79
+ Request.execute args, &block
80
+ end
81
+
82
+ def AbstractResponse.beautify_headers(headers)
83
+ headers.inject({}) do |out, (key, value)|
84
+ out[key.gsub(/-/, '_').downcase.to_sym] = %w{ set-cookie }.include?(key.downcase) ? value : value.first
85
+ out
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,172 @@
1
+ module RestClient
2
+
3
+ STATUSES = {100 => 'Continue',
4
+ 101 => 'Switching Protocols',
5
+ 102 => 'Processing', #WebDAV
6
+
7
+ 200 => 'OK',
8
+ 201 => 'Created',
9
+ 202 => 'Accepted',
10
+ 203 => 'Non-Authoritative Information', # http/1.1
11
+ 204 => 'No Content',
12
+ 205 => 'Reset Content',
13
+ 206 => 'Partial Content',
14
+ 207 => 'Multi-Status', #WebDAV
15
+
16
+ 300 => 'Multiple Choices',
17
+ 301 => 'Moved Permanently',
18
+ 302 => 'Found',
19
+ 303 => 'See Other', # http/1.1
20
+ 304 => 'Not Modified',
21
+ 305 => 'Use Proxy', # http/1.1
22
+ 306 => 'Switch Proxy', # no longer used
23
+ 307 => 'Temporary Redirect', # http/1.1
24
+
25
+ 400 => 'Bad Request',
26
+ 401 => 'Unauthorized',
27
+ 402 => 'Payment Required',
28
+ 403 => 'Forbidden',
29
+ 404 => 'Resource Not Found',
30
+ 405 => 'Method Not Allowed',
31
+ 406 => 'Not Acceptable',
32
+ 407 => 'Proxy Authentication Required',
33
+ 408 => 'Request Timeout',
34
+ 409 => 'Conflict',
35
+ 410 => 'Gone',
36
+ 411 => 'Length Required',
37
+ 412 => 'Precondition Failed',
38
+ 413 => 'Request Entity Too Large',
39
+ 414 => 'Request-URI Too Long',
40
+ 415 => 'Unsupported Media Type',
41
+ 416 => 'Requested Range Not Satisfiable',
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
+
53
+ 500 => 'Internal Server Error',
54
+ 501 => 'Not Implemented',
55
+ 502 => 'Bad Gateway',
56
+ 503 => 'Service Unavailable',
57
+ 504 => 'Gateway Timeout',
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'}
63
+
64
+ # Compatibility : make the Response act like a Net::HTTPResponse when needed
65
+ module ResponseForException
66
+ def method_missing symbol, *args
67
+ if net_http_res.respond_to? symbol
68
+ warn "[warning] The response contained in an RestClient::Exception is now a RestClient::Response instead of a Net::HTTPResponse, please update your code"
69
+ net_http_res.send symbol, *args
70
+ else
71
+ super
72
+ end
73
+ end
74
+ end
75
+
76
+ # This is the base RestClient exception class. Rescue it if you want to
77
+ # catch any exception that your request might raise
78
+ # You can get the status code by e.http_code, or see anything about the
79
+ # response via e.response.
80
+ # For example, the entire result body (which is
81
+ # probably an HTML error page) is e.response.
82
+ class Exception < RuntimeError
83
+ attr_accessor :message, :response
84
+
85
+ def initialize response = nil
86
+ @response = response
87
+
88
+ # compatibility: this make the exception behave like a Net::HTTPResponse
89
+ response.extend ResponseForException if response
90
+ end
91
+
92
+ def http_code
93
+ # return integer for compatibility
94
+ @response.code.to_i if @response
95
+ end
96
+
97
+ def http_body
98
+ @response.body if @response
99
+ end
100
+
101
+ def inspect
102
+ "#{self.class} : #{http_code} #{message}"
103
+ end
104
+
105
+ end
106
+
107
+ # Compatibility
108
+ class ExceptionWithResponse < Exception
109
+ end
110
+
111
+ # The request failed with an error code not managed by the code
112
+ class RequestFailed < ExceptionWithResponse
113
+
114
+ def message
115
+ "HTTP status code #{http_code}"
116
+ end
117
+
118
+ def to_s
119
+ message
120
+ end
121
+ end
122
+
123
+ # We will a create an exception for each status code, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
124
+ module Exceptions
125
+ # Map http status codes to the corresponding exception class
126
+ EXCEPTIONS_MAP = {}
127
+ end
128
+
129
+ STATUSES.each_pair do |code, message|
130
+
131
+ # Compatibility
132
+ superclass = ([304, 401, 404].include? code) ? ExceptionWithResponse : RequestFailed
133
+ klass = Class.new(superclass) do
134
+ send(:define_method, :message) {message}
135
+ end
136
+ klass_constant = const_set message.delete(' \-\''), klass
137
+ Exceptions::EXCEPTIONS_MAP[code] = klass_constant
138
+ end
139
+
140
+ # A redirect was encountered; caught by execute to retry with the new url.
141
+ class Redirect < Exception
142
+
143
+ message = 'Redirect'
144
+
145
+ attr_accessor :url
146
+
147
+ def initialize(url)
148
+ @url = url
149
+ end
150
+ end
151
+
152
+ # The server broke the connection prior to the request completing. Usually
153
+ # this means it crashed, or sometimes that your network connection was
154
+ # severed before it could complete.
155
+ class ServerBrokeConnection < Exception
156
+ message = 'Server broke connection'
157
+ end
158
+
159
+ class SSLCertificateNotVerified < Exception
160
+ def initialize(message)
161
+ super(nil)
162
+ self.message = message
163
+ end
164
+ end
165
+ end
166
+
167
+ # backwards compatibility
168
+ class RestClient::Request
169
+ Redirect = RestClient::Redirect
170
+ Unauthorized = RestClient::Unauthorized
171
+ RequestFailed = RestClient::RequestFailed
172
+ end
@@ -0,0 +1,21 @@
1
+ #
2
+ # Replace the request method in Net::HTTP to sniff the body type
3
+ # and set the stream if appropriate
4
+ #
5
+ # Taken from:
6
+ # http://www.missiondata.com/blog/ruby/29/streaming-data-to-s3-with-ruby/
7
+
8
+ module Net
9
+ class HTTP
10
+ alias __request__ request
11
+
12
+ def request(req, body=nil, &block)
13
+ if body != nil && body.respond_to?(:read)
14
+ req.body_stream = body
15
+ return __request__(req, nil, &block)
16
+ else
17
+ return __request__(req, body, &block)
18
+ end
19
+ end
20
+ end
21
+ end