httpi 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +10 -10
- data/README.md +40 -9
- data/lib/httpi.rb +9 -0
- data/lib/httpi/adapter/curb.rb +15 -6
- data/lib/httpi/adapter/httpclient.rb +20 -11
- data/lib/httpi/adapter/net_http.rb +14 -10
- data/lib/httpi/auth/config.rb +68 -0
- data/lib/httpi/auth/ssl.rb +76 -0
- data/lib/httpi/request.rb +32 -48
- data/lib/httpi/version.rb +1 -1
- data/spec/fixtures/client_cert.pem +16 -0
- data/spec/fixtures/client_key.pem +15 -0
- data/spec/httpi/adapter/curb_spec.rb +136 -10
- data/spec/httpi/adapter/httpclient_spec.rb +99 -33
- data/spec/httpi/adapter/net_http_spec.rb +99 -28
- data/spec/httpi/auth/config_spec.rb +117 -0
- data/spec/httpi/auth/ssl_spec.rb +112 -0
- data/spec/httpi/httpi_spec.rb +45 -37
- data/spec/httpi/request_spec.rb +38 -73
- data/spec/integration/request_spec.rb +3 -3
- metadata +14 -10
@@ -3,6 +3,7 @@ require "httpi/adapter/net_http"
|
|
3
3
|
require "httpi/request"
|
4
4
|
|
5
5
|
describe HTTPI::Adapter::NetHTTP do
|
6
|
+
let(:net_http) { Net::HTTP.any_instance }
|
6
7
|
|
7
8
|
def adapter(request)
|
8
9
|
@adapter ||= HTTPI::Adapter::NetHTTP.new request
|
@@ -16,58 +17,128 @@ describe HTTPI::Adapter::NetHTTP do
|
|
16
17
|
end
|
17
18
|
|
18
19
|
describe "#get" do
|
19
|
-
before do
|
20
|
-
@request = HTTPI::Request.new :url => "http://example.com"
|
21
|
-
stub_request(:get, @request.url.to_s).to_return(:body => Fixture.xml)
|
22
|
-
end
|
23
|
-
|
24
20
|
it "should return a valid HTTPI::Response" do
|
25
|
-
|
21
|
+
stub_request(:get, basic_request.url.to_s).to_return(:body => Fixture.xml)
|
22
|
+
adapter(basic_request).get(basic_request).should match_response(:body => Fixture.xml)
|
26
23
|
end
|
27
24
|
end
|
28
25
|
|
29
26
|
describe "#post" do
|
30
|
-
before do
|
31
|
-
@request = HTTPI::Request.new :url => "http://example.com", :body => Fixture.xml
|
32
|
-
stub_request(:post, @request.url.to_s).with(:body => @request.body).to_return(:body => Fixture.xml)
|
33
|
-
end
|
34
|
-
|
35
27
|
it "should return a valid HTTPI::Response" do
|
36
|
-
|
28
|
+
request = HTTPI::Request.new :url => "http://example.com", :body => Fixture.xml
|
29
|
+
stub_request(:post, request.url.to_s).with(:body => request.body).to_return(:body => Fixture.xml)
|
30
|
+
|
31
|
+
adapter(request).post(request).should match_response(:body => Fixture.xml)
|
37
32
|
end
|
38
33
|
end
|
39
34
|
|
40
35
|
describe "#head" do
|
41
|
-
before do
|
42
|
-
@request = HTTPI::Request.new :url => "http://example.com"
|
43
|
-
stub_request(:head, @request.url.to_s).to_return(:body => Fixture.xml)
|
44
|
-
end
|
45
|
-
|
46
36
|
it "should return a valid HTTPI::Response" do
|
47
|
-
|
37
|
+
stub_request(:head, basic_request.url.to_s).to_return(:body => Fixture.xml)
|
38
|
+
adapter(basic_request).head(basic_request).should match_response(:body => Fixture.xml)
|
48
39
|
end
|
49
40
|
end
|
50
41
|
|
51
42
|
describe "#put" do
|
52
|
-
|
53
|
-
|
54
|
-
stub_request(:put,
|
43
|
+
it "should return a valid HTTPI::Response" do
|
44
|
+
request = HTTPI::Request.new :url => "http://example.com", :body => Fixture.xml
|
45
|
+
stub_request(:put, request.url.to_s).with(:body => request.body).to_return(:body => Fixture.xml)
|
46
|
+
|
47
|
+
adapter(request).put(request).should match_response(:body => Fixture.xml)
|
55
48
|
end
|
49
|
+
end
|
56
50
|
|
51
|
+
describe "#delete" do
|
57
52
|
it "should return a valid HTTPI::Response" do
|
58
|
-
|
53
|
+
stub_request(:delete, basic_request.url.to_s)
|
54
|
+
adapter(basic_request).delete(basic_request).should match_response(:body => "")
|
59
55
|
end
|
60
56
|
end
|
61
57
|
|
62
|
-
describe "
|
63
|
-
before
|
64
|
-
|
65
|
-
|
58
|
+
describe "settings:" do
|
59
|
+
before { stub_request(:get, basic_request.url.to_s) }
|
60
|
+
|
61
|
+
describe "use_ssl" do
|
62
|
+
it "should be set to false for non-SSL requests" do
|
63
|
+
net_http.expects(:use_ssl=).with(false)
|
64
|
+
adapter(basic_request).get(basic_request)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should be set to true for SSL requests" do
|
68
|
+
request = basic_request { |request| request.ssl = true }
|
69
|
+
|
70
|
+
net_http.expects(:use_ssl=).with(true)
|
71
|
+
adapter(request).get(request)
|
72
|
+
end
|
66
73
|
end
|
67
74
|
|
68
|
-
|
69
|
-
|
75
|
+
describe "open_timeout" do
|
76
|
+
it "should not be set if not specified" do
|
77
|
+
net_http.expects(:open_timeout=).never
|
78
|
+
adapter(basic_request).get(basic_request)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should be set if specified" do
|
82
|
+
request = basic_request { |request| request.open_timeout = 30 }
|
83
|
+
|
84
|
+
net_http.expects(:open_timeout=).with(30)
|
85
|
+
adapter(request).get(request)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "read_timeout" do
|
90
|
+
it "should not be set if not specified" do
|
91
|
+
net_http.expects(:read_timeout=).never
|
92
|
+
adapter(basic_request).get(basic_request)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should be set if specified" do
|
96
|
+
request = basic_request { |request| request.read_timeout = 30 }
|
97
|
+
|
98
|
+
net_http.expects(:read_timeout=).with(30)
|
99
|
+
adapter(request).get(request)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "basic_auth" do
|
104
|
+
it "should be set for HTTP basic auth" do
|
105
|
+
request = basic_request { |request| request.auth.basic "username", "password" }
|
106
|
+
|
107
|
+
stub_request(:get, "http://username:password@example.com")
|
108
|
+
Net::HTTP::Get.any_instance.expects(:basic_auth).with(*request.auth.credentials)
|
109
|
+
adapter(request).get(request)
|
110
|
+
end
|
70
111
|
end
|
112
|
+
|
113
|
+
context "(for SSL client auth)" do
|
114
|
+
let(:ssl_auth_request) do
|
115
|
+
basic_request do |request|
|
116
|
+
request.auth.ssl.cert_key_file = "spec/fixtures/client_key.pem"
|
117
|
+
request.auth.ssl.cert_file = "spec/fixtures/client_cert.pem"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
it "key, cert and verify_mode should be set" do
|
122
|
+
net_http.expects(:cert=).with(ssl_auth_request.auth.ssl.cert)
|
123
|
+
net_http.expects(:key=).with(ssl_auth_request.auth.ssl.cert_key)
|
124
|
+
net_http.expects(:verify_mode=).with(ssl_auth_request.auth.ssl.openssl_verify_mode)
|
125
|
+
|
126
|
+
adapter(ssl_auth_request).get(ssl_auth_request)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should set the client_ca if specified" do
|
130
|
+
ssl_auth_request.auth.ssl.ca_cert_file = "spec/fixtures/client_cert.pem"
|
131
|
+
net_http.expects(:ca_file=).with(ssl_auth_request.auth.ssl.ca_cert_file)
|
132
|
+
|
133
|
+
adapter(ssl_auth_request).get(ssl_auth_request)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def basic_request
|
139
|
+
request = HTTPI::Request.new "http://example.com"
|
140
|
+
yield request if block_given?
|
141
|
+
request
|
71
142
|
end
|
72
143
|
|
73
144
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "httpi/auth/config"
|
3
|
+
|
4
|
+
describe HTTPI::Auth::Config do
|
5
|
+
let(:auth) { HTTPI::Auth::Config.new }
|
6
|
+
|
7
|
+
describe "#basic" do
|
8
|
+
it "lets you specify the basic auth credentials" do
|
9
|
+
auth.basic "username", "password"
|
10
|
+
auth.basic.should == ["username", "password"]
|
11
|
+
end
|
12
|
+
|
13
|
+
it "also accepts an Array of credentials" do
|
14
|
+
auth.basic ["username", "password"]
|
15
|
+
auth.basic.should == ["username", "password"]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "sets the authentication type to :basic" do
|
19
|
+
auth.basic "username", "password"
|
20
|
+
auth.type.should == :basic
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#basic?" do
|
25
|
+
it "should default to return false" do
|
26
|
+
auth.should_not be_basic
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return true for HTTP basic auth" do
|
30
|
+
auth.basic "username", "password"
|
31
|
+
auth.should be_basic
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#digest" do
|
36
|
+
it "lets you specify the digest auth credentials" do
|
37
|
+
auth.digest "username", "password"
|
38
|
+
auth.digest.should == ["username", "password"]
|
39
|
+
end
|
40
|
+
|
41
|
+
it "also accepts an Array of credentials" do
|
42
|
+
auth.digest ["username", "password"]
|
43
|
+
auth.digest.should == ["username", "password"]
|
44
|
+
end
|
45
|
+
|
46
|
+
it "sets the authentication type to :digest" do
|
47
|
+
auth.digest "username", "password"
|
48
|
+
auth.type.should == :digest
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#digest?" do
|
53
|
+
it "should default to return false" do
|
54
|
+
auth.should_not be_digest
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return true for HTTP digest auth" do
|
58
|
+
auth.digest "username", "password"
|
59
|
+
auth.should be_digest
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#http?" do
|
64
|
+
it "should default to return false" do
|
65
|
+
auth.should_not be_http
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should return true for HTTP basic auth" do
|
69
|
+
auth.basic "username", "password"
|
70
|
+
auth.should be_http
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should return true for HTTP digest auth" do
|
74
|
+
auth.digest "username", "password"
|
75
|
+
auth.should be_http
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#ssl" do
|
80
|
+
it "should return the HTTPI::Auth::SSL object" do
|
81
|
+
auth.ssl.should be_a(HTTPI::Auth::SSL)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#ssl?" do
|
86
|
+
it "should default to return false" do
|
87
|
+
auth.should_not be_ssl
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should return true for SSL client auth" do
|
91
|
+
auth.ssl.cert_key_file = "spec/fixtures/client_key.pem"
|
92
|
+
auth.ssl.cert_file = "spec/fixtures/client_cert.pem"
|
93
|
+
|
94
|
+
auth.should be_ssl
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#type" do
|
99
|
+
it "should return the authentication type" do
|
100
|
+
auth.basic "username", "password"
|
101
|
+
auth.type.should == :basic
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#credentials" do
|
106
|
+
it "return the credentials for HTTP basic auth" do
|
107
|
+
auth.basic "username", "basic"
|
108
|
+
auth.credentials.should == ["username", "basic"]
|
109
|
+
end
|
110
|
+
|
111
|
+
it "return the credentials for HTTP digest auth" do
|
112
|
+
auth.digest "username", "digest"
|
113
|
+
auth.credentials.should == ["username", "digest"]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "httpi/auth/ssl"
|
3
|
+
|
4
|
+
describe HTTPI::Auth::SSL do
|
5
|
+
|
6
|
+
describe "VERIFY_MODES" do
|
7
|
+
it "should contain the supported SSL verify modes" do
|
8
|
+
HTTPI::Auth::SSL::VERIFY_MODES.should == [:none, :peer, :fail_if_no_peer_cert, :client_once]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#present?" do
|
13
|
+
it "should default to return false" do
|
14
|
+
ssl = HTTPI::Auth::SSL.new
|
15
|
+
ssl.should_not be_present
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return false if only a client key was specified" do
|
19
|
+
ssl = HTTPI::Auth::SSL.new
|
20
|
+
ssl.cert_key_file = "spec/fixtures/client_key.pem"
|
21
|
+
|
22
|
+
ssl.should_not be_present
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return false if only a client key was specified" do
|
26
|
+
ssl = HTTPI::Auth::SSL.new
|
27
|
+
ssl.cert_file = "spec/fixtures/client_cert.pem"
|
28
|
+
|
29
|
+
ssl.should_not be_present
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return true if both client key and cert are present" do
|
33
|
+
ssl.should be_present
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#verify_mode" do
|
38
|
+
it "should default to return :peer" do
|
39
|
+
ssl.verify_mode.should == :peer
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should set the verify mode to use" do
|
43
|
+
ssl = HTTPI::Auth::SSL.new
|
44
|
+
|
45
|
+
ssl.verify_mode = :none
|
46
|
+
ssl.verify_mode.should == :none
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should raise an ArgumentError if the given mode is not supported" do
|
50
|
+
lambda { ssl.verify_mode = :invalid }.should raise_error(ArgumentError)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#cert" do
|
55
|
+
it "should return an OpenSSL::X509::Certificate for the given cert_file" do
|
56
|
+
ssl.cert.should be_a(OpenSSL::X509::Certificate)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#cert_key" do
|
61
|
+
it "should return a OpenSSL::PKey::RSA for the given cert_key" do
|
62
|
+
ssl.cert_key.should be_a(OpenSSL::PKey::RSA)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#ca_cert" do
|
67
|
+
it "should return an OpenSSL::X509::Certificate for the given ca_cert_file" do
|
68
|
+
ssl = HTTPI::Auth::SSL.new
|
69
|
+
|
70
|
+
ssl.ca_cert_file = "spec/fixtures/client_cert.pem"
|
71
|
+
ssl.ca_cert.should be_a(OpenSSL::X509::Certificate)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#openssl_verify_mode" do
|
76
|
+
it "should return the OpenSSL verify mode for :none" do
|
77
|
+
ssl = HTTPI::Auth::SSL.new
|
78
|
+
|
79
|
+
ssl.verify_mode = :none
|
80
|
+
ssl.openssl_verify_mode.should == OpenSSL::SSL::VERIFY_NONE
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should return the OpenSSL verify mode for :peer" do
|
84
|
+
ssl = HTTPI::Auth::SSL.new
|
85
|
+
|
86
|
+
ssl.verify_mode = :peer
|
87
|
+
ssl.openssl_verify_mode.should == OpenSSL::SSL::VERIFY_PEER
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should return the OpenSSL verify mode for :fail_if_no_peer_cert" do
|
91
|
+
ssl = HTTPI::Auth::SSL.new
|
92
|
+
|
93
|
+
ssl.verify_mode = :fail_if_no_peer_cert
|
94
|
+
ssl.openssl_verify_mode.should == OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should return the OpenSSL verify mode for :client_once" do
|
98
|
+
ssl = HTTPI::Auth::SSL.new
|
99
|
+
|
100
|
+
ssl.verify_mode = :client_once
|
101
|
+
ssl.openssl_verify_mode.should == OpenSSL::SSL::VERIFY_CLIENT_ONCE
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def ssl
|
106
|
+
ssl = HTTPI::Auth::SSL.new
|
107
|
+
ssl.cert_key_file = "spec/fixtures/client_key.pem"
|
108
|
+
ssl.cert_file = "spec/fixtures/client_cert.pem"
|
109
|
+
ssl
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
data/spec/httpi/httpi_spec.rb
CHANGED
@@ -42,28 +42,6 @@ describe HTTPI do
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
shared_examples_for "a request method" do
|
46
|
-
context "(with a block)" do
|
47
|
-
it "should yield the HTTP client instance used for the request" do
|
48
|
-
client.delete "http://example.com" do |http|
|
49
|
-
http.should be_an(HTTPClient)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
it "and raise an ArgumentError in case of an invalid adapter" do
|
55
|
-
lambda { client.delete HTTPI::Request.new, :invalid }.should raise_error(ArgumentError)
|
56
|
-
end
|
57
|
-
|
58
|
-
it "and raise an ArgumentError in case of an invalid URL" do
|
59
|
-
lambda { client.delete "invalid" }.should raise_error(ArgumentError)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
describe ".get" do
|
64
|
-
it_should_behave_like "a request method"
|
65
|
-
end
|
66
|
-
|
67
45
|
describe ".post(request)" do
|
68
46
|
it "should execute an HTTP POST request using the default adapter" do
|
69
47
|
request = HTTPI::Request.new
|
@@ -102,10 +80,6 @@ describe HTTPI do
|
|
102
80
|
end
|
103
81
|
end
|
104
82
|
|
105
|
-
describe ".post" do
|
106
|
-
it_should_behave_like "a request method"
|
107
|
-
end
|
108
|
-
|
109
83
|
describe ".head(request)" do
|
110
84
|
it "should execute an HTTP HEAD request using the default adapter" do
|
111
85
|
request = HTTPI::Request.new
|
@@ -142,10 +116,6 @@ describe HTTPI do
|
|
142
116
|
end
|
143
117
|
end
|
144
118
|
|
145
|
-
describe ".head" do
|
146
|
-
it_should_behave_like "a request method"
|
147
|
-
end
|
148
|
-
|
149
119
|
describe ".put(request)" do
|
150
120
|
it "should execute an HTTP PUT request using the default adapter" do
|
151
121
|
request = HTTPI::Request.new
|
@@ -184,10 +154,6 @@ describe HTTPI do
|
|
184
154
|
end
|
185
155
|
end
|
186
156
|
|
187
|
-
describe ".put" do
|
188
|
-
it_should_behave_like "a request method"
|
189
|
-
end
|
190
|
-
|
191
157
|
describe ".delete(request)" do
|
192
158
|
it "should execute an HTTP DELETE request using the default adapter" do
|
193
159
|
request = HTTPI::Request.new
|
@@ -223,9 +189,51 @@ describe HTTPI do
|
|
223
189
|
client.delete "http://example.com", :curb
|
224
190
|
end
|
225
191
|
end
|
226
|
-
|
227
|
-
describe ".
|
228
|
-
|
192
|
+
|
193
|
+
describe ".request" do
|
194
|
+
it "should raise an ArgumentError in case of an invalid request method" do
|
195
|
+
lambda { client.request :invalid, HTTPI::Request.new }.should raise_error(ArgumentError)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
HTTPI::REQUEST_METHODS.each do |method|
|
200
|
+
|
201
|
+
describe ".request(#{method}, request, adapter)" do
|
202
|
+
it "should delegate to the .#{method} method" do
|
203
|
+
HTTPI.expects(method)
|
204
|
+
client.request method, HTTPI::Request.new
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe ".#{method}" do
|
209
|
+
it "should raise an ArgumentError in case of an invalid adapter" do
|
210
|
+
lambda { client.request method, request, :invalid }.should raise_error(ArgumentError)
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should raise an ArgumentError in case of an invalid request" do
|
214
|
+
lambda { client.request method, "invalid" }.should raise_error(ArgumentError)
|
215
|
+
end
|
216
|
+
|
217
|
+
HTTPI::Adapter.adapters.each do |adapter, adapter_class|
|
218
|
+
client_class = {
|
219
|
+
:httpclient => lambda { HTTPClient },
|
220
|
+
:curb => lambda { Curl::Easy },
|
221
|
+
:net_http => lambda { Net::HTTP }
|
222
|
+
}
|
223
|
+
|
224
|
+
context "using :#{adapter} with a block" do
|
225
|
+
let(:request) { HTTPI::Request.new :url => "http://example.com" }
|
226
|
+
|
227
|
+
before { adapter_class.any_instance.stubs(method) }
|
228
|
+
|
229
|
+
it "should yield the HTTP client instance used for the request" do
|
230
|
+
block = lambda { |http| http.should be_a(client_class[adapter].call) }
|
231
|
+
client.request(method, request, adapter, &block)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
end
|
229
237
|
end
|
230
238
|
|
231
239
|
end
|