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.

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
@@ -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