rest-client 1.7.0.rc1-x86-mingw32
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.
Potentially problematic release.
This version of rest-client might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.travis.yml +14 -0
- data/AUTHORS +81 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.rdoc +325 -0
- data/Rakefile +117 -0
- data/bin/restclient +93 -0
- data/history.md +166 -0
- data/lib/rest-client.rb +2 -0
- data/lib/rest_client.rb +2 -0
- data/lib/restclient.rb +164 -0
- data/lib/restclient/abstract_response.rb +106 -0
- data/lib/restclient/exceptions.rb +203 -0
- data/lib/restclient/payload.rb +240 -0
- data/lib/restclient/platform.rb +30 -0
- data/lib/restclient/raw_response.rb +34 -0
- data/lib/restclient/request.rb +582 -0
- data/lib/restclient/resource.rb +169 -0
- data/lib/restclient/response.rb +24 -0
- data/lib/restclient/version.rb +7 -0
- data/lib/restclient/windows.rb +8 -0
- data/lib/restclient/windows/root_certs.rb +105 -0
- data/rest-client.gemspec +30 -0
- data/rest-client.windows.gemspec +19 -0
- data/spec/integration/capath_digicert/244b5494.0 +19 -0
- data/spec/integration/capath_digicert/81b9768f.0 +19 -0
- data/spec/integration/capath_digicert/README +8 -0
- data/spec/integration/capath_digicert/digicert.crt +19 -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 +19 -0
- data/spec/integration/certs/verisign.crt +14 -0
- data/spec/integration/integration_spec.rb +35 -0
- data/spec/integration/request_spec.rb +104 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/unit/abstract_response_spec.rb +85 -0
- data/spec/unit/exceptions_spec.rb +95 -0
- data/spec/unit/master_shake.jpg +0 -0
- data/spec/unit/payload_spec.rb +245 -0
- data/spec/unit/raw_response_spec.rb +17 -0
- data/spec/unit/request2_spec.rb +32 -0
- data/spec/unit/request_spec.rb +905 -0
- data/spec/unit/resource_spec.rb +133 -0
- data/spec/unit/response_spec.rb +166 -0
- data/spec/unit/restclient_spec.rb +79 -0
- data/spec/unit/windows/root_certs_spec.rb +22 -0
- metadata +241 -0
@@ -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,8 @@
|
|
1
|
+
The CA path symlinks can be created by c_rehash(1ssl).
|
2
|
+
|
3
|
+
But in order for the tests to work on Windows, they have to be regular files.
|
4
|
+
You can turn them all into regular files by running this on a GNU system:
|
5
|
+
|
6
|
+
for file in $(find . -type l); do
|
7
|
+
cp -iv --remove-destination $(readlink -e $file) $file
|
8
|
+
done
|
@@ -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,19 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
|
3
|
+
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
|
4
|
+
KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
|
5
|
+
MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
|
6
|
+
MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
|
7
|
+
Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
|
8
|
+
Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
|
9
|
+
OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
|
10
|
+
MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
|
11
|
+
NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
|
12
|
+
h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
|
13
|
+
Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
|
14
|
+
JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
|
15
|
+
V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
|
16
|
+
myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
|
17
|
+
mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
|
18
|
+
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
|
19
|
+
-----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,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RestClient do
|
4
|
+
|
5
|
+
it "a simple request" do
|
6
|
+
body = 'abc'
|
7
|
+
stub_request(:get, "www.example.com").to_return(:body => body, :status => 200)
|
8
|
+
response = RestClient.get "www.example.com"
|
9
|
+
response.code.should eq 200
|
10
|
+
response.body.should eq 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"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "a 404" do
|
21
|
+
body = "Ho hai ! I'm not here !"
|
22
|
+
stub_request(:get, "www.example.com").to_return(:body => body, :status => 404)
|
23
|
+
begin
|
24
|
+
RestClient.get "www.example.com"
|
25
|
+
raise
|
26
|
+
rescue RestClient::ResourceNotFound => e
|
27
|
+
e.http_code.should eq 404
|
28
|
+
e.response.code.should eq 404
|
29
|
+
e.response.body.should eq body
|
30
|
+
e.http_body.should eq body
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RestClient::Request do
|
4
|
+
before(:all) do
|
5
|
+
WebMock.disable!
|
6
|
+
end
|
7
|
+
|
8
|
+
after(:all) do
|
9
|
+
WebMock.enable!
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "ssl verification" do
|
13
|
+
it "is successful with the correct ca_file" do
|
14
|
+
request = RestClient::Request.new(
|
15
|
+
:method => :get,
|
16
|
+
:url => 'https://www.mozilla.org',
|
17
|
+
:ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "digicert.crt")
|
18
|
+
)
|
19
|
+
expect { request.execute }.to_not raise_error
|
20
|
+
end
|
21
|
+
|
22
|
+
it "is successful with the correct ca_path" do
|
23
|
+
request = RestClient::Request.new(
|
24
|
+
:method => :get,
|
25
|
+
:url => 'https://www.mozilla.org',
|
26
|
+
:ssl_ca_path => File.join(File.dirname(__FILE__), "capath_digicert")
|
27
|
+
)
|
28
|
+
expect { request.execute }.to_not raise_error
|
29
|
+
end
|
30
|
+
|
31
|
+
# TODO: deprecate and remove RestClient::SSLCertificateNotVerified and just
|
32
|
+
# pass through OpenSSL::SSL::SSLError directly. See note in
|
33
|
+
# lib/restclient/request.rb.
|
34
|
+
#
|
35
|
+
# On OS X, this test fails since Apple has patched OpenSSL to always fall
|
36
|
+
# back on the system CA store.
|
37
|
+
it "is unsuccessful with an incorrect ca_file", :unless => RestClient::Platform.mac? do
|
38
|
+
request = RestClient::Request.new(
|
39
|
+
:method => :get,
|
40
|
+
:url => 'https://www.mozilla.org',
|
41
|
+
:ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "verisign.crt")
|
42
|
+
)
|
43
|
+
expect { request.execute }.to raise_error(RestClient::SSLCertificateNotVerified)
|
44
|
+
end
|
45
|
+
|
46
|
+
# On OS X, this test fails since Apple has patched OpenSSL to always fall
|
47
|
+
# back on the system CA store.
|
48
|
+
it "is unsuccessful with an incorrect ca_path", :unless => RestClient::Platform.mac? do
|
49
|
+
request = RestClient::Request.new(
|
50
|
+
:method => :get,
|
51
|
+
:url => 'https://www.mozilla.org',
|
52
|
+
:ssl_ca_path => File.join(File.dirname(__FILE__), "capath_verisign")
|
53
|
+
)
|
54
|
+
expect { request.execute }.to raise_error(RestClient::SSLCertificateNotVerified)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "is successful using the default system cert store" do
|
58
|
+
request = RestClient::Request.new(
|
59
|
+
:method => :get,
|
60
|
+
:url => 'https://www.mozilla.org',
|
61
|
+
:verify_ssl => true,
|
62
|
+
)
|
63
|
+
expect {request.execute }.to_not raise_error
|
64
|
+
end
|
65
|
+
|
66
|
+
it "executes the verify_callback" do
|
67
|
+
ran_callback = false
|
68
|
+
request = RestClient::Request.new(
|
69
|
+
:method => :get,
|
70
|
+
:url => 'https://www.mozilla.org',
|
71
|
+
:verify_ssl => true,
|
72
|
+
:ssl_verify_callback => lambda { |preverify_ok, store_ctx|
|
73
|
+
ran_callback = true
|
74
|
+
preverify_ok
|
75
|
+
},
|
76
|
+
)
|
77
|
+
expect {request.execute }.to_not raise_error
|
78
|
+
ran_callback.should eq(true)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "fails verification when the callback returns false",
|
82
|
+
:unless => RestClient::Platform.mac? do
|
83
|
+
request = RestClient::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(RestClient::SSLCertificateNotVerified)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "succeeds verification when the callback returns true",
|
93
|
+
:unless => RestClient::Platform.mac? do
|
94
|
+
request = RestClient::Request.new(
|
95
|
+
:method => :get,
|
96
|
+
:url => 'https://www.mozilla.org',
|
97
|
+
:verify_ssl => true,
|
98
|
+
:ssl_ca_file => File.join(File.dirname(__FILE__), "certs", "verisign.crt"),
|
99
|
+
:ssl_verify_callback => lambda { |preverify_ok, store_ctx| true },
|
100
|
+
)
|
101
|
+
expect { request.execute }.to_not raise_error
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RestClient::AbstractResponse do
|
4
|
+
|
5
|
+
class MyAbstractResponse
|
6
|
+
|
7
|
+
include RestClient::AbstractResponse
|
8
|
+
|
9
|
+
attr_accessor :size
|
10
|
+
|
11
|
+
def initialize net_http_res, args
|
12
|
+
@net_http_res = net_http_res
|
13
|
+
@args = args
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
@net_http_res = double('net http response')
|
20
|
+
@response = MyAbstractResponse.new(@net_http_res, {})
|
21
|
+
end
|
22
|
+
|
23
|
+
it "fetches the numeric response code" do
|
24
|
+
@net_http_res.should_receive(:code).and_return('200')
|
25
|
+
@response.code.should eq 200
|
26
|
+
end
|
27
|
+
|
28
|
+
it "has a nice description" do
|
29
|
+
@net_http_res.should_receive(:to_hash).and_return({'Content-Type' => ['application/pdf']})
|
30
|
+
@net_http_res.should_receive(:code).and_return('200')
|
31
|
+
@response.description.should eq "200 OK | application/pdf bytes\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
it "beautifies the headers by turning the keys to symbols" do
|
35
|
+
h = RestClient::AbstractResponse.beautify_headers('content-type' => [ 'x' ])
|
36
|
+
h.keys.first.should eq :content_type
|
37
|
+
end
|
38
|
+
|
39
|
+
it "beautifies the headers by turning the values to strings instead of one-element arrays" do
|
40
|
+
h = RestClient::AbstractResponse.beautify_headers('x' => [ 'text/html' ] )
|
41
|
+
h.values.first.should eq 'text/html'
|
42
|
+
end
|
43
|
+
|
44
|
+
it "fetches the headers" do
|
45
|
+
@net_http_res.should_receive(:to_hash).and_return('content-type' => [ 'text/html' ])
|
46
|
+
@response.headers.should eq({ :content_type => 'text/html' })
|
47
|
+
end
|
48
|
+
|
49
|
+
it "extracts cookies from response headers" do
|
50
|
+
@net_http_res.should_receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/'])
|
51
|
+
@response.cookies.should eq({ 'session_id' => '1' })
|
52
|
+
end
|
53
|
+
|
54
|
+
it "extract strange cookies" do
|
55
|
+
@net_http_res.should_receive(:to_hash).and_return('set-cookie' => ['session_id=ZJ/HQVH6YE+rVkTpn0zvTQ==; path=/'])
|
56
|
+
@response.cookies.should eq({ 'session_id' => 'ZJ%2FHQVH6YE+rVkTpn0zvTQ%3D%3D' })
|
57
|
+
end
|
58
|
+
|
59
|
+
it "doesn't escape cookies" do
|
60
|
+
@net_http_res.should_receive(:to_hash).and_return('set-cookie' => ['session_id=BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca; path=/'])
|
61
|
+
@response.cookies.should eq({ 'session_id' => 'BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca' })
|
62
|
+
end
|
63
|
+
|
64
|
+
it "can access the net http result directly" do
|
65
|
+
@response.net_http_res.should eq @net_http_res
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#return!" do
|
69
|
+
it "should return the response itself on 200-codes" do
|
70
|
+
@net_http_res.should_receive(:code).and_return('200')
|
71
|
+
@response.return!.should be_equal(@response)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should raise RequestFailed on unknown codes" do
|
75
|
+
@net_http_res.should_receive(:code).and_return('1000')
|
76
|
+
lambda { @response.return! }.should raise_error RestClient::RequestFailed
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should raise an error on a redirection after non-GET/HEAD requests" do
|
80
|
+
@net_http_res.should_receive(:code).and_return('301')
|
81
|
+
@response.args.merge(:method => :put)
|
82
|
+
lambda { @response.return! }.should raise_error RestClient::RequestFailed
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RestClient::Exception do
|
4
|
+
it "returns a 'message' equal to the class name if the message is not set, because 'message' should not be nil" do
|
5
|
+
e = RestClient::Exception.new
|
6
|
+
e.message.should eq "RestClient::Exception"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns the 'message' that was set" do
|
10
|
+
e = RestClient::Exception.new
|
11
|
+
message = "An explicitly set message"
|
12
|
+
e.message = message
|
13
|
+
e.message.should eq message
|
14
|
+
end
|
15
|
+
|
16
|
+
it "sets the exception message to ErrorMessage" do
|
17
|
+
RestClient::ResourceNotFound.new.message.should eq 'Resource Not Found'
|
18
|
+
end
|
19
|
+
|
20
|
+
it "contains exceptions in RestClient" do
|
21
|
+
RestClient::Unauthorized.new.should be_a_kind_of(RestClient::Exception)
|
22
|
+
RestClient::ServerBrokeConnection.new.should be_a_kind_of(RestClient::Exception)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe RestClient::ServerBrokeConnection do
|
27
|
+
it "should have a default message of 'Server broke connection'" do
|
28
|
+
e = RestClient::ServerBrokeConnection.new
|
29
|
+
e.message.should eq 'Server broke connection'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe RestClient::RequestFailed do
|
34
|
+
before do
|
35
|
+
@response = double('HTTP Response', :code => '502')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "stores the http response on the exception" do
|
39
|
+
response = "response"
|
40
|
+
begin
|
41
|
+
raise RestClient::RequestFailed, response
|
42
|
+
rescue RestClient::RequestFailed => e
|
43
|
+
e.response.should eq response
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "http_code convenience method for fetching the code as an integer" do
|
48
|
+
RestClient::RequestFailed.new(@response).http_code.should eq 502
|
49
|
+
end
|
50
|
+
|
51
|
+
it "http_body convenience method for fetching the body (decoding when necessary)" do
|
52
|
+
RestClient::RequestFailed.new(@response).http_code.should eq 502
|
53
|
+
RestClient::RequestFailed.new(@response).message.should eq 'HTTP status code 502'
|
54
|
+
end
|
55
|
+
|
56
|
+
it "shows the status code in the message" do
|
57
|
+
RestClient::RequestFailed.new(@response).to_s.should match(/502/)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe RestClient::ResourceNotFound do
|
62
|
+
it "also has the http response attached" do
|
63
|
+
response = "response"
|
64
|
+
begin
|
65
|
+
raise RestClient::ResourceNotFound, response
|
66
|
+
rescue RestClient::ResourceNotFound => e
|
67
|
+
e.response.should eq response
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "backwards compatibility" do
|
73
|
+
it "alias RestClient::Request::Redirect to RestClient::Redirect" do
|
74
|
+
RestClient::Request::Redirect.should eq RestClient::Redirect
|
75
|
+
end
|
76
|
+
|
77
|
+
it "alias RestClient::Request::Unauthorized to RestClient::Unauthorized" do
|
78
|
+
RestClient::Request::Unauthorized.should eq RestClient::Unauthorized
|
79
|
+
end
|
80
|
+
|
81
|
+
it "alias RestClient::Request::RequestFailed to RestClient::RequestFailed" do
|
82
|
+
RestClient::Request::RequestFailed.should eq RestClient::RequestFailed
|
83
|
+
end
|
84
|
+
|
85
|
+
it "make the exception's response act like an Net::HTTPResponse" do
|
86
|
+
body = "body"
|
87
|
+
stub_request(:get, "www.example.com").to_return(:body => body, :status => 404)
|
88
|
+
begin
|
89
|
+
RestClient.get "www.example.com"
|
90
|
+
raise
|
91
|
+
rescue RestClient::ResourceNotFound => e
|
92
|
+
e.response.body.should eq body
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
Binary file
|
@@ -0,0 +1,245 @@
|
|
1
|
+
# encoding: binary
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe RestClient::Payload do
|
6
|
+
context "A regular Payload" do
|
7
|
+
it "should use standard enctype as default content-type" do
|
8
|
+
RestClient::Payload::UrlEncoded.new({}).headers['Content-Type'].
|
9
|
+
should eq 'application/x-www-form-urlencoded'
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should form properly encoded params" do
|
13
|
+
RestClient::Payload::UrlEncoded.new({:foo => 'bar'}).to_s.
|
14
|
+
should eq "foo=bar"
|
15
|
+
["foo=bar&baz=qux", "baz=qux&foo=bar"].should include(
|
16
|
+
RestClient::Payload::UrlEncoded.new({:foo => 'bar', :baz => 'qux'}).to_s)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should escape parameters" do
|
20
|
+
RestClient::Payload::UrlEncoded.new({'foo ' => 'bar'}).to_s.
|
21
|
+
should eq "foo%20=bar"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should properly handle hashes as parameter" do
|
25
|
+
RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz'}}).to_s.
|
26
|
+
should eq "foo[bar]=baz"
|
27
|
+
RestClient::Payload::UrlEncoded.new({:foo => {:bar => {:baz => 'qux'}}}).to_s.
|
28
|
+
should eq "foo[bar][baz]=qux"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should handle many attributes inside a hash" do
|
32
|
+
parameters = RestClient::Payload::UrlEncoded.new({:foo => {:bar => 'baz', :baz => 'qux'}}).to_s
|
33
|
+
parameters.should include("foo[bar]=baz", "foo[baz]=qux")
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should handle attributes inside a an array inside an hash" do
|
37
|
+
parameters = RestClient::Payload::UrlEncoded.new({"foo" => [{"bar" => 'baz'}, {"bar" => 'qux'}]}).to_s
|
38
|
+
parameters.should include("foo[bar]=baz", "foo[bar]=qux")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should handle attributes inside a an array inside an array inside an hash" do
|
42
|
+
parameters = RestClient::Payload::UrlEncoded.new({"foo" => [[{"bar" => 'baz'}, {"bar" => 'qux'}]]}).to_s
|
43
|
+
parameters.should include("foo[bar]=baz", "foo[bar]=qux")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should form properly use symbols as parameters" do
|
47
|
+
RestClient::Payload::UrlEncoded.new({:foo => :bar}).to_s.
|
48
|
+
should eq "foo=bar"
|
49
|
+
RestClient::Payload::UrlEncoded.new({:foo => {:bar => :baz}}).to_s.
|
50
|
+
should eq "foo[bar]=baz"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should properly handle arrays as repeated parameters" do
|
54
|
+
RestClient::Payload::UrlEncoded.new({:foo => ['bar']}).to_s.
|
55
|
+
should eq "foo[]=bar"
|
56
|
+
RestClient::Payload::UrlEncoded.new({:foo => ['bar', 'baz']}).to_s.
|
57
|
+
should eq "foo[]=bar&foo[]=baz"
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should not close if stream already closed' do
|
61
|
+
p = RestClient::Payload::UrlEncoded.new({'foo ' => 'bar'})
|
62
|
+
3.times {p.close}
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
context "A multipart Payload" do
|
68
|
+
it "should use standard enctype as default content-type" do
|
69
|
+
m = RestClient::Payload::Multipart.new({})
|
70
|
+
m.stub(:boundary).and_return(123)
|
71
|
+
m.headers['Content-Type'].should eq 'multipart/form-data; boundary=123'
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should not error on close if stream already closed' do
|
75
|
+
m = RestClient::Payload::Multipart.new(:file => File.new(File.join(File.dirname(File.expand_path(__FILE__)), 'master_shake.jpg')))
|
76
|
+
3.times {m.close}
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should form properly separated multipart data" do
|
80
|
+
m = RestClient::Payload::Multipart.new([[:bar, "baz"], [:foo, "bar"]])
|
81
|
+
m.to_s.should eq <<-EOS
|
82
|
+
--#{m.boundary}\r
|
83
|
+
Content-Disposition: form-data; name="bar"\r
|
84
|
+
\r
|
85
|
+
baz\r
|
86
|
+
--#{m.boundary}\r
|
87
|
+
Content-Disposition: form-data; name="foo"\r
|
88
|
+
\r
|
89
|
+
bar\r
|
90
|
+
--#{m.boundary}--\r
|
91
|
+
EOS
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should not escape parameters names" do
|
95
|
+
m = RestClient::Payload::Multipart.new([["bar ", "baz"]])
|
96
|
+
m.to_s.should eq <<-EOS
|
97
|
+
--#{m.boundary}\r
|
98
|
+
Content-Disposition: form-data; name="bar "\r
|
99
|
+
\r
|
100
|
+
baz\r
|
101
|
+
--#{m.boundary}--\r
|
102
|
+
EOS
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should form properly separated multipart data" do
|
106
|
+
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
107
|
+
m = RestClient::Payload::Multipart.new({:foo => f})
|
108
|
+
m.to_s.should eq <<-EOS
|
109
|
+
--#{m.boundary}\r
|
110
|
+
Content-Disposition: form-data; name="foo"; filename="master_shake.jpg"\r
|
111
|
+
Content-Type: image/jpeg\r
|
112
|
+
\r
|
113
|
+
#{File.open(f.path, 'rb'){|bin| bin.read}}\r
|
114
|
+
--#{m.boundary}--\r
|
115
|
+
EOS
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should ignore the name attribute when it's not set" do
|
119
|
+
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
120
|
+
m = RestClient::Payload::Multipart.new({nil => f})
|
121
|
+
m.to_s.should eq <<-EOS
|
122
|
+
--#{m.boundary}\r
|
123
|
+
Content-Disposition: form-data; filename="master_shake.jpg"\r
|
124
|
+
Content-Type: image/jpeg\r
|
125
|
+
\r
|
126
|
+
#{File.open(f.path, 'rb'){|bin| bin.read}}\r
|
127
|
+
--#{m.boundary}--\r
|
128
|
+
EOS
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should detect optional (original) content type and filename" do
|
132
|
+
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
133
|
+
f.instance_eval "def content_type; 'text/plain'; end"
|
134
|
+
f.instance_eval "def original_filename; 'foo.txt'; end"
|
135
|
+
m = RestClient::Payload::Multipart.new({:foo => f})
|
136
|
+
m.to_s.should eq <<-EOS
|
137
|
+
--#{m.boundary}\r
|
138
|
+
Content-Disposition: form-data; name="foo"; filename="foo.txt"\r
|
139
|
+
Content-Type: text/plain\r
|
140
|
+
\r
|
141
|
+
#{File.open(f.path, 'rb'){|bin| bin.read}}\r
|
142
|
+
--#{m.boundary}--\r
|
143
|
+
EOS
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should handle hash in hash parameters" do
|
147
|
+
m = RestClient::Payload::Multipart.new({:bar => {:baz => "foo"}})
|
148
|
+
m.to_s.should eq <<-EOS
|
149
|
+
--#{m.boundary}\r
|
150
|
+
Content-Disposition: form-data; name="bar[baz]"\r
|
151
|
+
\r
|
152
|
+
foo\r
|
153
|
+
--#{m.boundary}--\r
|
154
|
+
EOS
|
155
|
+
|
156
|
+
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
157
|
+
f.instance_eval "def content_type; 'text/plain'; end"
|
158
|
+
f.instance_eval "def original_filename; 'foo.txt'; end"
|
159
|
+
m = RestClient::Payload::Multipart.new({:foo => {:bar => f}})
|
160
|
+
m.to_s.should eq <<-EOS
|
161
|
+
--#{m.boundary}\r
|
162
|
+
Content-Disposition: form-data; name="foo[bar]"; filename="foo.txt"\r
|
163
|
+
Content-Type: text/plain\r
|
164
|
+
\r
|
165
|
+
#{File.open(f.path, 'rb'){|bin| bin.read}}\r
|
166
|
+
--#{m.boundary}--\r
|
167
|
+
EOS
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
context "streamed payloads" do
|
173
|
+
it "should properly determine the size of file payloads" do
|
174
|
+
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
175
|
+
payload = RestClient::Payload.generate(f)
|
176
|
+
payload.size.should eq 76_988
|
177
|
+
payload.length.should eq 76_988
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should properly determine the size of other kinds of streaming payloads" do
|
181
|
+
s = StringIO.new 'foo'
|
182
|
+
payload = RestClient::Payload.generate(s)
|
183
|
+
payload.size.should eq 3
|
184
|
+
payload.length.should eq 3
|
185
|
+
|
186
|
+
begin
|
187
|
+
f = Tempfile.new "rest-client"
|
188
|
+
f.write 'foo bar'
|
189
|
+
|
190
|
+
payload = RestClient::Payload.generate(f)
|
191
|
+
payload.size.should eq 7
|
192
|
+
payload.length.should eq 7
|
193
|
+
ensure
|
194
|
+
f.close
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
context "Payload generation" do
|
200
|
+
it "should recognize standard urlencoded params" do
|
201
|
+
RestClient::Payload.generate({"foo" => 'bar'}).should be_kind_of(RestClient::Payload::UrlEncoded)
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should recognize multipart params" do
|
205
|
+
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
206
|
+
RestClient::Payload.generate({"foo" => f}).should be_kind_of(RestClient::Payload::Multipart)
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should be multipart if forced" do
|
210
|
+
RestClient::Payload.generate({"foo" => "bar", :multipart => true}).should be_kind_of(RestClient::Payload::Multipart)
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should return data if no of the above" do
|
214
|
+
RestClient::Payload.generate("data").should be_kind_of(RestClient::Payload::Base)
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should recognize nested multipart payloads in hashes" do
|
218
|
+
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
219
|
+
RestClient::Payload.generate({"foo" => {"file" => f}}).should be_kind_of(RestClient::Payload::Multipart)
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should recognize nested multipart payloads in arrays" do
|
223
|
+
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
224
|
+
RestClient::Payload.generate({"foo" => [f]}).should be_kind_of(RestClient::Payload::Multipart)
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should recognize file payloads that can be streamed" do
|
228
|
+
f = File.new(File.dirname(__FILE__) + "/master_shake.jpg")
|
229
|
+
RestClient::Payload.generate(f).should be_kind_of(RestClient::Payload::Streamed)
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should recognize other payloads that can be streamed" do
|
233
|
+
RestClient::Payload.generate(StringIO.new('foo')).should be_kind_of(RestClient::Payload::Streamed)
|
234
|
+
end
|
235
|
+
|
236
|
+
# hashery gem introduces Hash#read convenience method. Existence of #read method used to determine of content is streameable :/
|
237
|
+
it "shouldn't treat hashes as streameable" do
|
238
|
+
RestClient::Payload.generate({"foo" => 'bar'}).should be_kind_of(RestClient::Payload::UrlEncoded)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
class HashMapForTesting < Hash
|
243
|
+
alias :read :[]
|
244
|
+
end
|
245
|
+
end
|