rest-client 1.8.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +2 -0
- data/.mailmap +10 -0
- data/.rspec +2 -1
- data/.rubocop +2 -0
- data/.rubocop-disables.yml +386 -0
- data/.rubocop.yml +8 -0
- data/.travis.yml +56 -8
- data/AUTHORS +26 -1
- data/README.md +901 -0
- data/Rakefile +27 -3
- data/bin/restclient +3 -5
- data/history.md +181 -0
- data/lib/restclient/abstract_response.rb +172 -55
- data/lib/restclient/exceptions.rb +96 -55
- data/lib/restclient/params_array.rb +72 -0
- data/lib/restclient/payload.rb +70 -74
- data/lib/restclient/platform.rb +19 -0
- data/lib/restclient/raw_response.rb +21 -7
- data/lib/restclient/request.rb +540 -281
- data/lib/restclient/resource.rb +19 -9
- data/lib/restclient/response.rb +75 -6
- data/lib/restclient/utils.rb +274 -0
- data/lib/restclient/version.rb +2 -1
- data/lib/restclient.rb +21 -3
- data/rest-client.gemspec +12 -10
- data/spec/ISS.jpg +0 -0
- data/spec/helpers.rb +54 -0
- data/spec/integration/_lib.rb +1 -0
- data/spec/integration/capath_digicert/3513523f.0 +22 -0
- data/spec/integration/capath_digicert/399e7759.0 +22 -0
- data/spec/integration/capath_digicert/digicert.crt +20 -17
- data/spec/integration/certs/digicert.crt +20 -17
- data/spec/integration/httpbin_spec.rb +128 -0
- data/spec/integration/integration_spec.rb +97 -14
- data/spec/integration/request_spec.rb +25 -2
- data/spec/spec_helper.rb +28 -1
- data/spec/unit/_lib.rb +1 -0
- data/spec/unit/abstract_response_spec.rb +95 -38
- data/spec/unit/exceptions_spec.rb +41 -28
- data/spec/unit/params_array_spec.rb +36 -0
- data/spec/unit/payload_spec.rb +118 -68
- data/spec/unit/raw_response_spec.rb +10 -6
- data/spec/unit/request2_spec.rb +34 -12
- data/spec/unit/request_spec.rb +745 -424
- data/spec/unit/resource_spec.rb +31 -27
- data/spec/unit/response_spec.rb +134 -57
- data/spec/unit/restclient_spec.rb +16 -15
- data/spec/unit/utils_spec.rb +147 -0
- data/spec/unit/windows/root_certs_spec.rb +3 -3
- metadata +79 -29
- data/README.rdoc +0 -324
- data/spec/integration/capath_digicert/244b5494.0 +0 -19
- data/spec/integration/capath_digicert/81b9768f.0 +0 -19
- data/spec/unit/master_shake.jpg +0 -0
@@ -1,19 +1,22 @@
|
|
1
1
|
-----BEGIN CERTIFICATE-----
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
2
|
+
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
3
|
+
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
4
|
+
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
5
|
+
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
6
|
+
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
7
|
+
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
8
|
+
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
9
|
+
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
10
|
+
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
11
|
+
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
12
|
+
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
13
|
+
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
14
|
+
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
15
|
+
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
16
|
+
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
17
|
+
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
18
|
+
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
19
|
+
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
20
|
+
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
21
|
+
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
19
22
|
-----END CERTIFICATE-----
|
@@ -1,19 +1,22 @@
|
|
1
1
|
-----BEGIN CERTIFICATE-----
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
2
|
+
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
3
|
+
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
4
|
+
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
5
|
+
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
6
|
+
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
7
|
+
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
8
|
+
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
9
|
+
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
10
|
+
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
11
|
+
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
12
|
+
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
13
|
+
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
14
|
+
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
15
|
+
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
16
|
+
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
17
|
+
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
18
|
+
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
19
|
+
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
20
|
+
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
21
|
+
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
19
22
|
-----END CERTIFICATE-----
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require_relative '_lib'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require 'zlib'
|
5
|
+
|
6
|
+
describe RestClient::Request do
|
7
|
+
before(:all) do
|
8
|
+
WebMock.disable!
|
9
|
+
end
|
10
|
+
|
11
|
+
after(:all) do
|
12
|
+
WebMock.enable!
|
13
|
+
end
|
14
|
+
|
15
|
+
def default_httpbin_url
|
16
|
+
# add a hack to work around java/jruby bug
|
17
|
+
# java.lang.RuntimeException: Could not generate DH keypair with backtrace
|
18
|
+
# Also (2017-04-09) Travis Jruby versions have a broken CA keystore
|
19
|
+
if ENV['TRAVIS_RUBY_VERSION'] =~ /\Ajruby-/
|
20
|
+
'http://httpbin.org/'
|
21
|
+
else
|
22
|
+
'https://httpbin.org/'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def httpbin(suffix='')
|
27
|
+
url = ENV.fetch('HTTPBIN_URL', default_httpbin_url)
|
28
|
+
unless url.end_with?('/')
|
29
|
+
url += '/'
|
30
|
+
end
|
31
|
+
|
32
|
+
url + suffix
|
33
|
+
end
|
34
|
+
|
35
|
+
def execute_httpbin(suffix, opts={})
|
36
|
+
opts = {url: httpbin(suffix)}.merge(opts)
|
37
|
+
RestClient::Request.execute(opts)
|
38
|
+
end
|
39
|
+
|
40
|
+
def execute_httpbin_json(suffix, opts={})
|
41
|
+
JSON.parse(execute_httpbin(suffix, opts))
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '.execute' do
|
45
|
+
it 'sends a user agent' do
|
46
|
+
data = execute_httpbin_json('user-agent', method: :get)
|
47
|
+
expect(data['user-agent']).to match(/rest-client/)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'receives cookies on 302' do
|
51
|
+
expect {
|
52
|
+
execute_httpbin('cookies/set?foo=bar', method: :get, max_redirects: 0)
|
53
|
+
}.to raise_error(RestClient::Found) { |ex|
|
54
|
+
expect(ex.http_code).to eq 302
|
55
|
+
expect(ex.response.cookies['foo']).to eq 'bar'
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'passes along cookies through 302' do
|
60
|
+
data = execute_httpbin_json('cookies/set?foo=bar', method: :get)
|
61
|
+
expect(data).to have_key('cookies')
|
62
|
+
expect(data['cookies']['foo']).to eq 'bar'
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'handles quote wrapped cookies' do
|
66
|
+
expect {
|
67
|
+
execute_httpbin('cookies/set?foo=' + CGI.escape('"bar:baz"'),
|
68
|
+
method: :get, max_redirects: 0)
|
69
|
+
}.to raise_error(RestClient::Found) { |ex|
|
70
|
+
expect(ex.http_code).to eq 302
|
71
|
+
expect(ex.response.cookies['foo']).to eq '"bar:baz"'
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'sends basic auth' do
|
76
|
+
user = 'user'
|
77
|
+
pass = 'pass'
|
78
|
+
|
79
|
+
data = execute_httpbin_json("basic-auth/#{user}/#{pass}", method: :get, user: user, password: pass)
|
80
|
+
expect(data).to eq({'authenticated' => true, 'user' => user})
|
81
|
+
|
82
|
+
expect {
|
83
|
+
execute_httpbin_json("basic-auth/#{user}/#{pass}", method: :get, user: user, password: 'badpass')
|
84
|
+
}.to raise_error(RestClient::Unauthorized) { |ex|
|
85
|
+
expect(ex.http_code).to eq 401
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'handles gzipped/deflated responses' do
|
90
|
+
[['gzip', 'gzipped'], ['deflate', 'deflated']].each do |encoding, var|
|
91
|
+
raw = execute_httpbin(encoding, method: :get)
|
92
|
+
|
93
|
+
begin
|
94
|
+
data = JSON.parse(raw)
|
95
|
+
rescue StandardError
|
96
|
+
puts "Failed to parse: " + raw.inspect
|
97
|
+
raise
|
98
|
+
end
|
99
|
+
|
100
|
+
expect(data['method']).to eq 'GET'
|
101
|
+
expect(data.fetch(var)).to be true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'does not uncompress response when accept-encoding is set' do
|
106
|
+
# == gzip ==
|
107
|
+
raw = execute_httpbin('gzip', method: :get, headers: {accept_encoding: 'gzip, deflate'})
|
108
|
+
|
109
|
+
# check for gzip magic number
|
110
|
+
expect(raw.body).to start_with("\x1F\x8B".b)
|
111
|
+
|
112
|
+
decoded = Zlib::GzipReader.new(StringIO.new(raw.body)).read
|
113
|
+
parsed = JSON.parse(decoded)
|
114
|
+
|
115
|
+
expect(parsed['method']).to eq 'GET'
|
116
|
+
expect(parsed.fetch('gzipped')).to be true
|
117
|
+
|
118
|
+
# == delate ==
|
119
|
+
raw = execute_httpbin('deflate', method: :get, headers: {accept_encoding: 'gzip, deflate'})
|
120
|
+
|
121
|
+
decoded = Zlib::Inflate.new.inflate(raw.body)
|
122
|
+
parsed = JSON.parse(decoded)
|
123
|
+
|
124
|
+
expect(parsed['method']).to eq 'GET'
|
125
|
+
expect(parsed.fetch('deflated')).to be true
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '_lib'
|
3
|
+
require 'base64'
|
2
4
|
|
3
5
|
describe RestClient do
|
4
6
|
|
@@ -6,15 +8,8 @@ describe RestClient do
|
|
6
8
|
body = 'abc'
|
7
9
|
stub_request(:get, "www.example.com").to_return(:body => body, :status => 200)
|
8
10
|
response = RestClient.get "www.example.com"
|
9
|
-
response.code.
|
10
|
-
response.body.
|
11
|
-
end
|
12
|
-
|
13
|
-
it "a simple request with gzipped content" do
|
14
|
-
stub_request(:get, "www.example.com").with(:headers => { 'Accept-Encoding' => 'gzip, deflate' }).to_return(:body => "\037\213\b\b\006'\252H\000\003t\000\313T\317UH\257\312,HM\341\002\000G\242(\r\v\000\000\000", :status => 200, :headers => { 'Content-Encoding' => 'gzip' } )
|
15
|
-
response = RestClient.get "www.example.com"
|
16
|
-
response.code.should eq 200
|
17
|
-
response.body.should eq "i'm gziped\n"
|
11
|
+
expect(response.code).to eq 200
|
12
|
+
expect(response.body).to eq body
|
18
13
|
end
|
19
14
|
|
20
15
|
it "a 404" do
|
@@ -24,12 +19,100 @@ describe RestClient do
|
|
24
19
|
RestClient.get "www.example.com"
|
25
20
|
raise
|
26
21
|
rescue RestClient::ResourceNotFound => e
|
27
|
-
e.http_code.
|
28
|
-
e.response.code.
|
29
|
-
e.response.body.
|
30
|
-
e.http_body.
|
22
|
+
expect(e.http_code).to eq 404
|
23
|
+
expect(e.response.code).to eq 404
|
24
|
+
expect(e.response.body).to eq body
|
25
|
+
expect(e.http_body).to eq body
|
31
26
|
end
|
32
27
|
end
|
33
28
|
|
29
|
+
describe 'charset parsing' do
|
30
|
+
it 'handles utf-8' do
|
31
|
+
body = "λ".force_encoding('ASCII-8BIT')
|
32
|
+
stub_request(:get, "www.example.com").to_return(
|
33
|
+
:body => body, :status => 200, :headers => {
|
34
|
+
'Content-Type' => 'text/plain; charset=UTF-8'
|
35
|
+
})
|
36
|
+
response = RestClient.get "www.example.com"
|
37
|
+
expect(response.encoding).to eq Encoding::UTF_8
|
38
|
+
expect(response.valid_encoding?).to eq true
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'handles windows-1252' do
|
42
|
+
body = "\xff".force_encoding('ASCII-8BIT')
|
43
|
+
stub_request(:get, "www.example.com").to_return(
|
44
|
+
:body => body, :status => 200, :headers => {
|
45
|
+
'Content-Type' => 'text/plain; charset=windows-1252'
|
46
|
+
})
|
47
|
+
response = RestClient.get "www.example.com"
|
48
|
+
expect(response.encoding).to eq Encoding::WINDOWS_1252
|
49
|
+
expect(response.encode('utf-8')).to eq "ÿ"
|
50
|
+
expect(response.valid_encoding?).to eq true
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'handles binary' do
|
54
|
+
body = "\xfe".force_encoding('ASCII-8BIT')
|
55
|
+
stub_request(:get, "www.example.com").to_return(
|
56
|
+
:body => body, :status => 200, :headers => {
|
57
|
+
'Content-Type' => 'application/octet-stream; charset=binary'
|
58
|
+
})
|
59
|
+
response = RestClient.get "www.example.com"
|
60
|
+
expect(response.encoding).to eq Encoding::BINARY
|
61
|
+
expect {
|
62
|
+
response.encode('utf-8')
|
63
|
+
}.to raise_error(Encoding::UndefinedConversionError)
|
64
|
+
expect(response.valid_encoding?).to eq true
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'handles euc-jp' do
|
68
|
+
body = "\xA4\xA2\xA4\xA4\xA4\xA6\xA4\xA8\xA4\xAA".
|
69
|
+
force_encoding(Encoding::BINARY)
|
70
|
+
body_utf8 = 'あいうえお'
|
71
|
+
expect(body_utf8.encoding).to eq Encoding::UTF_8
|
72
|
+
|
73
|
+
stub_request(:get, 'www.example.com').to_return(
|
74
|
+
:body => body, :status => 200, :headers => {
|
75
|
+
'Content-Type' => 'text/plain; charset=EUC-JP'
|
76
|
+
})
|
77
|
+
response = RestClient.get 'www.example.com'
|
78
|
+
expect(response.encoding).to eq Encoding::EUC_JP
|
79
|
+
expect(response.valid_encoding?).to eq true
|
80
|
+
expect(response.length).to eq 5
|
81
|
+
expect(response.encode('utf-8')).to eq body_utf8
|
82
|
+
end
|
34
83
|
|
84
|
+
it 'defaults to the default encoding' do
|
85
|
+
stub_request(:get, 'www.example.com').to_return(
|
86
|
+
body: 'abc', status: 200, headers: {
|
87
|
+
'Content-Type' => 'text/plain'
|
88
|
+
})
|
89
|
+
|
90
|
+
response = RestClient.get 'www.example.com'
|
91
|
+
# expect(response.encoding).to eq Encoding.default_external
|
92
|
+
expect(response.encoding).to eq Encoding::UTF_8
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'handles invalid encoding' do
|
96
|
+
stub_request(:get, 'www.example.com').to_return(
|
97
|
+
body: 'abc', status: 200, headers: {
|
98
|
+
'Content-Type' => 'text; charset=plain'
|
99
|
+
})
|
100
|
+
|
101
|
+
response = RestClient.get 'www.example.com'
|
102
|
+
# expect(response.encoding).to eq Encoding.default_external
|
103
|
+
expect(response.encoding).to eq Encoding::UTF_8
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'leaves images as binary' do
|
107
|
+
gif = Base64.strict_decode64('R0lGODlhAQABAAAAADs=')
|
108
|
+
|
109
|
+
stub_request(:get, 'www.example.com').to_return(
|
110
|
+
body: gif, status: 200, headers: {
|
111
|
+
'Content-Type' => 'image/gif'
|
112
|
+
})
|
113
|
+
|
114
|
+
response = RestClient.get 'www.example.com'
|
115
|
+
expect(response.encoding).to eq Encoding::BINARY
|
116
|
+
end
|
117
|
+
end
|
35
118
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative '_lib'
|
2
2
|
|
3
3
|
describe RestClient::Request do
|
4
4
|
before(:all) do
|
@@ -75,7 +75,7 @@ describe RestClient::Request do
|
|
75
75
|
},
|
76
76
|
)
|
77
77
|
expect {request.execute }.to_not raise_error
|
78
|
-
ran_callback.
|
78
|
+
expect(ran_callback).to eq(true)
|
79
79
|
end
|
80
80
|
|
81
81
|
it "fails verification when the callback returns false",
|
@@ -101,4 +101,27 @@ describe RestClient::Request do
|
|
101
101
|
expect { request.execute }.to_not raise_error
|
102
102
|
end
|
103
103
|
end
|
104
|
+
|
105
|
+
describe "timeouts" do
|
106
|
+
it "raises OpenTimeout when it hits an open timeout" do
|
107
|
+
request = RestClient::Request.new(
|
108
|
+
:method => :get,
|
109
|
+
:url => 'http://www.mozilla.org',
|
110
|
+
:open_timeout => 1e-10,
|
111
|
+
)
|
112
|
+
expect { request.execute }.to(
|
113
|
+
raise_error(RestClient::Exceptions::OpenTimeout))
|
114
|
+
end
|
115
|
+
|
116
|
+
it "raises ReadTimeout when it hits a read timeout via :read_timeout" do
|
117
|
+
request = RestClient::Request.new(
|
118
|
+
:method => :get,
|
119
|
+
:url => 'https://www.mozilla.org',
|
120
|
+
:read_timeout => 1e-10,
|
121
|
+
)
|
122
|
+
expect { request.execute }.to(
|
123
|
+
raise_error(RestClient::Exceptions::ReadTimeout))
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
104
127
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,2 +1,29 @@
|
|
1
1
|
require 'webmock/rspec'
|
2
|
-
require '
|
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'
|
@@ -1,88 +1,145 @@
|
|
1
|
-
|
1
|
+
require_relative '_lib'
|
2
2
|
|
3
|
-
describe RestClient::AbstractResponse do
|
3
|
+
describe RestClient::AbstractResponse, :include_helpers do
|
4
4
|
|
5
|
+
# Sample class implementing AbstractResponse used for testing.
|
5
6
|
class MyAbstractResponse
|
6
7
|
|
7
8
|
include RestClient::AbstractResponse
|
8
9
|
|
9
10
|
attr_accessor :size
|
10
11
|
|
11
|
-
def initialize
|
12
|
-
|
13
|
-
@args = args
|
14
|
-
@request = request
|
12
|
+
def initialize(net_http_res, request)
|
13
|
+
response_set_vars(net_http_res, request, Time.now - 1)
|
15
14
|
end
|
16
15
|
|
17
16
|
end
|
18
17
|
|
19
18
|
before do
|
20
|
-
@net_http_res =
|
21
|
-
@request =
|
22
|
-
@response = MyAbstractResponse.new(@net_http_res,
|
19
|
+
@net_http_res = res_double()
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
44
57
|
end
|
45
58
|
|
46
59
|
it "fetches the headers" do
|
47
|
-
@net_http_res.
|
48
|
-
@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' })
|
49
62
|
end
|
50
63
|
|
51
64
|
it "extracts cookies from response headers" do
|
52
|
-
@net_http_res.
|
53
|
-
@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' })
|
54
67
|
end
|
55
68
|
|
56
69
|
it "extract strange cookies" do
|
57
|
-
@net_http_res.
|
58
|
-
@response.headers.
|
59
|
-
@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==' })
|
60
73
|
end
|
61
74
|
|
62
75
|
it "doesn't escape cookies" do
|
63
|
-
@net_http_res.
|
64
|
-
@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('request', url: 'example.com', uri: URI.parse('http://example.com'),
|
96
|
+
method: 'get', cookie_jar: HTTP::CookieJar.new, redirection_history: nil)
|
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
|
65
106
|
end
|
66
107
|
|
67
108
|
it "can access the net http result directly" do
|
68
|
-
@response.net_http_res.
|
109
|
+
expect(@response.net_http_res).to eq @net_http_res
|
69
110
|
end
|
70
111
|
|
71
112
|
describe "#return!" do
|
72
113
|
it "should return the response itself on 200-codes" do
|
73
|
-
@net_http_res.
|
74
|
-
@response.return
|
114
|
+
expect(@net_http_res).to receive(:code).and_return('200')
|
115
|
+
expect(@response.return!).to be_equal(@response)
|
75
116
|
end
|
76
117
|
|
77
118
|
it "should raise RequestFailed on unknown codes" do
|
78
|
-
@net_http_res.
|
79
|
-
|
119
|
+
expect(@net_http_res).to receive(:code).and_return('1000')
|
120
|
+
expect { @response.return! }.to raise_error RestClient::RequestFailed
|
80
121
|
end
|
81
122
|
|
82
123
|
it "should raise an error on a redirection after non-GET/HEAD requests" do
|
83
|
-
@net_http_res.
|
84
|
-
@
|
85
|
-
|
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 = res_double(code: 302)
|
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
|
86
143
|
end
|
87
144
|
end
|
88
145
|
end
|