rest-client 1.8.0 → 2.1.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.
- 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
|