rest-client 1.6.14 → 2.0.2
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.
- checksums.yaml +5 -5
- data/.gitignore +6 -6
- data/.rspec +2 -1
- data/.rubocop-disables.yml +384 -0
- data/.rubocop.yml +3 -0
- data/.travis.yml +46 -1
- data/AUTHORS +28 -5
- data/Gemfile +5 -1
- data/LICENSE +21 -0
- data/README.md +784 -0
- data/Rakefile +95 -12
- data/bin/restclient +11 -12
- data/history.md +180 -16
- data/lib/restclient.rb +25 -11
- data/lib/restclient/abstract_response.rb +171 -51
- data/lib/restclient/exceptions.rb +102 -56
- data/lib/restclient/params_array.rb +72 -0
- data/lib/restclient/payload.rb +43 -74
- data/lib/restclient/platform.rb +22 -2
- data/lib/restclient/raw_response.rb +7 -3
- data/lib/restclient/request.rb +672 -179
- data/lib/restclient/resource.rb +6 -7
- data/lib/restclient/response.rb +64 -10
- data/lib/restclient/utils.rb +235 -0
- data/lib/restclient/version.rb +2 -1
- data/lib/restclient/windows.rb +8 -0
- data/lib/restclient/windows/root_certs.rb +105 -0
- data/rest-client.gemspec +16 -11
- data/rest-client.windows.gemspec +19 -0
- data/spec/helpers.rb +22 -0
- data/spec/integration/_lib.rb +1 -0
- data/spec/integration/capath_verisign/415660c1.0 +14 -0
- data/spec/integration/capath_verisign/7651b327.0 +14 -0
- data/spec/integration/capath_verisign/README +8 -0
- data/spec/integration/capath_verisign/verisign.crt +14 -0
- data/spec/integration/httpbin_spec.rb +87 -0
- data/spec/integration/integration_spec.rb +125 -0
- data/spec/integration/request_spec.rb +72 -20
- data/spec/spec_helper.rb +29 -0
- data/spec/unit/_lib.rb +1 -0
- data/spec/unit/abstract_response_spec.rb +145 -0
- data/spec/unit/exceptions_spec.rb +108 -0
- data/spec/{master_shake.jpg → unit/master_shake.jpg} +0 -0
- data/spec/unit/params_array_spec.rb +36 -0
- data/spec/{payload_spec.rb → unit/payload_spec.rb} +73 -54
- data/spec/{raw_response_spec.rb → unit/raw_response_spec.rb} +5 -4
- data/spec/unit/request2_spec.rb +54 -0
- data/spec/unit/request_spec.rb +1250 -0
- data/spec/unit/resource_spec.rb +134 -0
- data/spec/unit/response_spec.rb +241 -0
- data/spec/unit/restclient_spec.rb +79 -0
- data/spec/unit/utils_spec.rb +147 -0
- data/spec/unit/windows/root_certs_spec.rb +22 -0
- metadata +143 -53
- data/README.rdoc +0 -300
- data/lib/restclient/net_http_ext.rb +0 -55
- data/spec/abstract_response_spec.rb +0 -85
- data/spec/base.rb +0 -13
- data/spec/exceptions_spec.rb +0 -98
- data/spec/integration_spec.rb +0 -38
- data/spec/request2_spec.rb +0 -35
- data/spec/request_spec.rb +0 -528
- data/spec/resource_spec.rb +0 -136
- data/spec/response_spec.rb +0 -169
- data/spec/restclient_spec.rb +0 -73
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'webmock/rspec'
|
2
|
+
require 'rest-client'
|
3
|
+
|
4
|
+
require_relative './helpers'
|
5
|
+
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.raise_errors_for_deprecations!
|
9
|
+
|
10
|
+
# Run specs in random order to surface order dependencies. If you find an
|
11
|
+
# order dependency and want to debug it, you can fix the order by providing
|
12
|
+
# the seed, which is printed after each run.
|
13
|
+
# --seed 1234
|
14
|
+
config.order = 'random'
|
15
|
+
|
16
|
+
# always run with ruby warnings enabled
|
17
|
+
# TODO: figure out why this is so obscenely noisy (rspec bug?)
|
18
|
+
# config.warnings = true
|
19
|
+
|
20
|
+
# add helpers
|
21
|
+
config.include Helpers, :include_helpers
|
22
|
+
|
23
|
+
config.mock_with :rspec do |mocks|
|
24
|
+
mocks.yield_receiver_to_any_instance_implementation_blocks = true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# always run with ruby warnings enabled (see above)
|
29
|
+
$VERBOSE = true
|
data/spec/unit/_lib.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative '../spec_helper'
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require_relative '_lib'
|
2
|
+
|
3
|
+
describe RestClient::AbstractResponse, :include_helpers do
|
4
|
+
|
5
|
+
class MyAbstractResponse
|
6
|
+
|
7
|
+
include RestClient::AbstractResponse
|
8
|
+
|
9
|
+
attr_accessor :size
|
10
|
+
|
11
|
+
def initialize net_http_res, request
|
12
|
+
@net_http_res = net_http_res
|
13
|
+
@request = request
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
@net_http_res = double('net http response')
|
20
|
+
@request = request_double(url: 'http://example.com', method: 'get')
|
21
|
+
@response = MyAbstractResponse.new(@net_http_res, @request)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "fetches the numeric response code" do
|
25
|
+
expect(@net_http_res).to receive(:code).and_return('200')
|
26
|
+
expect(@response.code).to eq 200
|
27
|
+
end
|
28
|
+
|
29
|
+
it "has a nice description" do
|
30
|
+
expect(@net_http_res).to receive(:to_hash).and_return({'Content-Type' => ['application/pdf']})
|
31
|
+
expect(@net_http_res).to receive(:code).and_return('200')
|
32
|
+
expect(@response.description).to eq "200 OK | application/pdf bytes\n"
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '.beautify_headers' do
|
36
|
+
it "beautifies the headers by turning the keys to symbols" do
|
37
|
+
h = RestClient::AbstractResponse.beautify_headers('content-type' => [ 'x' ])
|
38
|
+
expect(h.keys.first).to eq :content_type
|
39
|
+
end
|
40
|
+
|
41
|
+
it "beautifies the headers by turning the values to strings instead of one-element arrays" do
|
42
|
+
h = RestClient::AbstractResponse.beautify_headers('x' => [ 'text/html' ] )
|
43
|
+
expect(h.values.first).to eq 'text/html'
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'joins multiple header values by comma' do
|
47
|
+
expect(RestClient::AbstractResponse.beautify_headers(
|
48
|
+
{'My-Header' => ['one', 'two']}
|
49
|
+
)).to eq({:my_header => 'one, two'})
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'leaves set-cookie headers as array' do
|
53
|
+
expect(RestClient::AbstractResponse.beautify_headers(
|
54
|
+
{'Set-Cookie' => ['cookie1=foo', 'cookie2=bar']}
|
55
|
+
)).to eq({:set_cookie => ['cookie1=foo', 'cookie2=bar']})
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "fetches the headers" do
|
60
|
+
expect(@net_http_res).to receive(:to_hash).and_return('content-type' => [ 'text/html' ])
|
61
|
+
expect(@response.headers).to eq({ :content_type => 'text/html' })
|
62
|
+
end
|
63
|
+
|
64
|
+
it "extracts cookies from response headers" do
|
65
|
+
expect(@net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/'])
|
66
|
+
expect(@response.cookies).to eq({ 'session_id' => '1' })
|
67
|
+
end
|
68
|
+
|
69
|
+
it "extract strange cookies" do
|
70
|
+
expect(@net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=ZJ/HQVH6YE+rVkTpn0zvTQ==; path=/'])
|
71
|
+
expect(@response.headers).to eq({:set_cookie => ['session_id=ZJ/HQVH6YE+rVkTpn0zvTQ==; path=/']})
|
72
|
+
expect(@response.cookies).to eq({ 'session_id' => 'ZJ/HQVH6YE+rVkTpn0zvTQ==' })
|
73
|
+
end
|
74
|
+
|
75
|
+
it "doesn't escape cookies" do
|
76
|
+
expect(@net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca; path=/'])
|
77
|
+
expect(@response.cookies).to eq({ 'session_id' => 'BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca' })
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '.cookie_jar' do
|
81
|
+
it 'extracts cookies into cookie jar' do
|
82
|
+
expect(@net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/'])
|
83
|
+
expect(@response.cookie_jar).to be_a HTTP::CookieJar
|
84
|
+
|
85
|
+
cookie = @response.cookie_jar.cookies.first
|
86
|
+
expect(cookie.domain).to eq 'example.com'
|
87
|
+
expect(cookie.name).to eq 'session_id'
|
88
|
+
expect(cookie.value).to eq '1'
|
89
|
+
expect(cookie.path).to eq '/'
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'handles cookies when URI scheme is implicit' do
|
93
|
+
net_http_res = double('net http response')
|
94
|
+
expect(net_http_res).to receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/'])
|
95
|
+
request = double(url: 'example.com', uri: URI.parse('http://example.com'),
|
96
|
+
method: 'get', cookie_jar: HTTP::CookieJar.new)
|
97
|
+
response = MyAbstractResponse.new(net_http_res, request)
|
98
|
+
expect(response.cookie_jar).to be_a HTTP::CookieJar
|
99
|
+
|
100
|
+
cookie = response.cookie_jar.cookies.first
|
101
|
+
expect(cookie.domain).to eq 'example.com'
|
102
|
+
expect(cookie.name).to eq 'session_id'
|
103
|
+
expect(cookie.value).to eq '1'
|
104
|
+
expect(cookie.path).to eq '/'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
it "can access the net http result directly" do
|
109
|
+
expect(@response.net_http_res).to eq @net_http_res
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "#return!" do
|
113
|
+
it "should return the response itself on 200-codes" do
|
114
|
+
expect(@net_http_res).to receive(:code).and_return('200')
|
115
|
+
expect(@response.return!).to be_equal(@response)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should raise RequestFailed on unknown codes" do
|
119
|
+
expect(@net_http_res).to receive(:code).and_return('1000')
|
120
|
+
expect { @response.return! }.to raise_error RestClient::RequestFailed
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should raise an error on a redirection after non-GET/HEAD requests" do
|
124
|
+
expect(@net_http_res).to receive(:code).and_return('301')
|
125
|
+
expect(@request).to receive(:method).and_return('put')
|
126
|
+
expect(@response).not_to receive(:follow_redirection)
|
127
|
+
expect { @response.return! }.to raise_error RestClient::RequestFailed
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should follow 302 redirect" do
|
131
|
+
expect(@net_http_res).to receive(:code).and_return('302')
|
132
|
+
expect(@response).to receive(:check_max_redirects).and_return('fake-check')
|
133
|
+
expect(@response).to receive(:follow_redirection).and_return('fake-redirection')
|
134
|
+
expect(@response.return!).to eq 'fake-redirection'
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should gracefully handle 302 redirect with no location header" do
|
138
|
+
@net_http_res = response_double(code: 302, location: nil)
|
139
|
+
@request = request_double()
|
140
|
+
@response = MyAbstractResponse.new(@net_http_res, @request)
|
141
|
+
expect(@response).to receive(:check_max_redirects).and_return('fake-check')
|
142
|
+
expect { @response.return! }.to raise_error RestClient::Found
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require_relative '_lib'
|
2
|
+
|
3
|
+
describe RestClient::Exception do
|
4
|
+
it "returns a 'message' equal to the class name if the message is not set, because 'message' should not be nil" do
|
5
|
+
e = RestClient::Exception.new
|
6
|
+
expect(e.message).to eq "RestClient::Exception"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns the 'message' that was set" do
|
10
|
+
e = RestClient::Exception.new
|
11
|
+
message = "An explicitly set message"
|
12
|
+
e.message = message
|
13
|
+
expect(e.message).to eq message
|
14
|
+
end
|
15
|
+
|
16
|
+
it "sets the exception message to ErrorMessage" do
|
17
|
+
expect(RestClient::ResourceNotFound.new.message).to eq 'Not Found'
|
18
|
+
end
|
19
|
+
|
20
|
+
it "contains exceptions in RestClient" do
|
21
|
+
expect(RestClient::Unauthorized.new).to be_a_kind_of(RestClient::Exception)
|
22
|
+
expect(RestClient::ServerBrokeConnection.new).to be_a_kind_of(RestClient::Exception)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe RestClient::ServerBrokeConnection do
|
27
|
+
it "should have a default message of 'Server broke connection'" do
|
28
|
+
e = RestClient::ServerBrokeConnection.new
|
29
|
+
expect(e.message).to eq 'Server broke connection'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe RestClient::RequestFailed do
|
34
|
+
before do
|
35
|
+
@response = double('HTTP Response', :code => '502')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "stores the http response on the exception" do
|
39
|
+
response = "response"
|
40
|
+
begin
|
41
|
+
raise RestClient::RequestFailed, response
|
42
|
+
rescue RestClient::RequestFailed => e
|
43
|
+
expect(e.response).to eq response
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "http_code convenience method for fetching the code as an integer" do
|
48
|
+
expect(RestClient::RequestFailed.new(@response).http_code).to eq 502
|
49
|
+
end
|
50
|
+
|
51
|
+
it "http_body convenience method for fetching the body (decoding when necessary)" do
|
52
|
+
expect(RestClient::RequestFailed.new(@response).http_code).to eq 502
|
53
|
+
expect(RestClient::RequestFailed.new(@response).message).to eq 'HTTP status code 502'
|
54
|
+
end
|
55
|
+
|
56
|
+
it "shows the status code in the message" do
|
57
|
+
expect(RestClient::RequestFailed.new(@response).to_s).to match(/502/)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe RestClient::ResourceNotFound do
|
62
|
+
it "also has the http response attached" do
|
63
|
+
response = "response"
|
64
|
+
begin
|
65
|
+
raise RestClient::ResourceNotFound, response
|
66
|
+
rescue RestClient::ResourceNotFound => e
|
67
|
+
expect(e.response).to eq response
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'stores the body on the response of the exception' do
|
72
|
+
body = "body"
|
73
|
+
stub_request(:get, "www.example.com").to_return(:body => body, :status => 404)
|
74
|
+
begin
|
75
|
+
RestClient.get "www.example.com"
|
76
|
+
raise
|
77
|
+
rescue RestClient::ResourceNotFound => e
|
78
|
+
expect(e.response.body).to eq body
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "backwards compatibility" do
|
84
|
+
it 'aliases RestClient::NotFound as ResourceNotFound' do
|
85
|
+
expect(RestClient::ResourceNotFound).to eq RestClient::NotFound
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'aliases old names for HTTP 413, 414, 416' do
|
89
|
+
expect(RestClient::RequestEntityTooLarge).to eq RestClient::PayloadTooLarge
|
90
|
+
expect(RestClient::RequestURITooLong).to eq RestClient::URITooLong
|
91
|
+
expect(RestClient::RequestedRangeNotSatisfiable).to eq RestClient::RangeNotSatisfiable
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'subclasses NotFound from RequestFailed, ExceptionWithResponse' do
|
95
|
+
expect(RestClient::NotFound).to be < RestClient::RequestFailed
|
96
|
+
expect(RestClient::NotFound).to be < RestClient::ExceptionWithResponse
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'subclasses timeout from RestClient::RequestTimeout, RequestFailed, EWR' do
|
100
|
+
expect(RestClient::Exceptions::OpenTimeout).to be < RestClient::Exceptions::Timeout
|
101
|
+
expect(RestClient::Exceptions::ReadTimeout).to be < RestClient::Exceptions::Timeout
|
102
|
+
|
103
|
+
expect(RestClient::Exceptions::Timeout).to be < RestClient::RequestTimeout
|
104
|
+
expect(RestClient::Exceptions::Timeout).to be < RestClient::RequestFailed
|
105
|
+
expect(RestClient::Exceptions::Timeout).to be < RestClient::ExceptionWithResponse
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
File without changes
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative '_lib'
|
2
|
+
|
3
|
+
describe RestClient::ParamsArray do
|
4
|
+
|
5
|
+
describe '.new' do
|
6
|
+
it 'accepts various types of containers' do
|
7
|
+
as_array = [[:foo, 123], [:foo, 456], [:bar, 789], [:empty, nil]]
|
8
|
+
[
|
9
|
+
[[:foo, 123], [:foo, 456], [:bar, 789], [:empty, nil]],
|
10
|
+
[{foo: 123}, {foo: 456}, {bar: 789}, {empty: nil}],
|
11
|
+
[{foo: 123}, {foo: 456}, {bar: 789}, {empty: nil}],
|
12
|
+
[{foo: 123}, [:foo, 456], {bar: 789}, {empty: nil}],
|
13
|
+
[{foo: 123}, [:foo, 456], {bar: 789}, [:empty]],
|
14
|
+
].each do |input|
|
15
|
+
expect(RestClient::ParamsArray.new(input).to_a).to eq as_array
|
16
|
+
end
|
17
|
+
|
18
|
+
expect(RestClient::ParamsArray.new([]).to_a).to eq []
|
19
|
+
expect(RestClient::ParamsArray.new([]).empty?).to eq true
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'rejects various invalid input' do
|
23
|
+
expect {
|
24
|
+
RestClient::ParamsArray.new([[]])
|
25
|
+
}.to raise_error(IndexError)
|
26
|
+
|
27
|
+
expect {
|
28
|
+
RestClient::ParamsArray.new([[1,2,3]])
|
29
|
+
}.to raise_error(ArgumentError)
|
30
|
+
|
31
|
+
expect {
|
32
|
+
RestClient::ParamsArray.new([1,2,3])
|
33
|
+
}.to raise_error(NoMethodError)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,59 +1,68 @@
|
|
1
1
|
# encoding: binary
|
2
|
-
|
2
|
+
|
3
|
+
require_relative '_lib'
|
3
4
|
|
4
5
|
describe RestClient::Payload do
|
6
|
+
context "Base Payload" do
|
7
|
+
it "should reset stream after to_s" do
|
8
|
+
payload = RestClient::Payload::Base.new('foobar')
|
9
|
+
expect(payload.to_s).to eq 'foobar'
|
10
|
+
expect(payload.to_s).to eq 'foobar'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
5
14
|
context "A regular Payload" do
|
6
15
|
it "should use standard enctype as default content-type" do
|
7
|
-
RestClient::Payload::UrlEncoded.new({}).headers['Content-Type'].
|
8
|
-
|
16
|
+
expect(RestClient::Payload::UrlEncoded.new({}).headers['Content-Type']).
|
17
|
+
to eq 'application/x-www-form-urlencoded'
|
9
18
|
end
|
10
19
|
|
11
20
|
it "should form properly encoded params" do
|
12
|
-
RestClient::Payload::UrlEncoded.new({:foo => 'bar'}).to_s.
|
13
|
-
|
14
|
-
["foo=bar&baz=qux", "baz=qux&foo=bar"].
|
21
|
+
expect(RestClient::Payload::UrlEncoded.new({:foo => 'bar'}).to_s).
|
22
|
+
to eq "foo=bar"
|
23
|
+
expect(["foo=bar&baz=qux", "baz=qux&foo=bar"]).to include(
|
15
24
|
RestClient::Payload::UrlEncoded.new({:foo => 'bar', :baz => 'qux'}).to_s)
|
16
25
|
end
|
17
26
|
|
18
27
|
it "should escape parameters" do
|
19
|
-
RestClient::Payload::UrlEncoded.new({'foo ' => '
|
20
|
-
|
28
|
+
expect(RestClient::Payload::UrlEncoded.new({'foo + bar' => 'baz'}).to_s).
|
29
|
+
to eq "foo+%2B+bar=baz"
|
21
30
|
end
|
22
31
|
|
23
32
|
it "should properly handle hashes as parameter" do
|
24
|
-
RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz'}}).to_s.
|
25
|
-
|
26
|
-
RestClient::Payload::UrlEncoded.new({:foo => {:bar => {:baz => 'qux'}}}).to_s.
|
27
|
-
|
33
|
+
expect(RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz'}}).to_s).
|
34
|
+
to eq "foo[bar]=baz"
|
35
|
+
expect(RestClient::Payload::UrlEncoded.new({:foo => {:bar => {:baz => 'qux'}}}).to_s).
|
36
|
+
to eq "foo[bar][baz]=qux"
|
28
37
|
end
|
29
38
|
|
30
39
|
it "should handle many attributes inside a hash" do
|
31
40
|
parameters = RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz', :baz => 'qux'}}).to_s
|
32
|
-
parameters.
|
41
|
+
expect(parameters).to eq 'foo[bar]=baz&foo[baz]=qux'
|
33
42
|
end
|
34
43
|
|
35
|
-
it "should handle attributes inside
|
44
|
+
it "should handle attributes inside an array inside an hash" do
|
36
45
|
parameters = RestClient::Payload::UrlEncoded.new({"foo" => [{"bar" => 'baz'}, {"bar" => 'qux'}]}).to_s
|
37
|
-
parameters.
|
46
|
+
expect(parameters).to eq 'foo[][bar]=baz&foo[][bar]=qux'
|
38
47
|
end
|
39
48
|
|
40
|
-
it "should handle
|
41
|
-
parameters = RestClient::Payload::UrlEncoded.new({"foo" =>
|
42
|
-
parameters.
|
49
|
+
it "should handle arrays inside a hash inside a hash" do
|
50
|
+
parameters = RestClient::Payload::UrlEncoded.new({"foo" => {'even' => [0, 2], 'odd' => [1, 3]}}).to_s
|
51
|
+
expect(parameters).to eq 'foo[even][]=0&foo[even][]=2&foo[odd][]=1&foo[odd][]=3'
|
43
52
|
end
|
44
53
|
|
45
54
|
it "should form properly use symbols as parameters" do
|
46
|
-
RestClient::Payload::UrlEncoded.new({:foo => :bar}).to_s.
|
47
|
-
|
48
|
-
RestClient::Payload::UrlEncoded.new({:foo => {:bar => :baz}}).to_s.
|
49
|
-
|
55
|
+
expect(RestClient::Payload::UrlEncoded.new({:foo => :bar}).to_s).
|
56
|
+
to eq "foo=bar"
|
57
|
+
expect(RestClient::Payload::UrlEncoded.new({:foo => {:bar => :baz}}).to_s).
|
58
|
+
to eq "foo[bar]=baz"
|
50
59
|
end
|
51
60
|
|
52
61
|
it "should properly handle arrays as repeated parameters" do
|
53
|
-
RestClient::Payload::UrlEncoded.new({:foo => ['bar']}).to_s.
|
54
|
-
|
55
|
-
RestClient::Payload::UrlEncoded.new({:foo => ['bar', 'baz']}).to_s.
|
56
|
-
|
62
|
+
expect(RestClient::Payload::UrlEncoded.new({:foo => ['bar']}).to_s).
|
63
|
+
to eq "foo[]=bar"
|
64
|
+
expect(RestClient::Payload::UrlEncoded.new({:foo => ['bar', 'baz']}).to_s).
|
65
|
+
to eq "foo[]=bar&foo[]=baz"
|
57
66
|
end
|
58
67
|
|
59
68
|
it 'should not close if stream already closed' do
|
@@ -66,8 +75,8 @@ describe RestClient::Payload do
|
|
66
75
|
context "A multipart Payload" do
|
67
76
|
it "should use standard enctype as default content-type" do
|
68
77
|
m = RestClient::Payload::Multipart.new({})
|
69
|
-
m.
|
70
|
-
m.headers['Content-Type'].
|
78
|
+
allow(m).to receive(:boundary).and_return(123)
|
79
|
+
expect(m.headers['Content-Type']).to eq 'multipart/form-data; boundary=123'
|
71
80
|
end
|
72
81
|
|
73
82
|
it 'should not error on close if stream already closed' do
|
@@ -77,7 +86,7 @@ describe RestClient::Payload do
|
|
77
86
|
|
78
87
|
it "should form properly separated multipart data" do
|
79
88
|
m = RestClient::Payload::Multipart.new([[:bar, "baz"], [:foo, "bar"]])
|
80
|
-
m.to_s.
|
89
|
+
expect(m.to_s).to eq <<-EOS
|
81
90
|
--#{m.boundary}\r
|
82
91
|
Content-Disposition: form-data; name="bar"\r
|
83
92
|
\r
|
@@ -92,7 +101,7 @@ bar\r
|
|
92
101
|
|
93
102
|
it "should not escape parameters names" do
|
94
103
|
m = RestClient::Payload::Multipart.new([["bar ", "baz"]])
|
95
|
-
m.to_s.
|
104
|
+
expect(m.to_s).to eq <<-EOS
|
96
105
|
--#{m.boundary}\r
|
97
106
|
Content-Disposition: form-data; name="bar "\r
|
98
107
|
\r
|
@@ -104,7 +113,7 @@ baz\r
|
|
104
113
|
it "should form properly separated multipart data" do
|
105
114
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
106
115
|
m = RestClient::Payload::Multipart.new({:foo => f})
|
107
|
-
m.to_s.
|
116
|
+
expect(m.to_s).to eq <<-EOS
|
108
117
|
--#{m.boundary}\r
|
109
118
|
Content-Disposition: form-data; name="foo"; filename="master_shake.jpg"\r
|
110
119
|
Content-Type: image/jpeg\r
|
@@ -117,7 +126,7 @@ Content-Type: image/jpeg\r
|
|
117
126
|
it "should ignore the name attribute when it's not set" do
|
118
127
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
119
128
|
m = RestClient::Payload::Multipart.new({nil => f})
|
120
|
-
m.to_s.
|
129
|
+
expect(m.to_s).to eq <<-EOS
|
121
130
|
--#{m.boundary}\r
|
122
131
|
Content-Disposition: form-data; filename="master_shake.jpg"\r
|
123
132
|
Content-Type: image/jpeg\r
|
@@ -132,7 +141,7 @@ Content-Type: image/jpeg\r
|
|
132
141
|
f.instance_eval "def content_type; 'text/plain'; end"
|
133
142
|
f.instance_eval "def original_filename; 'foo.txt'; end"
|
134
143
|
m = RestClient::Payload::Multipart.new({:foo => f})
|
135
|
-
m.to_s.
|
144
|
+
expect(m.to_s).to eq <<-EOS
|
136
145
|
--#{m.boundary}\r
|
137
146
|
Content-Disposition: form-data; name="foo"; filename="foo.txt"\r
|
138
147
|
Content-Type: text/plain\r
|
@@ -144,7 +153,7 @@ Content-Type: text/plain\r
|
|
144
153
|
|
145
154
|
it "should handle hash in hash parameters" do
|
146
155
|
m = RestClient::Payload::Multipart.new({:bar => {:baz => "foo"}})
|
147
|
-
m.to_s.
|
156
|
+
expect(m.to_s).to eq <<-EOS
|
148
157
|
--#{m.boundary}\r
|
149
158
|
Content-Disposition: form-data; name="bar[baz]"\r
|
150
159
|
\r
|
@@ -156,7 +165,7 @@ foo\r
|
|
156
165
|
f.instance_eval "def content_type; 'text/plain'; end"
|
157
166
|
f.instance_eval "def original_filename; 'foo.txt'; end"
|
158
167
|
m = RestClient::Payload::Multipart.new({:foo => {:bar => f}})
|
159
|
-
m.to_s.
|
168
|
+
expect(m.to_s).to eq <<-EOS
|
160
169
|
--#{m.boundary}\r
|
161
170
|
Content-Disposition: form-data; name="foo[bar]"; filename="foo.txt"\r
|
162
171
|
Content-Type: text/plain\r
|
@@ -166,29 +175,36 @@ Content-Type: text/plain\r
|
|
166
175
|
EOS
|
167
176
|
end
|
168
177
|
|
178
|
+
it 'should correctly format hex boundary' do
|
179
|
+
allow(SecureRandom).to receive(:base64).with(12).and_return('TGs89+ttw/xna6TV')
|
180
|
+
f = File.new(File.dirname(__FILE__) + '/master_shake.jpg')
|
181
|
+
m = RestClient::Payload::Multipart.new({:foo => f})
|
182
|
+
expect(m.boundary).to eq('-' * 4 + 'RubyFormBoundary' + 'TGs89AttwBxna6TV')
|
183
|
+
end
|
184
|
+
|
169
185
|
end
|
170
186
|
|
171
187
|
context "streamed payloads" do
|
172
188
|
it "should properly determine the size of file payloads" do
|
173
189
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
174
190
|
payload = RestClient::Payload.generate(f)
|
175
|
-
payload.size.
|
176
|
-
payload.length.
|
191
|
+
expect(payload.size).to eq 76_988
|
192
|
+
expect(payload.length).to eq 76_988
|
177
193
|
end
|
178
194
|
|
179
195
|
it "should properly determine the size of other kinds of streaming payloads" do
|
180
196
|
s = StringIO.new 'foo'
|
181
197
|
payload = RestClient::Payload.generate(s)
|
182
|
-
payload.size.
|
183
|
-
payload.length.
|
198
|
+
expect(payload.size).to eq 3
|
199
|
+
expect(payload.length).to eq 3
|
184
200
|
|
185
201
|
begin
|
186
202
|
f = Tempfile.new "rest-client"
|
187
203
|
f.write 'foo bar'
|
188
204
|
|
189
205
|
payload = RestClient::Payload.generate(f)
|
190
|
-
payload.size.
|
191
|
-
payload.length.
|
206
|
+
expect(payload.size).to eq 7
|
207
|
+
expect(payload.length).to eq 7
|
192
208
|
ensure
|
193
209
|
f.close
|
194
210
|
end
|
@@ -197,48 +213,51 @@ Content-Type: text/plain\r
|
|
197
213
|
|
198
214
|
context "Payload generation" do
|
199
215
|
it "should recognize standard urlencoded params" do
|
200
|
-
RestClient::Payload.generate({"foo" => 'bar'}).
|
216
|
+
expect(RestClient::Payload.generate({"foo" => 'bar'})).to be_kind_of(RestClient::Payload::UrlEncoded)
|
201
217
|
end
|
202
218
|
|
203
219
|
it "should recognize multipart params" do
|
204
220
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
205
|
-
RestClient::Payload.generate({"foo" => f}).
|
221
|
+
expect(RestClient::Payload.generate({"foo" => f})).to be_kind_of(RestClient::Payload::Multipart)
|
206
222
|
end
|
207
223
|
|
208
224
|
it "should be multipart if forced" do
|
209
|
-
RestClient::Payload.generate({"foo" => "bar", :multipart => true}).
|
225
|
+
expect(RestClient::Payload.generate({"foo" => "bar", :multipart => true})).to be_kind_of(RestClient::Payload::Multipart)
|
210
226
|
end
|
211
227
|
|
228
|
+
it "should handle deeply nested multipart" do
|
229
|
+
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
230
|
+
params = {foo: RestClient::ParamsArray.new({nested: f})}
|
231
|
+
expect(RestClient::Payload.generate(params)).to be_kind_of(RestClient::Payload::Multipart)
|
232
|
+
end
|
233
|
+
|
234
|
+
|
212
235
|
it "should return data if no of the above" do
|
213
|
-
RestClient::Payload.generate("data").
|
236
|
+
expect(RestClient::Payload.generate("data")).to be_kind_of(RestClient::Payload::Base)
|
214
237
|
end
|
215
238
|
|
216
239
|
it "should recognize nested multipart payloads in hashes" do
|
217
240
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
218
|
-
RestClient::Payload.generate({"foo" => {"file" => f}}).
|
241
|
+
expect(RestClient::Payload.generate({"foo" => {"file" => f}})).to be_kind_of(RestClient::Payload::Multipart)
|
219
242
|
end
|
220
243
|
|
221
244
|
it "should recognize nested multipart payloads in arrays" do
|
222
245
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
223
|
-
RestClient::Payload.generate({"foo" => [f]}).
|
246
|
+
expect(RestClient::Payload.generate({"foo" => [f]})).to be_kind_of(RestClient::Payload::Multipart)
|
224
247
|
end
|
225
248
|
|
226
249
|
it "should recognize file payloads that can be streamed" do
|
227
250
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
228
|
-
RestClient::Payload.generate(f).
|
251
|
+
expect(RestClient::Payload.generate(f)).to be_kind_of(RestClient::Payload::Streamed)
|
229
252
|
end
|
230
253
|
|
231
254
|
it "should recognize other payloads that can be streamed" do
|
232
|
-
RestClient::Payload.generate(StringIO.new('foo')).
|
255
|
+
expect(RestClient::Payload.generate(StringIO.new('foo'))).to be_kind_of(RestClient::Payload::Streamed)
|
233
256
|
end
|
234
257
|
|
235
258
|
# hashery gem introduces Hash#read convenience method. Existence of #read method used to determine of content is streameable :/
|
236
259
|
it "shouldn't treat hashes as streameable" do
|
237
|
-
RestClient::Payload.generate({"foo" => 'bar'}).
|
260
|
+
expect(RestClient::Payload.generate({"foo" => 'bar'})).to be_kind_of(RestClient::Payload::UrlEncoded)
|
238
261
|
end
|
239
262
|
end
|
240
|
-
|
241
|
-
class HashMapForTesting < Hash
|
242
|
-
alias :read :[]
|
243
|
-
end
|
244
263
|
end
|