rest-client 1.7.0.rc1-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rest-client might be problematic. Click here for more details.

Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +14 -0
  5. data/AUTHORS +81 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE +21 -0
  8. data/README.rdoc +325 -0
  9. data/Rakefile +117 -0
  10. data/bin/restclient +93 -0
  11. data/history.md +166 -0
  12. data/lib/rest-client.rb +2 -0
  13. data/lib/rest_client.rb +2 -0
  14. data/lib/restclient.rb +164 -0
  15. data/lib/restclient/abstract_response.rb +106 -0
  16. data/lib/restclient/exceptions.rb +203 -0
  17. data/lib/restclient/payload.rb +240 -0
  18. data/lib/restclient/platform.rb +30 -0
  19. data/lib/restclient/raw_response.rb +34 -0
  20. data/lib/restclient/request.rb +582 -0
  21. data/lib/restclient/resource.rb +169 -0
  22. data/lib/restclient/response.rb +24 -0
  23. data/lib/restclient/version.rb +7 -0
  24. data/lib/restclient/windows.rb +8 -0
  25. data/lib/restclient/windows/root_certs.rb +105 -0
  26. data/rest-client.gemspec +30 -0
  27. data/rest-client.windows.gemspec +19 -0
  28. data/spec/integration/capath_digicert/244b5494.0 +19 -0
  29. data/spec/integration/capath_digicert/81b9768f.0 +19 -0
  30. data/spec/integration/capath_digicert/README +8 -0
  31. data/spec/integration/capath_digicert/digicert.crt +19 -0
  32. data/spec/integration/capath_verisign/415660c1.0 +14 -0
  33. data/spec/integration/capath_verisign/7651b327.0 +14 -0
  34. data/spec/integration/capath_verisign/README +8 -0
  35. data/spec/integration/capath_verisign/verisign.crt +14 -0
  36. data/spec/integration/certs/digicert.crt +19 -0
  37. data/spec/integration/certs/verisign.crt +14 -0
  38. data/spec/integration/integration_spec.rb +35 -0
  39. data/spec/integration/request_spec.rb +104 -0
  40. data/spec/spec_helper.rb +12 -0
  41. data/spec/unit/abstract_response_spec.rb +85 -0
  42. data/spec/unit/exceptions_spec.rb +95 -0
  43. data/spec/unit/master_shake.jpg +0 -0
  44. data/spec/unit/payload_spec.rb +245 -0
  45. data/spec/unit/raw_response_spec.rb +17 -0
  46. data/spec/unit/request2_spec.rb +32 -0
  47. data/spec/unit/request_spec.rb +905 -0
  48. data/spec/unit/resource_spec.rb +133 -0
  49. data/spec/unit/response_spec.rb +166 -0
  50. data/spec/unit/restclient_spec.rb +79 -0
  51. data/spec/unit/windows/root_certs_spec.rb +22 -0
  52. 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
@@ -0,0 +1,12 @@
1
+ def is_ruby_19?
2
+ RUBY_VERSION > '1.9'
3
+ end
4
+
5
+ begin
6
+ require "ruby-debug"
7
+ rescue LoadError
8
+ # NOP, ignore
9
+ end
10
+
11
+ require 'webmock/rspec'
12
+ require 'restclient'
@@ -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