rest-client 1.1.0 → 1.2.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.

Potentially problematic release.


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

@@ -8,10 +8,13 @@ of specifying actions: get, put, post, delete.
8
8
  require 'rest_client'
9
9
 
10
10
  RestClient.get 'http://example.com/resource'
11
+
11
12
  RestClient.get 'https://user:password@example.com/private/resource'
12
13
 
13
14
  RestClient.post 'http://example.com/resource', :param1 => 'one', :nested => { :param2 => 'two' }
14
15
 
16
+ RestClient.post "http://example.com/resource", { 'x' => 1 }.to_json, :content_type => :json, :accept => :json
17
+
15
18
  RestClient.delete 'http://example.com/resource'
16
19
 
17
20
  == Multipart
data/Rakefile CHANGED
@@ -7,8 +7,8 @@ Jeweler::Tasks.new do |s|
7
7
  s.description = "A simple REST client for Ruby, inspired by the Sinatra microframework style of specifying actions: get, put, post, delete."
8
8
  s.summary = "Simple REST client for Ruby, inspired by microframework syntax for specifying actions."
9
9
  s.author = "Adam Wiggins"
10
- s.email = "adam@heroku.com"
11
- s.homepage = "http://rest-client.heroku.com/"
10
+ s.email = "rest.client@librelist.com"
11
+ s.homepage = "http://github.com/archiloque/rest-client"
12
12
  s.rubyforge_project = "rest-client"
13
13
  s.has_rdoc = true
14
14
  s.files = FileList["[A-Z]*", "{bin,lib,spec}/**/*"]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.2.0
@@ -3,10 +3,10 @@ require 'zlib'
3
3
  require 'stringio'
4
4
 
5
5
  begin
6
- require 'net/https'
6
+ require 'net/https'
7
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"
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
10
  end
11
11
 
12
12
  require File.dirname(__FILE__) + '/restclient/request'
@@ -63,41 +63,42 @@ require File.dirname(__FILE__) + '/restclient/net_http_ext'
63
63
  # => "PUT http://rest-test.heroku.com/resource with a 7 byte payload, content type application/x-www-form-urlencoded {\"foo\"=>\"baz\"}"
64
64
  #
65
65
  module RestClient
66
- def self.get(url, headers={})
67
- Request.execute(:method => :get, :url => url, :headers => headers)
68
- end
69
66
 
70
- def self.post(url, payload, headers={})
71
- Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers)
72
- end
67
+ def self.get(url, headers={})
68
+ Request.execute(:method => :get, :url => url, :headers => headers)
69
+ end
73
70
 
74
- def self.put(url, payload, headers={})
75
- Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers)
76
- end
71
+ def self.post(url, payload, headers={})
72
+ Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers)
73
+ end
77
74
 
78
- def self.delete(url, headers={})
79
- Request.execute(:method => :delete, :url => url, :headers => headers)
80
- end
75
+ def self.put(url, payload, headers={})
76
+ Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers)
77
+ end
81
78
 
82
- def self.head(url, headers={})
83
- Request.execute(:method => :head, :url => url, :headers => headers)
84
- end
79
+ def self.delete(url, headers={})
80
+ Request.execute(:method => :delete, :url => url, :headers => headers)
81
+ end
85
82
 
86
- class << self
87
- attr_accessor :proxy
88
- end
83
+ def self.head(url, headers={})
84
+ Request.execute(:method => :head, :url => url, :headers => headers)
85
+ end
89
86
 
90
- # Print log of RestClient calls. Value can be stdout, stderr, or a filename.
91
- # You can also configure logging by the environment variable RESTCLIENT_LOG.
92
- def self.log=(log)
93
- @@log = log
94
- end
87
+ class << self
88
+ attr_accessor :proxy
89
+ end
90
+
91
+ # Print log of RestClient calls. Value can be stdout, stderr, or a filename.
92
+ # You can also configure logging by the environment variable RESTCLIENT_LOG.
93
+ def self.log=(log)
94
+ @@log = log
95
+ end
95
96
 
96
- def self.log # :nodoc:
97
- return ENV['RESTCLIENT_LOG'] if ENV['RESTCLIENT_LOG']
98
- return @@log if defined? @@log
99
- nil
100
- end
97
+ def self.log # :nodoc:
98
+ return ENV['RESTCLIENT_LOG'] if ENV['RESTCLIENT_LOG']
99
+ return @@log if defined? @@log
100
+ nil
101
+ end
101
102
 
102
103
  def self.version
103
104
  version_path = File.dirname(__FILE__) + "/../VERSION"
@@ -1,88 +1,89 @@
1
1
  module RestClient
2
- # This is the base RestClient exception class. Rescue it if you want to
3
- # catch any exception that your request might raise
4
- class Exception < RuntimeError
5
- def message(default=nil)
6
- self.class::ErrorMessage
7
- end
8
- end
2
+ # This is the base RestClient exception class. Rescue it if you want to
3
+ # catch any exception that your request might raise
4
+ class Exception < RuntimeError
5
+ def message(default=nil)
6
+ self.class::ErrorMessage
7
+ end
8
+ end
9
9
 
10
- # Base RestClient exception when there's a response available
11
- class ExceptionWithResponse < Exception
12
- attr_accessor :response
10
+ # Base RestClient exception when there's a response available
11
+ class ExceptionWithResponse < Exception
12
+ attr_accessor :response
13
13
 
14
- def initialize(response=nil)
15
- @response = response
16
- end
14
+ def initialize(response=nil)
15
+ @response = response
16
+ end
17
17
 
18
- def http_code
19
- @response.code.to_i if @response
20
- end
18
+ def http_code
19
+ @response.code.to_i if @response
20
+ end
21
21
 
22
- def http_body
23
- RestClient::Request.decode(@response['content-encoding'], @response.body) if @response
24
- end
25
- end
22
+ def http_body
23
+ RestClient::Request.decode(@response['content-encoding'], @response.body) if @response
24
+ end
25
+ end
26
26
 
27
- # A redirect was encountered; caught by execute to retry with the new url.
28
- class Redirect < Exception
29
- ErrorMessage = "Redirect"
27
+ # A redirect was encountered; caught by execute to retry with the new url.
28
+ class Redirect < Exception
29
+ ErrorMessage = "Redirect"
30
30
 
31
- attr_accessor :url
32
- def initialize(url)
33
- @url = url
34
- end
35
- end
31
+ attr_accessor :url
36
32
 
37
- class NotModified < ExceptionWithResponse
38
- ErrorMessage = 'NotModified'
39
- end
33
+ def initialize(url)
34
+ @url = url
35
+ end
36
+ end
40
37
 
41
- # Authorization is required to access the resource specified.
42
- class Unauthorized < ExceptionWithResponse
43
- ErrorMessage = 'Unauthorized'
44
- end
38
+ class NotModified < ExceptionWithResponse
39
+ ErrorMessage = 'NotModified'
40
+ end
45
41
 
46
- # No resource was found at the given URL.
47
- class ResourceNotFound < ExceptionWithResponse
48
- ErrorMessage = 'Resource not found'
49
- end
42
+ # Authorization is required to access the resource specified.
43
+ class Unauthorized < ExceptionWithResponse
44
+ ErrorMessage = 'Unauthorized'
45
+ end
50
46
 
51
- # The server broke the connection prior to the request completing. Usually
52
- # this means it crashed, or sometimes that your network connection was
53
- # severed before it could complete.
54
- class ServerBrokeConnection < Exception
55
- ErrorMessage = 'Server broke connection'
56
- end
47
+ # No resource was found at the given URL.
48
+ class ResourceNotFound < ExceptionWithResponse
49
+ ErrorMessage = 'Resource not found'
50
+ end
57
51
 
58
- # The server took too long to respond.
59
- class RequestTimeout < Exception
60
- ErrorMessage = 'Request timed out'
61
- end
52
+ # The server broke the connection prior to the request completing. Usually
53
+ # this means it crashed, or sometimes that your network connection was
54
+ # severed before it could complete.
55
+ class ServerBrokeConnection < Exception
56
+ ErrorMessage = 'Server broke connection'
57
+ end
62
58
 
63
- # The request failed, meaning the remote HTTP server returned a code other
64
- # than success, unauthorized, or redirect.
65
- #
66
- # The exception message attempts to extract the error from the XML, using
67
- # format returned by Rails: <errors><error>some message</error></errors>
68
- #
69
- # You can get the status code by e.http_code, or see anything about the
70
- # response via e.response. For example, the entire result body (which is
71
- # probably an HTML error page) is e.response.body.
72
- class RequestFailed < ExceptionWithResponse
73
- def message
74
- "HTTP status code #{http_code}"
75
- end
59
+ # The server took too long to respond.
60
+ class RequestTimeout < Exception
61
+ ErrorMessage = 'Request timed out'
62
+ end
76
63
 
77
- def to_s
78
- message
79
- end
80
- end
64
+ # The request failed, meaning the remote HTTP server returned a code other
65
+ # than success, unauthorized, or redirect.
66
+ #
67
+ # The exception message attempts to extract the error from the XML, using
68
+ # format returned by Rails: <errors><error>some message</error></errors>
69
+ #
70
+ # You can get the status code by e.http_code, or see anything about the
71
+ # response via e.response. For example, the entire result body (which is
72
+ # probably an HTML error page) is e.response.body.
73
+ class RequestFailed < ExceptionWithResponse
74
+ def message
75
+ "HTTP status code #{http_code}"
76
+ end
77
+
78
+ def to_s
79
+ message
80
+ end
81
+ end
81
82
  end
82
83
 
83
84
  # backwards compatibility
84
85
  class RestClient::Request
85
- Redirect = RestClient::Redirect
86
- Unauthorized = RestClient::Unauthorized
87
- RequestFailed = RestClient::RequestFailed
86
+ Redirect = RestClient::Redirect
87
+ Unauthorized = RestClient::Unauthorized
88
+ RequestFailed = RestClient::RequestFailed
88
89
  end
@@ -1,48 +1,48 @@
1
1
  module RestClient
2
- module Mixin
3
- module Response
4
- attr_reader :net_http_res
2
+ module Mixin
3
+ module Response
4
+ attr_reader :net_http_res
5
5
 
6
- # HTTP status code, always 200 since RestClient throws exceptions for
7
- # other codes.
8
- def code
9
- @code ||= @net_http_res.code.to_i
10
- end
6
+ # HTTP status code, always 200 since RestClient throws exceptions for
7
+ # other codes.
8
+ def code
9
+ @code ||= @net_http_res.code.to_i
10
+ end
11
11
 
12
- # A hash of the headers, beautified with symbols and underscores.
13
- # e.g. "Content-type" will become :content_type.
14
- def headers
15
- @headers ||= self.class.beautify_headers(@net_http_res.to_hash)
16
- end
12
+ # A hash of the headers, beautified with symbols and underscores.
13
+ # e.g. "Content-type" will become :content_type.
14
+ def headers
15
+ @headers ||= self.class.beautify_headers(@net_http_res.to_hash)
16
+ end
17
17
 
18
- # The raw headers.
19
- def raw_headers
20
- @raw_headers ||= @net_http_res.to_hash
21
- end
18
+ # The raw headers.
19
+ def raw_headers
20
+ @raw_headers ||= @net_http_res.to_hash
21
+ end
22
22
 
23
- # Hash of cookies extracted from response headers
24
- def cookies
25
- @cookies ||= (self.headers[:set_cookie] || "").split('; ').inject({}) do |out, raw_c|
26
- key, val = raw_c.split('=')
27
- unless %w(expires domain path secure).member?(key)
28
- out[key] = val
29
- end
30
- out
31
- end
32
- end
23
+ # Hash of cookies extracted from response headers
24
+ def cookies
25
+ @cookies ||= (self.headers[:set_cookie] || "").split('; ').inject({}) do |out, raw_c|
26
+ key, val = raw_c.split('=')
27
+ unless %w(expires domain path secure).member?(key)
28
+ out[key] = val
29
+ end
30
+ out
31
+ end
32
+ end
33
33
 
34
- def self.included(receiver)
35
- receiver.extend(RestClient::Mixin::Response::ClassMethods)
36
- end
34
+ def self.included(receiver)
35
+ receiver.extend(RestClient::Mixin::Response::ClassMethods)
36
+ end
37
37
 
38
- module ClassMethods
39
- def beautify_headers(headers)
40
- headers.inject({}) do |out, (key, value)|
41
- out[key.gsub(/-/, '_').downcase.to_sym] = value.first
42
- out
43
- end
44
- end
45
- end
46
- end
47
- end
38
+ module ClassMethods
39
+ def beautify_headers(headers)
40
+ headers.inject({}) do |out, (key, value)|
41
+ out[key.gsub(/-/, '_').downcase.to_sym] = value.first
42
+ out
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
48
  end
@@ -6,16 +6,16 @@
6
6
  # http://www.missiondata.com/blog/ruby/29/streaming-data-to-s3-with-ruby/
7
7
 
8
8
  module Net
9
- class HTTP
10
- alias __request__ request
9
+ class HTTP
10
+ alias __request__ request
11
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
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
21
  end
@@ -1,171 +1,178 @@
1
- require "tempfile"
2
- require "stringio"
3
- require "mime/types"
1
+ require 'tempfile'
2
+ require 'stringio'
3
+ require 'mime/types'
4
4
 
5
5
  module RestClient
6
- module Payload
7
- extend self
8
-
9
- def generate(params)
10
- if params.is_a?(String)
11
- Base.new(params)
12
- elsif params
13
- if params.delete(:multipart) == true || has_file?(params)
14
- Multipart.new(params)
15
- else
16
- UrlEncoded.new(params)
17
- end
18
- else
19
- nil
20
- end
21
- end
22
-
23
- def has_file?(params)
24
- params.any? do |_, v|
25
- case v
26
- when Hash
27
- has_file?(v)
28
- else
29
- v.respond_to?(:path) && v.respond_to?(:read)
30
- end
31
- end
32
- end
33
-
34
- class Base
35
- def initialize(params)
36
- build_stream(params)
37
- end
38
-
39
- def build_stream(params)
40
- @stream = StringIO.new(params)
41
- @stream.seek(0)
42
- end
43
-
44
- def read(bytes=nil)
45
- @stream.read(bytes)
46
- end
47
- alias :to_s :read
48
-
49
- def escape(v)
50
- URI.escape(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
51
- end
52
-
53
- # Flatten parameters by converting hashes of hashes to flat hashes
54
- # {keys1 => {keys2 => value}} will be transformed into {keys1[key2] => value}
55
- def flatten_params(params, parent_key = nil)
56
- result = {}
57
- params.keys.map do |key|
58
- calculated_key = parent_key ? "#{parent_key}[#{escape key}]" : escape(key)
59
- value = params[key]
60
- if value.is_a? Hash
61
- result.merge!(flatten_params(value, calculated_key))
62
- else
63
- result[calculated_key] = value
64
- end
65
- end
66
- result
67
- end
68
-
69
- def headers
70
- { 'Content-Length' => size.to_s }
71
- end
72
-
73
- def size
74
- @stream.size
75
- end
76
- alias :length :size
77
-
78
- def close
79
- @stream.close
80
- end
81
-
82
- def inspect
83
- result = to_s.inspect
84
- @stream.seek(0)
85
- result
86
- end
87
- end
88
-
89
- class UrlEncoded < Base
90
- def build_stream(params = nil)
91
- @stream = StringIO.new(flatten_params(params).map do |k,v|
92
- "#{k}=#{escape(v)}"
93
- end.join("&"))
94
- @stream.seek(0)
95
- end
96
-
97
- def headers
98
- super.merge({ 'Content-Type' => 'application/x-www-form-urlencoded' })
99
- end
100
- end
101
-
102
- class Multipart < Base
103
- EOL = "\r\n"
104
-
105
- def build_stream(params)
106
- b = "--#{boundary}"
107
-
108
- @stream = Tempfile.new("RESTClient.Stream.#{rand(1000)}")
109
- @stream.write(b + EOL)
110
-
111
- if params.is_a? Hash
112
- x = flatten_params(params).to_a
113
- else
114
- x = params.to_a
115
- end
116
-
117
- last_index = x.length - 1
118
- x.each_with_index do |a, index|
119
- k, v = *a
120
- if v.respond_to?(:read) && v.respond_to?(:path)
121
- create_file_field(@stream, k,v)
122
- else
123
- create_regular_field(@stream, k,v)
124
- end
125
- @stream.write(EOL + b)
126
- @stream.write(EOL) unless last_index == index
127
- end
128
- @stream.write('--')
129
- @stream.write(EOL)
130
- @stream.seek(0)
131
- end
132
-
133
- def create_regular_field(s, k, v)
134
- s.write("Content-Disposition: multipart/form-data; name=\"#{k}\"")
135
- s.write(EOL)
136
- s.write(EOL)
137
- s.write(v)
138
- end
139
-
140
- def create_file_field(s, k, v)
141
- begin
142
- s.write("Content-Disposition: multipart/form-data; name=\"#{k}\"; filename=\"#{v.respond_to?(:original_filename) ? v.original_filename : File.basename(v.path)}\"#{EOL}")
143
- s.write("Content-Type: #{v.respond_to?(:content_type) ? v.content_type : mime_for(v.path)}#{EOL}")
144
- s.write(EOL)
145
- while data = v.read(8124)
146
- s.write(data)
147
- end
148
- ensure
149
- v.close
150
- end
151
- end
152
-
153
- def mime_for(path)
154
- mime = MIME::Types.type_for path
155
- mime.empty? ? 'text/plain' : mime[0].content_type
156
- end
157
-
158
- def boundary
159
- @boundary ||= rand(1_000_000).to_s
160
- end
161
-
162
- def headers
163
- super.merge({'Content-Type' => %Q{multipart/form-data; boundary="#{boundary}"}})
164
- end
165
-
166
- def close
167
- @stream.close
168
- end
169
- end
170
- end
6
+ module Payload
7
+ extend self
8
+
9
+ def generate(params)
10
+ if params.is_a?(String)
11
+ Base.new(params)
12
+ elsif params
13
+ if params.delete(:multipart) == true || has_file?(params)
14
+ Multipart.new(params)
15
+ else
16
+ UrlEncoded.new(params)
17
+ end
18
+ else
19
+ nil
20
+ end
21
+ end
22
+
23
+ def has_file?(params)
24
+ params.any? do |_, v|
25
+ case v
26
+ when Hash
27
+ has_file?(v)
28
+ else
29
+ v.respond_to?(:path) && v.respond_to?(:read)
30
+ end
31
+ end
32
+ end
33
+
34
+ class Base
35
+ def initialize(params)
36
+ build_stream(params)
37
+ end
38
+
39
+ def build_stream(params)
40
+ @stream = StringIO.new(params)
41
+ @stream.seek(0)
42
+ end
43
+
44
+ def read(bytes=nil)
45
+ @stream.read(bytes)
46
+ end
47
+
48
+ alias :to_s :read
49
+
50
+ def escape(v)
51
+ URI.escape(v.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
52
+ end
53
+
54
+ # Flatten parameters by converting hashes of hashes to flat hashes
55
+ # {keys1 => {keys2 => value}} will be transformed into {keys1[key2] => value}
56
+ def flatten_params(params, parent_key = nil)
57
+ result = {}
58
+ params.keys.map do |key|
59
+ calculated_key = parent_key ? "#{parent_key}[#{escape key}]" : escape(key)
60
+ value = params[key]
61
+ if value.is_a? Hash
62
+ result.merge!(flatten_params(value, calculated_key))
63
+ else
64
+ result[calculated_key] = value
65
+ end
66
+ end
67
+ result
68
+ end
69
+
70
+ def headers
71
+ { 'Content-Length' => size.to_s }
72
+ end
73
+
74
+ def size
75
+ @stream.size
76
+ end
77
+
78
+ alias :length :size
79
+
80
+ def close
81
+ @stream.close
82
+ end
83
+
84
+ def inspect
85
+ result = to_s.inspect
86
+ @stream.seek(0)
87
+ result
88
+ end
89
+
90
+ def short_inspect
91
+ (size > 100 ? "#{size} byte length" : inspect)
92
+ end
93
+
94
+ end
95
+
96
+ class UrlEncoded < Base
97
+ def build_stream(params = nil)
98
+ @stream = StringIO.new(flatten_params(params).map do |k, v|
99
+ "#{k}=#{escape(v)}"
100
+ end.join("&"))
101
+ @stream.seek(0)
102
+ end
103
+
104
+ def headers
105
+ super.merge({ 'Content-Type' => 'application/x-www-form-urlencoded' })
106
+ end
107
+ end
108
+
109
+ class Multipart < Base
110
+ EOL = "\r\n"
111
+
112
+ def build_stream(params)
113
+ b = "--#{boundary}"
114
+
115
+ @stream = Tempfile.new("RESTClient.Stream.#{rand(1000)}")
116
+ @stream.write(b + EOL)
117
+
118
+ if params.is_a? Hash
119
+ x = flatten_params(params).to_a
120
+ else
121
+ x = params.to_a
122
+ end
123
+
124
+ last_index = x.length - 1
125
+ x.each_with_index do |a, index|
126
+ k, v = *a
127
+ if v.respond_to?(:read) && v.respond_to?(:path)
128
+ create_file_field(@stream, k, v)
129
+ else
130
+ create_regular_field(@stream, k, v)
131
+ end
132
+ @stream.write(EOL + b)
133
+ @stream.write(EOL) unless last_index == index
134
+ end
135
+ @stream.write('--')
136
+ @stream.write(EOL)
137
+ @stream.seek(0)
138
+ end
139
+
140
+ def create_regular_field(s, k, v)
141
+ s.write("Content-Disposition: multipart/form-data; name=\"#{k}\"")
142
+ s.write(EOL)
143
+ s.write(EOL)
144
+ s.write(v)
145
+ end
146
+
147
+ def create_file_field(s, k, v)
148
+ begin
149
+ s.write("Content-Disposition: multipart/form-data; name=\"#{k}\"; filename=\"#{v.respond_to?(:original_filename) ? v.original_filename : File.basename(v.path)}\"#{EOL}")
150
+ s.write("Content-Type: #{v.respond_to?(:content_type) ? v.content_type : mime_for(v.path)}#{EOL}")
151
+ s.write(EOL)
152
+ while data = v.read(8124)
153
+ s.write(data)
154
+ end
155
+ ensure
156
+ v.close
157
+ end
158
+ end
159
+
160
+ def mime_for(path)
161
+ mime = MIME::Types.type_for path
162
+ mime.empty? ? 'text/plain' : mime[0].content_type
163
+ end
164
+
165
+ def boundary
166
+ @boundary ||= rand(1_000_000).to_s
167
+ end
168
+
169
+ def headers
170
+ super.merge({'Content-Type' => %Q{multipart/form-data; boundary="#{boundary}"}})
171
+ end
172
+
173
+ def close
174
+ @stream.close
175
+ end
176
+ end
177
+ end
171
178
  end