rest-man 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/multi-matrix-test.yml +35 -0
- data/.github/workflows/single-matrix-test.yml +27 -0
- data/.gitignore +13 -0
- data/.mailmap +10 -0
- data/.rspec +2 -0
- data/.rubocop +2 -0
- data/.rubocop-disables.yml +386 -0
- data/.rubocop.yml +8 -0
- data/AUTHORS +106 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.md +843 -0
- data/Rakefile +140 -0
- data/exe/restman +92 -0
- data/lib/rest-man.rb +2 -0
- data/lib/rest_man.rb +2 -0
- data/lib/restman/abstract_response.rb +252 -0
- data/lib/restman/exceptions.rb +238 -0
- data/lib/restman/params_array.rb +72 -0
- data/lib/restman/payload.rb +234 -0
- data/lib/restman/platform.rb +49 -0
- data/lib/restman/raw_response.rb +49 -0
- data/lib/restman/request.rb +859 -0
- data/lib/restman/resource.rb +178 -0
- data/lib/restman/response.rb +90 -0
- data/lib/restman/utils.rb +274 -0
- data/lib/restman/version.rb +8 -0
- data/lib/restman/windows/root_certs.rb +105 -0
- data/lib/restman/windows.rb +8 -0
- data/lib/restman.rb +183 -0
- data/matrixeval.yml +73 -0
- data/rest-man.gemspec +41 -0
- data/spec/ISS.jpg +0 -0
- data/spec/cassettes/request_httpbin_with_basic_auth.yml +83 -0
- data/spec/cassettes/request_httpbin_with_cookies.yml +49 -0
- data/spec/cassettes/request_httpbin_with_cookies_2.yml +94 -0
- data/spec/cassettes/request_httpbin_with_cookies_3.yml +49 -0
- data/spec/cassettes/request_httpbin_with_encoding_deflate.yml +45 -0
- data/spec/cassettes/request_httpbin_with_encoding_deflate_and_accept_headers.yml +44 -0
- data/spec/cassettes/request_httpbin_with_encoding_gzip.yml +45 -0
- data/spec/cassettes/request_httpbin_with_encoding_gzip_and_accept_headers.yml +44 -0
- data/spec/cassettes/request_httpbin_with_user_agent.yml +44 -0
- data/spec/cassettes/request_mozilla_org.yml +151 -0
- data/spec/cassettes/request_mozilla_org_callback_returns_true.yml +178 -0
- data/spec/cassettes/request_mozilla_org_with_system_cert.yml +152 -0
- data/spec/cassettes/request_mozilla_org_with_system_cert_and_callback.yml +151 -0
- data/spec/helpers.rb +54 -0
- data/spec/integration/_lib.rb +1 -0
- data/spec/integration/capath_digicert/README +8 -0
- data/spec/integration/capath_digicert/ce5e74ef.0 +1 -0
- data/spec/integration/capath_digicert/digicert.crt +20 -0
- data/spec/integration/capath_digicert/update +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/certs/digicert.crt +20 -0
- data/spec/integration/certs/verisign.crt +14 -0
- data/spec/integration/httpbin_spec.rb +137 -0
- data/spec/integration/integration_spec.rb +118 -0
- data/spec/integration/request_spec.rb +134 -0
- data/spec/spec_helper.rb +40 -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/unit/params_array_spec.rb +36 -0
- data/spec/unit/payload_spec.rb +295 -0
- data/spec/unit/raw_response_spec.rb +22 -0
- data/spec/unit/request2_spec.rb +54 -0
- data/spec/unit/request_spec.rb +1205 -0
- data/spec/unit/resource_spec.rb +134 -0
- data/spec/unit/response_spec.rb +252 -0
- data/spec/unit/restclient_spec.rb +80 -0
- data/spec/unit/utils_spec.rb +147 -0
- data/spec/unit/windows/root_certs_spec.rb +22 -0
- metadata +336 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
|
3
|
+
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
4
|
+
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
|
5
|
+
MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
|
6
|
+
b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
|
7
|
+
ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
|
8
|
+
9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
|
9
|
+
IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
|
10
|
+
VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
|
11
|
+
93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
|
12
|
+
jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
|
13
|
+
AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
|
14
|
+
A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
|
15
|
+
U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
|
16
|
+
N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
|
17
|
+
o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
|
18
|
+
5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
|
19
|
+
rqXRfboQnoZsG4q5WTP468SQvvG5
|
20
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,14 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
|
3
|
+
A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
|
4
|
+
cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
|
5
|
+
MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
|
6
|
+
BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
|
7
|
+
YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
|
8
|
+
ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
|
9
|
+
BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
|
10
|
+
I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
|
11
|
+
CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
|
12
|
+
lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
|
13
|
+
AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
|
14
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require_relative '_lib'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require 'zlib'
|
5
|
+
|
6
|
+
describe RestMan::Request do
|
7
|
+
|
8
|
+
def default_httpbin_url
|
9
|
+
# add a hack to work around java/jruby bug
|
10
|
+
# java.lang.RuntimeException: Could not generate DH keypair with backtrace
|
11
|
+
# Also (2017-04-09) Travis Jruby versions have a broken CA keystore
|
12
|
+
if ENV['TRAVIS_RUBY_VERSION'] =~ /\Ajruby-/
|
13
|
+
'http://httpbin.org/'
|
14
|
+
else
|
15
|
+
'https://httpbin.org/'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def httpbin(suffix='')
|
20
|
+
url = ENV.fetch('HTTPBIN_URL', default_httpbin_url)
|
21
|
+
unless url.end_with?('/')
|
22
|
+
url += '/'
|
23
|
+
end
|
24
|
+
|
25
|
+
url + suffix
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute_httpbin(suffix, opts={})
|
29
|
+
opts = {url: httpbin(suffix)}.merge(opts)
|
30
|
+
RestMan::Request.execute(opts)
|
31
|
+
end
|
32
|
+
|
33
|
+
def execute_httpbin_json(suffix, opts={})
|
34
|
+
JSON.parse(execute_httpbin(suffix, opts))
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '.execute' do
|
38
|
+
it 'sends a user agent' do
|
39
|
+
VCR.use_cassette("request_httpbin_with_user_agent") do
|
40
|
+
data = execute_httpbin_json('user-agent', method: :get)
|
41
|
+
expect(data['user-agent']).to match(/rest-man/)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'receives cookies on 302' do
|
46
|
+
VCR.use_cassette("request_httpbin_with_cookies") do
|
47
|
+
expect {
|
48
|
+
execute_httpbin('cookies/set?foo=bar', method: :get, max_redirects: 0)
|
49
|
+
}.to raise_error(RestMan::Found) { |ex|
|
50
|
+
expect(ex.http_code).to eq 302
|
51
|
+
expect(ex.response.cookies['foo']).to eq 'bar'
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'passes along cookies through 302' do
|
57
|
+
VCR.use_cassette("request_httpbin_with_cookies_2") do
|
58
|
+
data = execute_httpbin_json('cookies/set?foo=bar', method: :get)
|
59
|
+
expect(data).to have_key('cookies')
|
60
|
+
expect(data['cookies']['foo']).to eq 'bar'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'handles quote wrapped cookies' do
|
65
|
+
VCR.use_cassette("request_httpbin_with_cookies_3") do
|
66
|
+
expect {
|
67
|
+
execute_httpbin('cookies/set?foo=' + CGI.escape('"bar:baz"'),
|
68
|
+
method: :get, max_redirects: 0)
|
69
|
+
}.to raise_error(RestMan::Found) { |ex|
|
70
|
+
expect(ex.http_code).to eq 302
|
71
|
+
expect(ex.response.cookies['foo']).to eq '"bar:baz"'
|
72
|
+
}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'sends basic auth' do
|
77
|
+
VCR.use_cassette("request_httpbin_with_basic_auth") do
|
78
|
+
user = 'user'
|
79
|
+
pass = 'pass'
|
80
|
+
|
81
|
+
data = execute_httpbin_json("basic-auth/#{user}/#{pass}", method: :get, user: user, password: pass)
|
82
|
+
expect(data).to eq({'authenticated' => true, 'user' => user})
|
83
|
+
|
84
|
+
expect {
|
85
|
+
execute_httpbin_json("basic-auth/#{user}/#{pass}", method: :get, user: user, password: 'badpass')
|
86
|
+
}.to raise_error(RestMan::Unauthorized) { |ex|
|
87
|
+
expect(ex.http_code).to eq 401
|
88
|
+
}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'handles gzipped/deflated responses' do
|
93
|
+
[['gzip', 'gzipped'], ['deflate', 'deflated']].each do |encoding, var|
|
94
|
+
VCR.use_cassette("request_httpbin_with_encoding_#{encoding}") do
|
95
|
+
raw = execute_httpbin(encoding, method: :get)
|
96
|
+
|
97
|
+
begin
|
98
|
+
data = JSON.parse(raw)
|
99
|
+
rescue StandardError
|
100
|
+
puts "Failed to parse: " + raw.inspect
|
101
|
+
raise
|
102
|
+
end
|
103
|
+
|
104
|
+
expect(data['method']).to eq 'GET'
|
105
|
+
expect(data.fetch(var)).to be true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'does not uncompress response when accept-encoding is set' do
|
111
|
+
VCR.use_cassette("request_httpbin_with_encoding_gzip_and_accept_headers") do
|
112
|
+
# == gzip ==
|
113
|
+
raw = execute_httpbin('gzip', method: :get, headers: {accept_encoding: 'gzip, deflate'})
|
114
|
+
|
115
|
+
# check for gzip magic number
|
116
|
+
expect(raw.body).to start_with("\x1F\x8B".b)
|
117
|
+
|
118
|
+
decoded = Zlib::GzipReader.new(StringIO.new(raw.body)).read
|
119
|
+
parsed = JSON.parse(decoded)
|
120
|
+
|
121
|
+
expect(parsed['method']).to eq 'GET'
|
122
|
+
expect(parsed.fetch('gzipped')).to be true
|
123
|
+
end
|
124
|
+
|
125
|
+
VCR.use_cassette("request_httpbin_with_encoding_deflate_and_accept_headers") do
|
126
|
+
# == delate ==
|
127
|
+
raw = execute_httpbin('deflate', method: :get, headers: {accept_encoding: 'gzip, deflate'})
|
128
|
+
|
129
|
+
decoded = Zlib::Inflate.new.inflate(raw.body)
|
130
|
+
parsed = JSON.parse(decoded)
|
131
|
+
|
132
|
+
expect(parsed['method']).to eq 'GET'
|
133
|
+
expect(parsed.fetch('deflated')).to be true
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require_relative '_lib'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
describe RestMan do
|
6
|
+
|
7
|
+
it "a simple request" do
|
8
|
+
body = 'abc'
|
9
|
+
stub_request(:get, "www.example.com").to_return(:body => body, :status => 200)
|
10
|
+
response = RestMan.get "www.example.com"
|
11
|
+
expect(response.code).to eq 200
|
12
|
+
expect(response.body).to eq body
|
13
|
+
end
|
14
|
+
|
15
|
+
it "a 404" do
|
16
|
+
body = "Ho hai ! I'm not here !"
|
17
|
+
stub_request(:get, "www.example.com").to_return(:body => body, :status => 404)
|
18
|
+
begin
|
19
|
+
RestMan.get "www.example.com"
|
20
|
+
raise
|
21
|
+
rescue RestMan::ResourceNotFound => e
|
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
|
26
|
+
end
|
27
|
+
end
|
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 = RestMan.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 = RestMan.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 = RestMan.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 = RestMan.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
|
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 = RestMan.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 = RestMan.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 = RestMan.get 'www.example.com'
|
115
|
+
expect(response.encoding).to eq Encoding::BINARY
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require_relative '_lib'
|
2
|
+
|
3
|
+
describe RestMan::Request do
|
4
|
+
|
5
|
+
describe "ssl verification" do
|
6
|
+
it "is successful with the correct ca_file" do
|
7
|
+
VCR.use_cassette('request_mozilla_org') do
|
8
|
+
request = RestMan::Request.new(
|
9
|
+
:method => :get,
|
10
|
+
:url => 'https://www.mozilla.org',
|
11
|
+
:ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "digicert.crt")
|
12
|
+
)
|
13
|
+
expect { request.execute }.to_not raise_error
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "is successful with the correct ca_path" do
|
18
|
+
VCR.use_cassette('request_mozilla_org') do
|
19
|
+
request = RestMan::Request.new(
|
20
|
+
:method => :get,
|
21
|
+
:url => 'https://www.mozilla.org',
|
22
|
+
:ssl_ca_path => File.join(File.dirname(__FILE__), "capath_digicert")
|
23
|
+
)
|
24
|
+
expect { request.execute }.to_not raise_error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "is unsuccessful with an incorrect ca_file", :unless => RestMan::Platform.mac_mri? do
|
29
|
+
VCR.use_cassette('request_mozilla_org_with_incorrect_ca_file') do
|
30
|
+
request = RestMan::Request.new(
|
31
|
+
:method => :get,
|
32
|
+
:url => 'https://www.mozilla.org',
|
33
|
+
:ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "verisign.crt")
|
34
|
+
)
|
35
|
+
expect { request.execute }.to raise_error(OpenSSL::SSL::SSLError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# On OS X, this test fails since Apple has patched OpenSSL to always fall
|
40
|
+
# back on the system CA store.
|
41
|
+
it "is unsuccessful with an incorrect ca_path", :unless => RestMan::Platform.mac_mri? do
|
42
|
+
VCR.use_cassette('request_mozilla_org_with_incorrect_ca_path') do
|
43
|
+
request = RestMan::Request.new(
|
44
|
+
:method => :get,
|
45
|
+
:url => 'https://www.mozilla.org',
|
46
|
+
:ssl_ca_path => File.join(File.dirname(__FILE__), "capath_verisign")
|
47
|
+
)
|
48
|
+
expect { request.execute }.to raise_error(OpenSSL::SSL::SSLError)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "is successful using the default system cert store" do
|
53
|
+
VCR.use_cassette('request_mozilla_org_with_system_cert') do
|
54
|
+
request = RestMan::Request.new(
|
55
|
+
:method => :get,
|
56
|
+
:url => 'https://www.mozilla.org',
|
57
|
+
:verify_ssl => true,
|
58
|
+
)
|
59
|
+
expect {request.execute }.to_not raise_error
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# verify_callback is not works well with VCR
|
65
|
+
# it "executes the verify_callback", focus: true do
|
66
|
+
# ran_callback = false
|
67
|
+
# request = RestMan::Request.new(
|
68
|
+
# :method => :get,
|
69
|
+
# :url => 'https://www.mozilla.org',
|
70
|
+
# :verify_ssl => true,
|
71
|
+
# :ssl_verify_callback => lambda { |preverify_ok, store_ctx|
|
72
|
+
# ran_callback = true
|
73
|
+
# preverify_ok
|
74
|
+
# },
|
75
|
+
# )
|
76
|
+
# expect {request.execute }.to_not raise_error
|
77
|
+
# expect(ran_callback).to eq(true)
|
78
|
+
# end
|
79
|
+
|
80
|
+
it "fails verification when the callback returns false",
|
81
|
+
:unless => RestMan::Platform.mac_mri? do
|
82
|
+
VCR.use_cassette('request_mozilla_org_callback_returns_false') do
|
83
|
+
request = RestMan::Request.new(
|
84
|
+
:method => :get,
|
85
|
+
:url => 'https://www.mozilla.org',
|
86
|
+
:verify_ssl => true,
|
87
|
+
:ssl_verify_callback => lambda { |preverify_ok, store_ctx| false },
|
88
|
+
)
|
89
|
+
expect { request.execute }.to raise_error(OpenSSL::SSL::SSLError)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it "succeeds verification when the callback returns true",
|
94
|
+
:unless => RestMan::Platform.mac_mri? do
|
95
|
+
VCR.use_cassette('request_mozilla_org_callback_returns_true') do
|
96
|
+
request = RestMan::Request.new(
|
97
|
+
:method => :get,
|
98
|
+
:url => 'https://www.mozilla.org',
|
99
|
+
:verify_ssl => true,
|
100
|
+
:ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "verisign.crt"),
|
101
|
+
:ssl_verify_callback => lambda { |preverify_ok, store_ctx| true },
|
102
|
+
)
|
103
|
+
expect { request.execute }.to_not raise_error
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "timeouts" do
|
109
|
+
it "raises OpenTimeout when it hits an open timeout" do
|
110
|
+
allow_any_instance_of(Net::HTTP).to receive(:request).and_raise(Net::OpenTimeout.new)
|
111
|
+
|
112
|
+
request = RestMan::Request.new(
|
113
|
+
:method => :get,
|
114
|
+
:url => 'http://www.mozilla.org',
|
115
|
+
:open_timeout => 1e-10,
|
116
|
+
)
|
117
|
+
expect { request.execute }.to(
|
118
|
+
raise_error(RestMan::Exceptions::OpenTimeout))
|
119
|
+
end
|
120
|
+
|
121
|
+
it "raises ReadTimeout when it hits a read timeout via :read_timeout" do
|
122
|
+
allow_any_instance_of(Net::HTTP).to receive(:request).and_raise(Net::ReadTimeout.new)
|
123
|
+
|
124
|
+
request = RestMan::Request.new(
|
125
|
+
:method => :get,
|
126
|
+
:url => 'https://www.mozilla.org',
|
127
|
+
:read_timeout => 1e-10,
|
128
|
+
)
|
129
|
+
expect { request.execute }.to(
|
130
|
+
raise_error(RestMan::Exceptions::ReadTimeout))
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'webmock/rspec'
|
2
|
+
require 'rest-man'
|
3
|
+
|
4
|
+
require_relative './helpers'
|
5
|
+
require 'byebug' unless RUBY_PLATFORM == 'java'
|
6
|
+
require 'ruby-debug' if RUBY_PLATFORM == 'java'
|
7
|
+
require 'vcr'
|
8
|
+
|
9
|
+
VCR.configure do |config|
|
10
|
+
config.default_cassette_options = { match_requests_on: %i[uri method] }
|
11
|
+
config.cassette_library_dir = 'spec/cassettes'
|
12
|
+
config.hook_into :webmock
|
13
|
+
end
|
14
|
+
|
15
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
16
|
+
RSpec.configure do |config|
|
17
|
+
config.raise_errors_for_deprecations!
|
18
|
+
|
19
|
+
# Run specs in random order to surface order dependencies. If you find an
|
20
|
+
# order dependency and want to debug it, you can fix the order by providing
|
21
|
+
# the seed, which is printed after each run.
|
22
|
+
# --seed 1234
|
23
|
+
config.order = 'random'
|
24
|
+
|
25
|
+
# always run with ruby warnings enabled
|
26
|
+
# TODO: figure out why this is so obscenely noisy (rspec bug?)
|
27
|
+
# config.warnings = true
|
28
|
+
|
29
|
+
# add helpers
|
30
|
+
config.include Helpers, :include_helpers
|
31
|
+
|
32
|
+
config.filter_run_when_matching :focus
|
33
|
+
|
34
|
+
config.mock_with :rspec do |mocks|
|
35
|
+
mocks.yield_receiver_to_any_instance_implementation_blocks = true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# always run with ruby warnings enabled (see above)
|
40
|
+
$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 RestMan::AbstractResponse, :include_helpers do
|
4
|
+
|
5
|
+
# Sample class implementing AbstractResponse used for testing.
|
6
|
+
class MyAbstractResponse
|
7
|
+
|
8
|
+
include RestMan::AbstractResponse
|
9
|
+
|
10
|
+
attr_accessor :size
|
11
|
+
|
12
|
+
def initialize(net_http_res, request)
|
13
|
+
response_set_vars(net_http_res, request, Time.now - 1)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
@net_http_res = res_double()
|
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 = RestMan::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 = RestMan::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(RestMan::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(RestMan::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('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
|
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 RestMan::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 RestMan::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 RestMan::Found
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|