rest-client 2.0.0.rc2-x64-mingw32 → 2.0.0.rc3-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop-disables.yml +17 -8
- data/.travis.yml +32 -2
- data/AUTHORS +6 -0
- data/README.md +578 -0
- data/Rakefile +1 -1
- data/history.md +45 -13
- data/lib/restclient.rb +4 -2
- data/lib/restclient/abstract_response.rb +51 -25
- data/lib/restclient/exceptions.rb +45 -6
- data/lib/restclient/params_array.rb +72 -0
- data/lib/restclient/payload.rb +40 -69
- data/lib/restclient/raw_response.rb +1 -2
- data/lib/restclient/request.rb +372 -199
- data/lib/restclient/response.rb +11 -8
- data/lib/restclient/utils.rb +144 -2
- data/lib/restclient/version.rb +1 -1
- data/rest-client.gemspec +5 -5
- data/spec/helpers.rb +8 -0
- data/spec/integration/httpbin_spec.rb +7 -7
- data/spec/integration/integration_spec.rb +34 -24
- data/spec/integration/request_spec.rb +1 -1
- data/spec/spec_helper.rb +8 -1
- data/spec/unit/abstract_response_spec.rb +76 -33
- data/spec/unit/exceptions_spec.rb +27 -21
- data/spec/unit/params_array_spec.rb +36 -0
- data/spec/unit/payload_spec.rb +71 -53
- data/spec/unit/raw_response_spec.rb +3 -3
- data/spec/unit/request2_spec.rb +29 -7
- data/spec/unit/request_spec.rb +552 -415
- data/spec/unit/resource_spec.rb +25 -25
- data/spec/unit/response_spec.rb +86 -64
- data/spec/unit/restclient_spec.rb +13 -13
- data/spec/unit/utils_spec.rb +117 -41
- data/spec/unit/windows/root_certs_spec.rb +2 -2
- metadata +15 -12
- data/README.rdoc +0 -410
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative '_lib'
|
2
2
|
|
3
|
-
describe RestClient::AbstractResponse do
|
3
|
+
describe RestClient::AbstractResponse, :include_helpers do
|
4
4
|
|
5
5
|
class MyAbstractResponse
|
6
6
|
|
@@ -8,9 +8,8 @@ describe RestClient::AbstractResponse do
|
|
8
8
|
|
9
9
|
attr_accessor :size
|
10
10
|
|
11
|
-
def initialize net_http_res,
|
11
|
+
def initialize net_http_res, request
|
12
12
|
@net_http_res = net_http_res
|
13
|
-
@args = args
|
14
13
|
@request = request
|
15
14
|
end
|
16
15
|
|
@@ -18,85 +17,129 @@ describe RestClient::AbstractResponse do
|
|
18
17
|
|
19
18
|
before do
|
20
19
|
@net_http_res = double('net http response')
|
21
|
-
@request =
|
22
|
-
@response = MyAbstractResponse.new(@net_http_res,
|
20
|
+
@request = request_double(url: 'http://example.com', method: 'get')
|
21
|
+
@response = MyAbstractResponse.new(@net_http_res, @request)
|
23
22
|
end
|
24
23
|
|
25
24
|
it "fetches the numeric response code" do
|
26
|
-
@net_http_res.
|
27
|
-
@response.code.
|
25
|
+
expect(@net_http_res).to receive(:code).and_return('200')
|
26
|
+
expect(@response.code).to eq 200
|
28
27
|
end
|
29
28
|
|
30
29
|
it "has a nice description" do
|
31
|
-
@net_http_res.
|
32
|
-
@net_http_res.
|
33
|
-
@response.description.
|
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"
|
34
33
|
end
|
35
34
|
|
36
35
|
describe '.beautify_headers' do
|
37
36
|
it "beautifies the headers by turning the keys to symbols" do
|
38
37
|
h = RestClient::AbstractResponse.beautify_headers('content-type' => [ 'x' ])
|
39
|
-
h.keys.first.
|
38
|
+
expect(h.keys.first).to eq :content_type
|
40
39
|
end
|
41
40
|
|
42
41
|
it "beautifies the headers by turning the values to strings instead of one-element arrays" do
|
43
42
|
h = RestClient::AbstractResponse.beautify_headers('x' => [ 'text/html' ] )
|
44
|
-
h.values.first.
|
43
|
+
expect(h.values.first).to eq 'text/html'
|
45
44
|
end
|
46
45
|
|
47
46
|
it 'joins multiple header values by comma' do
|
48
|
-
RestClient::AbstractResponse.beautify_headers(
|
47
|
+
expect(RestClient::AbstractResponse.beautify_headers(
|
49
48
|
{'My-Header' => ['one', 'two']}
|
50
|
-
).
|
49
|
+
)).to eq({:my_header => 'one, two'})
|
51
50
|
end
|
52
51
|
|
53
52
|
it 'leaves set-cookie headers as array' do
|
54
|
-
RestClient::AbstractResponse.beautify_headers(
|
53
|
+
expect(RestClient::AbstractResponse.beautify_headers(
|
55
54
|
{'Set-Cookie' => ['cookie1=foo', 'cookie2=bar']}
|
56
|
-
).
|
55
|
+
)).to eq({:set_cookie => ['cookie1=foo', 'cookie2=bar']})
|
57
56
|
end
|
58
57
|
end
|
59
58
|
|
60
59
|
it "fetches the headers" do
|
61
|
-
@net_http_res.
|
62
|
-
@response.headers.
|
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' })
|
63
62
|
end
|
64
63
|
|
65
64
|
it "extracts cookies from response headers" do
|
66
|
-
@net_http_res.
|
67
|
-
@response.cookies.
|
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' })
|
68
67
|
end
|
69
68
|
|
70
69
|
it "extract strange cookies" do
|
71
|
-
@net_http_res.
|
72
|
-
@response.headers.
|
73
|
-
@response.cookies.
|
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==' })
|
74
73
|
end
|
75
74
|
|
76
75
|
it "doesn't escape cookies" do
|
77
|
-
@net_http_res.
|
78
|
-
@response.cookies.
|
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
|
79
106
|
end
|
80
107
|
|
81
108
|
it "can access the net http result directly" do
|
82
|
-
@response.net_http_res.
|
109
|
+
expect(@response.net_http_res).to eq @net_http_res
|
83
110
|
end
|
84
111
|
|
85
112
|
describe "#return!" do
|
86
113
|
it "should return the response itself on 200-codes" do
|
87
|
-
@net_http_res.
|
88
|
-
@response.return
|
114
|
+
expect(@net_http_res).to receive(:code).and_return('200')
|
115
|
+
expect(@response.return!).to be_equal(@response)
|
89
116
|
end
|
90
117
|
|
91
118
|
it "should raise RequestFailed on unknown codes" do
|
92
|
-
@net_http_res.
|
93
|
-
|
119
|
+
expect(@net_http_res).to receive(:code).and_return('1000')
|
120
|
+
expect { @response.return! }.to raise_error RestClient::RequestFailed
|
94
121
|
end
|
95
122
|
|
96
123
|
it "should raise an error on a redirection after non-GET/HEAD requests" do
|
97
|
-
@net_http_res.
|
98
|
-
@
|
99
|
-
|
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
|
100
143
|
end
|
101
144
|
end
|
102
145
|
end
|
@@ -3,30 +3,30 @@ require_relative '_lib'
|
|
3
3
|
describe RestClient::Exception do
|
4
4
|
it "returns a 'message' equal to the class name if the message is not set, because 'message' should not be nil" do
|
5
5
|
e = RestClient::Exception.new
|
6
|
-
e.message.
|
6
|
+
expect(e.message).to eq "RestClient::Exception"
|
7
7
|
end
|
8
8
|
|
9
9
|
it "returns the 'message' that was set" do
|
10
10
|
e = RestClient::Exception.new
|
11
11
|
message = "An explicitly set message"
|
12
12
|
e.message = message
|
13
|
-
e.message.
|
13
|
+
expect(e.message).to eq message
|
14
14
|
end
|
15
15
|
|
16
16
|
it "sets the exception message to ErrorMessage" do
|
17
|
-
RestClient::ResourceNotFound.new.message.
|
17
|
+
expect(RestClient::ResourceNotFound.new.message).to eq 'Not Found'
|
18
18
|
end
|
19
19
|
|
20
20
|
it "contains exceptions in RestClient" do
|
21
|
-
RestClient::Unauthorized.new.
|
22
|
-
RestClient::ServerBrokeConnection.new.
|
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
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
describe RestClient::ServerBrokeConnection do
|
27
27
|
it "should have a default message of 'Server broke connection'" do
|
28
28
|
e = RestClient::ServerBrokeConnection.new
|
29
|
-
e.message.
|
29
|
+
expect(e.message).to eq 'Server broke connection'
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -40,21 +40,21 @@ describe RestClient::RequestFailed do
|
|
40
40
|
begin
|
41
41
|
raise RestClient::RequestFailed, response
|
42
42
|
rescue RestClient::RequestFailed => e
|
43
|
-
e.response.
|
43
|
+
expect(e.response).to eq response
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
it "http_code convenience method for fetching the code as an integer" do
|
48
|
-
RestClient::RequestFailed.new(@response).http_code.
|
48
|
+
expect(RestClient::RequestFailed.new(@response).http_code).to eq 502
|
49
49
|
end
|
50
50
|
|
51
51
|
it "http_body convenience method for fetching the body (decoding when necessary)" do
|
52
|
-
RestClient::RequestFailed.new(@response).http_code.
|
53
|
-
RestClient::RequestFailed.new(@response).message.
|
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
54
|
end
|
55
55
|
|
56
56
|
it "shows the status code in the message" do
|
57
|
-
RestClient::RequestFailed.new(@response).to_s.
|
57
|
+
expect(RestClient::RequestFailed.new(@response).to_s).to match(/502/)
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
@@ -64,7 +64,7 @@ describe RestClient::ResourceNotFound do
|
|
64
64
|
begin
|
65
65
|
raise RestClient::ResourceNotFound, response
|
66
66
|
rescue RestClient::ResourceNotFound => e
|
67
|
-
e.response.
|
67
|
+
expect(e.response).to eq response
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -75,28 +75,34 @@ describe RestClient::ResourceNotFound do
|
|
75
75
|
RestClient.get "www.example.com"
|
76
76
|
raise
|
77
77
|
rescue RestClient::ResourceNotFound => e
|
78
|
-
e.response.body.
|
78
|
+
expect(e.response.body).to eq body
|
79
79
|
end
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
83
|
describe "backwards compatibility" do
|
84
84
|
it 'aliases RestClient::NotFound as ResourceNotFound' do
|
85
|
-
RestClient::ResourceNotFound.
|
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
|
86
92
|
end
|
87
93
|
|
88
94
|
it 'subclasses NotFound from RequestFailed, ExceptionWithResponse' do
|
89
|
-
RestClient::NotFound.
|
90
|
-
RestClient::NotFound.
|
95
|
+
expect(RestClient::NotFound).to be < RestClient::RequestFailed
|
96
|
+
expect(RestClient::NotFound).to be < RestClient::ExceptionWithResponse
|
91
97
|
end
|
92
98
|
|
93
99
|
it 'subclasses timeout from RestClient::RequestTimeout, RequestFailed, EWR' do
|
94
|
-
RestClient::Exceptions::OpenTimeout.
|
95
|
-
RestClient::Exceptions::ReadTimeout.
|
100
|
+
expect(RestClient::Exceptions::OpenTimeout).to be < RestClient::Exceptions::Timeout
|
101
|
+
expect(RestClient::Exceptions::ReadTimeout).to be < RestClient::Exceptions::Timeout
|
96
102
|
|
97
|
-
RestClient::Exceptions::Timeout.
|
98
|
-
RestClient::Exceptions::Timeout.
|
99
|
-
RestClient::Exceptions::Timeout.
|
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
|
100
106
|
end
|
101
107
|
|
102
108
|
end
|
@@ -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
|
data/spec/unit/payload_spec.rb
CHANGED
@@ -3,58 +3,66 @@
|
|
3
3
|
require_relative '_lib'
|
4
4
|
|
5
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
|
+
|
6
14
|
context "A regular Payload" do
|
7
15
|
it "should use standard enctype as default content-type" do
|
8
|
-
RestClient::Payload::UrlEncoded.new({}).headers['Content-Type'].
|
9
|
-
|
16
|
+
expect(RestClient::Payload::UrlEncoded.new({}).headers['Content-Type']).
|
17
|
+
to eq 'application/x-www-form-urlencoded'
|
10
18
|
end
|
11
19
|
|
12
20
|
it "should form properly encoded params" do
|
13
|
-
RestClient::Payload::UrlEncoded.new({:foo => 'bar'}).to_s.
|
14
|
-
|
15
|
-
["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(
|
16
24
|
RestClient::Payload::UrlEncoded.new({:foo => 'bar', :baz => 'qux'}).to_s)
|
17
25
|
end
|
18
26
|
|
19
27
|
it "should escape parameters" do
|
20
|
-
RestClient::Payload::UrlEncoded.new({'foo ' => '
|
21
|
-
|
28
|
+
expect(RestClient::Payload::UrlEncoded.new({'foo + bar' => 'baz'}).to_s).
|
29
|
+
to eq "foo+%2B+bar=baz"
|
22
30
|
end
|
23
31
|
|
24
32
|
it "should properly handle hashes as parameter" do
|
25
|
-
RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz'}}).to_s.
|
26
|
-
|
27
|
-
RestClient::Payload::UrlEncoded.new({:foo => {:bar => {:baz => 'qux'}}}).to_s.
|
28
|
-
|
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"
|
29
37
|
end
|
30
38
|
|
31
39
|
it "should handle many attributes inside a hash" do
|
32
40
|
parameters = RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz', :baz => 'qux'}}).to_s
|
33
|
-
parameters.
|
41
|
+
expect(parameters).to eq 'foo[bar]=baz&foo[baz]=qux'
|
34
42
|
end
|
35
43
|
|
36
|
-
it "should handle attributes inside
|
44
|
+
it "should handle attributes inside an array inside an hash" do
|
37
45
|
parameters = RestClient::Payload::UrlEncoded.new({"foo" => [{"bar" => 'baz'}, {"bar" => 'qux'}]}).to_s
|
38
|
-
parameters.
|
46
|
+
expect(parameters).to eq 'foo[][bar]=baz&foo[][bar]=qux'
|
39
47
|
end
|
40
48
|
|
41
|
-
it "should handle
|
42
|
-
parameters = RestClient::Payload::UrlEncoded.new({"foo" =>
|
43
|
-
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'
|
44
52
|
end
|
45
53
|
|
46
54
|
it "should form properly use symbols as parameters" do
|
47
|
-
RestClient::Payload::UrlEncoded.new({:foo => :bar}).to_s.
|
48
|
-
|
49
|
-
RestClient::Payload::UrlEncoded.new({:foo => {:bar => :baz}}).to_s.
|
50
|
-
|
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"
|
51
59
|
end
|
52
60
|
|
53
61
|
it "should properly handle arrays as repeated parameters" do
|
54
|
-
RestClient::Payload::UrlEncoded.new({:foo => ['bar']}).to_s.
|
55
|
-
|
56
|
-
RestClient::Payload::UrlEncoded.new({:foo => ['bar', 'baz']}).to_s.
|
57
|
-
|
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"
|
58
66
|
end
|
59
67
|
|
60
68
|
it 'should not close if stream already closed' do
|
@@ -67,8 +75,8 @@ describe RestClient::Payload do
|
|
67
75
|
context "A multipart Payload" do
|
68
76
|
it "should use standard enctype as default content-type" do
|
69
77
|
m = RestClient::Payload::Multipart.new({})
|
70
|
-
m.
|
71
|
-
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'
|
72
80
|
end
|
73
81
|
|
74
82
|
it 'should not error on close if stream already closed' do
|
@@ -78,7 +86,7 @@ describe RestClient::Payload do
|
|
78
86
|
|
79
87
|
it "should form properly separated multipart data" do
|
80
88
|
m = RestClient::Payload::Multipart.new([[:bar, "baz"], [:foo, "bar"]])
|
81
|
-
m.to_s.
|
89
|
+
expect(m.to_s).to eq <<-EOS
|
82
90
|
--#{m.boundary}\r
|
83
91
|
Content-Disposition: form-data; name="bar"\r
|
84
92
|
\r
|
@@ -93,7 +101,7 @@ bar\r
|
|
93
101
|
|
94
102
|
it "should not escape parameters names" do
|
95
103
|
m = RestClient::Payload::Multipart.new([["bar ", "baz"]])
|
96
|
-
m.to_s.
|
104
|
+
expect(m.to_s).to eq <<-EOS
|
97
105
|
--#{m.boundary}\r
|
98
106
|
Content-Disposition: form-data; name="bar "\r
|
99
107
|
\r
|
@@ -105,7 +113,7 @@ baz\r
|
|
105
113
|
it "should form properly separated multipart data" do
|
106
114
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
107
115
|
m = RestClient::Payload::Multipart.new({:foo => f})
|
108
|
-
m.to_s.
|
116
|
+
expect(m.to_s).to eq <<-EOS
|
109
117
|
--#{m.boundary}\r
|
110
118
|
Content-Disposition: form-data; name="foo"; filename="master_shake.jpg"\r
|
111
119
|
Content-Type: image/jpeg\r
|
@@ -118,7 +126,7 @@ Content-Type: image/jpeg\r
|
|
118
126
|
it "should ignore the name attribute when it's not set" do
|
119
127
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
120
128
|
m = RestClient::Payload::Multipart.new({nil => f})
|
121
|
-
m.to_s.
|
129
|
+
expect(m.to_s).to eq <<-EOS
|
122
130
|
--#{m.boundary}\r
|
123
131
|
Content-Disposition: form-data; filename="master_shake.jpg"\r
|
124
132
|
Content-Type: image/jpeg\r
|
@@ -133,7 +141,7 @@ Content-Type: image/jpeg\r
|
|
133
141
|
f.instance_eval "def content_type; 'text/plain'; end"
|
134
142
|
f.instance_eval "def original_filename; 'foo.txt'; end"
|
135
143
|
m = RestClient::Payload::Multipart.new({:foo => f})
|
136
|
-
m.to_s.
|
144
|
+
expect(m.to_s).to eq <<-EOS
|
137
145
|
--#{m.boundary}\r
|
138
146
|
Content-Disposition: form-data; name="foo"; filename="foo.txt"\r
|
139
147
|
Content-Type: text/plain\r
|
@@ -145,7 +153,7 @@ Content-Type: text/plain\r
|
|
145
153
|
|
146
154
|
it "should handle hash in hash parameters" do
|
147
155
|
m = RestClient::Payload::Multipart.new({:bar => {:baz => "foo"}})
|
148
|
-
m.to_s.
|
156
|
+
expect(m.to_s).to eq <<-EOS
|
149
157
|
--#{m.boundary}\r
|
150
158
|
Content-Disposition: form-data; name="bar[baz]"\r
|
151
159
|
\r
|
@@ -157,7 +165,7 @@ foo\r
|
|
157
165
|
f.instance_eval "def content_type; 'text/plain'; end"
|
158
166
|
f.instance_eval "def original_filename; 'foo.txt'; end"
|
159
167
|
m = RestClient::Payload::Multipart.new({:foo => {:bar => f}})
|
160
|
-
m.to_s.
|
168
|
+
expect(m.to_s).to eq <<-EOS
|
161
169
|
--#{m.boundary}\r
|
162
170
|
Content-Disposition: form-data; name="foo[bar]"; filename="foo.txt"\r
|
163
171
|
Content-Type: text/plain\r
|
@@ -167,29 +175,36 @@ Content-Type: text/plain\r
|
|
167
175
|
EOS
|
168
176
|
end
|
169
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
|
+
|
170
185
|
end
|
171
186
|
|
172
187
|
context "streamed payloads" do
|
173
188
|
it "should properly determine the size of file payloads" do
|
174
189
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
175
190
|
payload = RestClient::Payload.generate(f)
|
176
|
-
payload.size.
|
177
|
-
payload.length.
|
191
|
+
expect(payload.size).to eq 76_988
|
192
|
+
expect(payload.length).to eq 76_988
|
178
193
|
end
|
179
194
|
|
180
195
|
it "should properly determine the size of other kinds of streaming payloads" do
|
181
196
|
s = StringIO.new 'foo'
|
182
197
|
payload = RestClient::Payload.generate(s)
|
183
|
-
payload.size.
|
184
|
-
payload.length.
|
198
|
+
expect(payload.size).to eq 3
|
199
|
+
expect(payload.length).to eq 3
|
185
200
|
|
186
201
|
begin
|
187
202
|
f = Tempfile.new "rest-client"
|
188
203
|
f.write 'foo bar'
|
189
204
|
|
190
205
|
payload = RestClient::Payload.generate(f)
|
191
|
-
payload.size.
|
192
|
-
payload.length.
|
206
|
+
expect(payload.size).to eq 7
|
207
|
+
expect(payload.length).to eq 7
|
193
208
|
ensure
|
194
209
|
f.close
|
195
210
|
end
|
@@ -198,48 +213,51 @@ Content-Type: text/plain\r
|
|
198
213
|
|
199
214
|
context "Payload generation" do
|
200
215
|
it "should recognize standard urlencoded params" do
|
201
|
-
RestClient::Payload.generate({"foo" => 'bar'}).
|
216
|
+
expect(RestClient::Payload.generate({"foo" => 'bar'})).to be_kind_of(RestClient::Payload::UrlEncoded)
|
202
217
|
end
|
203
218
|
|
204
219
|
it "should recognize multipart params" do
|
205
220
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
206
|
-
RestClient::Payload.generate({"foo" => f}).
|
221
|
+
expect(RestClient::Payload.generate({"foo" => f})).to be_kind_of(RestClient::Payload::Multipart)
|
207
222
|
end
|
208
223
|
|
209
224
|
it "should be multipart if forced" do
|
210
|
-
RestClient::Payload.generate({"foo" => "bar", :multipart => true}).
|
225
|
+
expect(RestClient::Payload.generate({"foo" => "bar", :multipart => true})).to be_kind_of(RestClient::Payload::Multipart)
|
211
226
|
end
|
212
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
|
+
|
213
235
|
it "should return data if no of the above" do
|
214
|
-
RestClient::Payload.generate("data").
|
236
|
+
expect(RestClient::Payload.generate("data")).to be_kind_of(RestClient::Payload::Base)
|
215
237
|
end
|
216
238
|
|
217
239
|
it "should recognize nested multipart payloads in hashes" do
|
218
240
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
219
|
-
RestClient::Payload.generate({"foo" => {"file" => f}}).
|
241
|
+
expect(RestClient::Payload.generate({"foo" => {"file" => f}})).to be_kind_of(RestClient::Payload::Multipart)
|
220
242
|
end
|
221
243
|
|
222
244
|
it "should recognize nested multipart payloads in arrays" do
|
223
245
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
224
|
-
RestClient::Payload.generate({"foo" => [f]}).
|
246
|
+
expect(RestClient::Payload.generate({"foo" => [f]})).to be_kind_of(RestClient::Payload::Multipart)
|
225
247
|
end
|
226
248
|
|
227
249
|
it "should recognize file payloads that can be streamed" do
|
228
250
|
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
229
|
-
RestClient::Payload.generate(f).
|
251
|
+
expect(RestClient::Payload.generate(f)).to be_kind_of(RestClient::Payload::Streamed)
|
230
252
|
end
|
231
253
|
|
232
254
|
it "should recognize other payloads that can be streamed" do
|
233
|
-
RestClient::Payload.generate(StringIO.new('foo')).
|
255
|
+
expect(RestClient::Payload.generate(StringIO.new('foo'))).to be_kind_of(RestClient::Payload::Streamed)
|
234
256
|
end
|
235
257
|
|
236
258
|
# hashery gem introduces Hash#read convenience method. Existence of #read method used to determine of content is streameable :/
|
237
259
|
it "shouldn't treat hashes as streameable" do
|
238
|
-
RestClient::Payload.generate({"foo" => 'bar'}).
|
260
|
+
expect(RestClient::Payload.generate({"foo" => 'bar'})).to be_kind_of(RestClient::Payload::UrlEncoded)
|
239
261
|
end
|
240
262
|
end
|
241
|
-
|
242
|
-
class HashMapForTesting < Hash
|
243
|
-
alias :read :[]
|
244
|
-
end
|
245
263
|
end
|