httpi 2.0.2 → 2.1.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +42 -16
- data/Gemfile +12 -6
- data/README.md +19 -9
- data/httpi.gemspec +2 -1
- data/lib/httpi.rb +3 -0
- data/lib/httpi/adapter.rb +1 -1
- data/lib/httpi/adapter/curb.rb +11 -2
- data/lib/httpi/adapter/em_http.rb +21 -9
- data/lib/httpi/adapter/excon.rb +80 -0
- data/lib/httpi/adapter/httpclient.rb +13 -6
- data/lib/httpi/adapter/net_http.rb +88 -9
- data/lib/httpi/adapter/net_http_persistent.rb +43 -0
- data/lib/httpi/adapter/rack.rb +92 -0
- data/lib/httpi/auth/config.rb +6 -5
- data/lib/httpi/request.rb +9 -0
- data/lib/httpi/version.rb +1 -1
- data/spec/httpi/adapter/curb_spec.rb +17 -0
- data/spec/httpi/adapter/em_http_spec.rb +37 -27
- data/spec/httpi/adapter/excon_spec.rb +96 -0
- data/spec/httpi/adapter/httpclient_spec.rb +16 -8
- data/spec/httpi/adapter/net_http_persistent_spec.rb +96 -0
- data/spec/httpi/adapter/net_http_spec.rb +24 -151
- data/spec/httpi/adapter/rack_spec.rb +111 -0
- data/spec/httpi/auth/config_spec.rb +28 -0
- data/spec/httpi/httpi_spec.rb +17 -1
- data/spec/integration/curb_spec.rb +12 -0
- data/spec/integration/em_http_spec.rb +2 -0
- data/spec/integration/httpclient_spec.rb +32 -18
- data/spec/integration/net_http_persistent_spec.rb +139 -0
- data/spec/integration/net_http_spec.rb +59 -14
- data/spec/integration/support/application.rb +28 -0
- data/spec/spec_helper.rb +15 -6
- metadata +34 -32
- data/.rvmrc +0 -1
@@ -132,4 +132,32 @@ describe HTTPI::Auth::Config do
|
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|
135
|
+
describe "#ntlm" do
|
136
|
+
it "lets you specify the ntlm auth credentials" do
|
137
|
+
auth.ntlm "username", "password"
|
138
|
+
auth.ntlm.should == ["username", "password"]
|
139
|
+
end
|
140
|
+
|
141
|
+
it "also accepts an Array of credentials" do
|
142
|
+
auth.ntlm ["username", "password"]
|
143
|
+
auth.ntlm.should == ["username", "password"]
|
144
|
+
end
|
145
|
+
|
146
|
+
it "sets the authentication type to :ntlm" do
|
147
|
+
auth.ntlm "username", "password"
|
148
|
+
auth.type.should == :ntlm
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "#ntlm?" do
|
153
|
+
it "defaults to return false" do
|
154
|
+
auth.should_not be_ntlm
|
155
|
+
end
|
156
|
+
|
157
|
+
it "returns true for HTTP ntlm auth" do
|
158
|
+
auth.ntlm "username", "password"
|
159
|
+
auth.should be_ntlm
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
135
163
|
end
|
data/spec/httpi/httpi_spec.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require "spec_helper"
|
2
|
+
require "integration/support/server"
|
2
3
|
|
3
4
|
# find out why httpi doesn't load these automatically. [dh, 2012-12-15]
|
5
|
+
require "excon"
|
6
|
+
require "net/http/persistent"
|
7
|
+
|
4
8
|
unless RUBY_VERSION < "1.9"
|
5
9
|
require "em-synchrony"
|
6
10
|
require "em-http-request"
|
@@ -13,6 +17,15 @@ describe HTTPI do
|
|
13
17
|
let(:client) { HTTPI }
|
14
18
|
let(:httpclient) { HTTPI::Adapter.load(:httpclient) }
|
15
19
|
let(:net_http) { HTTPI::Adapter.load(:net_http) }
|
20
|
+
let(:net_http_persistent) { HTTPI::Adapter.load(:net_http_persistent) }
|
21
|
+
|
22
|
+
before(:all) do
|
23
|
+
HTTPI::Adapter::Rack.mount('example.com', IntegrationServer::Application)
|
24
|
+
end
|
25
|
+
|
26
|
+
after(:all) do
|
27
|
+
HTTPI::Adapter::Rack.unmount('example.com')
|
28
|
+
end
|
16
29
|
|
17
30
|
describe ".adapter=" do
|
18
31
|
it "sets the default adapter to use" do
|
@@ -204,7 +217,10 @@ describe HTTPI do
|
|
204
217
|
:httpclient => lambda { HTTPClient },
|
205
218
|
:curb => lambda { Curl::Easy },
|
206
219
|
:net_http => lambda { Net::HTTP },
|
207
|
-
:
|
220
|
+
:net_http_persistent => lambda { Net::HTTP::Persistent },
|
221
|
+
:em_http => lambda { EventMachine::HttpConnection },
|
222
|
+
:rack => lambda { Rack::MockRequest },
|
223
|
+
:excon => lambda { Excon::Connection }
|
208
224
|
}
|
209
225
|
|
210
226
|
context "using #{adapter}" do
|
@@ -78,6 +78,18 @@ describe HTTPI::Adapter::Curb do
|
|
78
78
|
response = HTTPI.get(request, adapter)
|
79
79
|
response.body.should eq("digest-auth")
|
80
80
|
end
|
81
|
+
|
82
|
+
it "supports chunked response" do
|
83
|
+
request = HTTPI::Request.new(@server.url)
|
84
|
+
res = ""
|
85
|
+
request.on_body do |body|
|
86
|
+
res += body
|
87
|
+
end
|
88
|
+
response = HTTPI.post(request, adapter)
|
89
|
+
res.should eq("post")
|
90
|
+
response.body.should eq("")
|
91
|
+
end
|
92
|
+
|
81
93
|
end
|
82
94
|
|
83
95
|
context "https requests" do
|
@@ -75,27 +75,41 @@ describe HTTPI::Adapter::HTTPClient do
|
|
75
75
|
response = HTTPI.get(request, adapter)
|
76
76
|
response.body.should eq("digest-auth")
|
77
77
|
end
|
78
|
-
end
|
79
|
-
|
80
|
-
context "https requests" do
|
81
|
-
before :all do
|
82
|
-
@server = IntegrationServer.run(:ssl => true)
|
83
|
-
end
|
84
78
|
|
85
|
-
|
86
|
-
@server.stop
|
87
|
-
end
|
88
|
-
|
89
|
-
it "raises when no certificate was set up" do
|
90
|
-
expect { HTTPI.post(@server.url, "", adapter) }.to raise_error(HTTPI::SSLError)
|
91
|
-
end
|
92
|
-
|
93
|
-
it "works when set up properly" do
|
79
|
+
it "supports chunked response" do
|
94
80
|
request = HTTPI::Request.new(@server.url)
|
95
|
-
|
81
|
+
res = ""
|
82
|
+
request.on_body do |body|
|
83
|
+
res += body
|
84
|
+
end
|
85
|
+
response = HTTPI.post(request, adapter)
|
86
|
+
res.should eq("post")
|
87
|
+
response.body.should eq("")
|
88
|
+
end
|
89
|
+
end
|
96
90
|
|
97
|
-
|
98
|
-
|
91
|
+
if RUBY_PLATFORM =~ /java/
|
92
|
+
pending "Puma Server complains: SSL not supported on JRuby"
|
93
|
+
else
|
94
|
+
context "https requests" do
|
95
|
+
before :all do
|
96
|
+
@server = IntegrationServer.run(:ssl => true)
|
97
|
+
end
|
98
|
+
after :all do
|
99
|
+
@server.stop
|
100
|
+
end
|
101
|
+
|
102
|
+
it "raises when no certificate was set up" do
|
103
|
+
expect { HTTPI.post(@server.url, "", adapter) }.to raise_error(HTTPI::SSLError)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "works when set up properly" do
|
107
|
+
request = HTTPI::Request.new(@server.url)
|
108
|
+
request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file
|
109
|
+
|
110
|
+
response = HTTPI.get(request, adapter)
|
111
|
+
expect(response.body).to eq("get")
|
112
|
+
end
|
99
113
|
end
|
100
114
|
end
|
101
115
|
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "integration/support/server"
|
3
|
+
|
4
|
+
describe HTTPI::Adapter::NetHTTP do
|
5
|
+
|
6
|
+
subject(:adapter) { :net_http_persistent }
|
7
|
+
|
8
|
+
context "http requests" do
|
9
|
+
before :all do
|
10
|
+
@server = IntegrationServer.run
|
11
|
+
end
|
12
|
+
|
13
|
+
after :all do
|
14
|
+
@server.stop
|
15
|
+
end
|
16
|
+
|
17
|
+
it "sends and receives HTTP headers" do
|
18
|
+
request = HTTPI::Request.new(@server.url + "x-header")
|
19
|
+
request.headers["X-Header"] = "HTTPI"
|
20
|
+
|
21
|
+
response = HTTPI.get(request, adapter)
|
22
|
+
response.body.should include("HTTPI")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "it supports headers with multiple values" do
|
26
|
+
request = HTTPI::Request.new(@server.url + "cookies")
|
27
|
+
|
28
|
+
response = HTTPI.get(request, adapter)
|
29
|
+
cookies = ["cookie1=chip1; path=/", "cookie2=chip2; path=/"]
|
30
|
+
response.headers["Set-Cookie"].should eq(cookies)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "executes GET requests" do
|
34
|
+
response = HTTPI.get(@server.url, adapter)
|
35
|
+
response.body.should eq("get")
|
36
|
+
response.headers["Content-Type"].should eq("text/plain")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "executes POST requests" do
|
40
|
+
response = HTTPI.post(@server.url, "<some>xml</some>", adapter)
|
41
|
+
response.body.should eq("post")
|
42
|
+
response.headers["Content-Type"].should eq("text/plain")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "executes HEAD requests" do
|
46
|
+
response = HTTPI.head(@server.url, adapter)
|
47
|
+
response.code.should == 200
|
48
|
+
response.headers["Content-Type"].should eq("text/plain")
|
49
|
+
end
|
50
|
+
|
51
|
+
it "executes PUT requests" do
|
52
|
+
response = HTTPI.put(@server.url, "<some>xml</some>", adapter)
|
53
|
+
response.body.should eq("put")
|
54
|
+
response.headers["Content-Type"].should eq("text/plain")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "executes DELETE requests" do
|
58
|
+
response = HTTPI.delete(@server.url, adapter)
|
59
|
+
response.body.should eq("delete")
|
60
|
+
response.headers["Content-Type"].should eq("text/plain")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "supports basic authentication" do
|
64
|
+
request = HTTPI::Request.new(@server.url + "basic-auth")
|
65
|
+
request.auth.basic("admin", "secret")
|
66
|
+
|
67
|
+
response = HTTPI.get(request, adapter)
|
68
|
+
response.body.should eq("basic-auth")
|
69
|
+
end
|
70
|
+
|
71
|
+
# it does not support digest authentication
|
72
|
+
|
73
|
+
it "supports chunked response" do
|
74
|
+
request = HTTPI::Request.new(@server.url)
|
75
|
+
res = ""
|
76
|
+
request.on_body do |body|
|
77
|
+
res += body
|
78
|
+
end
|
79
|
+
response = HTTPI.post(request, adapter)
|
80
|
+
res.should eq("post")
|
81
|
+
response.body.to_s.should eq("")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
if RUBY_PLATFORM =~ /java/
|
86
|
+
pending "Puma Server complains: SSL not supported on JRuby"
|
87
|
+
else
|
88
|
+
context "https requests" do
|
89
|
+
before :all do
|
90
|
+
@server = IntegrationServer.run(:ssl => true)
|
91
|
+
end
|
92
|
+
after :all do
|
93
|
+
@server.stop
|
94
|
+
end
|
95
|
+
|
96
|
+
# does not raise when no certificate was set up
|
97
|
+
it "works when set up properly" do
|
98
|
+
request = HTTPI::Request.new(@server.url)
|
99
|
+
request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file
|
100
|
+
|
101
|
+
response = HTTPI.get(request, adapter)
|
102
|
+
expect(response.body).to eq("get")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# The built-in Rack IntegrationServer and specs support a basic simulated NTLM exchange
|
108
|
+
# that does not require anything outside of the normal gem test infrastructure.
|
109
|
+
# (see spec/httpi/adapter/net_http_spec.rb: it "supports ntlm authentication"
|
110
|
+
# and spec/integration/support/application.rb: map "/ntlm-auth")
|
111
|
+
# But since that simulated exchange is based on recorded traffic, you may wish to
|
112
|
+
# run the following integration test against a real external NTLM server from time to time.
|
113
|
+
#
|
114
|
+
# This test must be specially enabled because it requires an external
|
115
|
+
# Windows 2012 Server configured according to the instructions found here:
|
116
|
+
# https://github.com/savonrb/httpi/wiki/NTLM-Integration-Test-Plan
|
117
|
+
#
|
118
|
+
# Once you have that server running as instructed, you can include this test by setting
|
119
|
+
# NTLM=external via the command line, e.g.:
|
120
|
+
# $ NTLM=external bundle exec rspec
|
121
|
+
#
|
122
|
+
if ENV["NTLM"]=="external"
|
123
|
+
context "http request via NTLM" do
|
124
|
+
it "works with NTLM connections" do
|
125
|
+
user = "tester"
|
126
|
+
pass = "vReqSoafRe5O"
|
127
|
+
request = HTTPI::Request.new("http://ntlmtest/")
|
128
|
+
request.auth.ntlm(user,pass)
|
129
|
+
response = HTTPI.get(request, adapter)
|
130
|
+
expect(response.code).to eq(200)
|
131
|
+
response.body.should match(/iis-8\.png/)
|
132
|
+
|
133
|
+
puts "EXTERNAL NTLM INTEGRATION TEST, response body:"
|
134
|
+
puts response.body
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
@@ -69,25 +69,70 @@ describe HTTPI::Adapter::NetHTTP do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
# it does not support digest authentication
|
72
|
-
end
|
73
72
|
|
74
|
-
|
75
|
-
|
76
|
-
|
73
|
+
it "supports chunked response" do
|
74
|
+
request = HTTPI::Request.new(@server.url)
|
75
|
+
res = ""
|
76
|
+
request.on_body do |body|
|
77
|
+
res += body
|
78
|
+
end
|
79
|
+
response = HTTPI.post(request, adapter)
|
80
|
+
res.should eq("post")
|
81
|
+
response.body.to_s.should eq("")
|
77
82
|
end
|
83
|
+
end
|
78
84
|
|
79
|
-
|
80
|
-
|
85
|
+
if RUBY_PLATFORM =~ /java/
|
86
|
+
pending "Puma Server complains: SSL not supported on JRuby"
|
87
|
+
else
|
88
|
+
context "https requests" do
|
89
|
+
before :all do
|
90
|
+
@server = IntegrationServer.run(:ssl => true)
|
91
|
+
end
|
92
|
+
after :all do
|
93
|
+
@server.stop
|
94
|
+
end
|
95
|
+
|
96
|
+
# does not raise when no certificate was set up
|
97
|
+
it "works when set up properly" do
|
98
|
+
request = HTTPI::Request.new(@server.url)
|
99
|
+
request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file
|
100
|
+
|
101
|
+
response = HTTPI.get(request, adapter)
|
102
|
+
expect(response.body).to eq("get")
|
103
|
+
end
|
81
104
|
end
|
105
|
+
end
|
82
106
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
107
|
+
# The built-in Rack IntegrationServer and specs support a basic simulated NTLM exchange
|
108
|
+
# that does not require anything outside of the normal gem test infrastructure.
|
109
|
+
# (see spec/httpi/adapter/net_http_spec.rb: it "supports ntlm authentication"
|
110
|
+
# and spec/integration/support/application.rb: map "/ntlm-auth")
|
111
|
+
# But since that simulated exchange is based on recorded traffic, you may wish to
|
112
|
+
# run the following integration test against a real external NTLM server from time to time.
|
113
|
+
#
|
114
|
+
# This test must be specially enabled because it requires an external
|
115
|
+
# Windows 2012 Server configured according to the instructions found here:
|
116
|
+
# https://github.com/savonrb/httpi/wiki/NTLM-Integration-Test-Plan
|
117
|
+
#
|
118
|
+
# Once you have that server running as instructed, you can include this test by setting
|
119
|
+
# NTLM=external via the command line, e.g.:
|
120
|
+
# $ NTLM=external bundle exec rspec
|
121
|
+
#
|
122
|
+
if ENV["NTLM"]=="external"
|
123
|
+
context "http request via NTLM" do
|
124
|
+
it "works with NTLM connections" do
|
125
|
+
user = "tester"
|
126
|
+
pass = "vReqSoafRe5O"
|
127
|
+
request = HTTPI::Request.new("http://ntlmtest/")
|
128
|
+
request.auth.ntlm(user,pass)
|
129
|
+
response = HTTPI.get(request, adapter)
|
130
|
+
expect(response.code).to eq(200)
|
131
|
+
response.body.should match(/iis-8\.png/)
|
132
|
+
|
133
|
+
puts "EXTERNAL NTLM INTEGRATION TEST, response body:"
|
134
|
+
puts response.body
|
135
|
+
end
|
91
136
|
end
|
92
137
|
end
|
93
138
|
|
@@ -47,6 +47,34 @@ class IntegrationServer
|
|
47
47
|
}
|
48
48
|
end
|
49
49
|
|
50
|
+
map "/ntlm-auth" do
|
51
|
+
run lambda { |env|
|
52
|
+
resp = [401, {"WWW-Authenticate" => "NTLM\r\nNegotiate"}, []]
|
53
|
+
# head request 1: challenge & response (from actual server)
|
54
|
+
if env["HTTP_AUTHORIZATION"] =~ /(NTLM|Negotiate) TlRMTVNTUAABAAAAB4IIAA/
|
55
|
+
resp = [401, {
|
56
|
+
"Content-Type" => "text/html; charset=us-ascii",
|
57
|
+
"Server" => "Microsoft-HTTPAPI/2.0",
|
58
|
+
"WWW-Authenticate" => "#{$1} TlRMTVNTUAACAAAAEAAQADgAAAAFgooCj/AvDazHhQsAAAAAAAAAAGAAYABIAAAABgLwIwAAAA9OAFQATABNAFQARQBTAFQAAgAQAE4AVABMAE0AVABFAFMAVAABABAATgBUAEwATQBUAEUAUwBUAAQAEABuAHQAbABtAHQAZQBzAHQAAwAQAG4AdABsAG0AdABlAHMAdAAHAAgAfzQp037nzQEAAAAA",
|
59
|
+
"Date" => "Mon, 31 Dec 2012 17:46:55 GMT",
|
60
|
+
"Content-Length" => "341"
|
61
|
+
}, []]
|
62
|
+
elsif env["HTTP_AUTHORIZATION"] =~ /(NTLM|Negotiate) (.+)/
|
63
|
+
# request 2: serve content
|
64
|
+
resp = IntegrationServer.respond_with "ntlm-auth"
|
65
|
+
else
|
66
|
+
resp = [401, {
|
67
|
+
"Content-Type" => "text/html; charset=us-ascii",
|
68
|
+
"WWW-Authenticate" => "NTLM\r\nNegotiate",
|
69
|
+
"Server" => "Microsoft-HTTPAPI/2.0",
|
70
|
+
"Date" => "Mon, 31 Dec 2012 17:46:55 GMT",
|
71
|
+
"Content-Length" => "341"
|
72
|
+
}, []]
|
73
|
+
end
|
74
|
+
resp
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
50
78
|
map "/digest-auth" do
|
51
79
|
unprotected_app = lambda { |env|
|
52
80
|
IntegrationServer.respond_with "digest-auth"
|
data/spec/spec_helper.rb
CHANGED
@@ -1,16 +1,25 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler'
|
2
2
|
Bundler.setup(:default, :development)
|
3
3
|
|
4
|
-
|
4
|
+
unless RUBY_PLATFORM =~ /java/
|
5
|
+
require 'simplecov'
|
6
|
+
require 'coveralls'
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
+
SimpleCov.formatter = Coveralls::SimpleCov::Formatter
|
9
|
+
SimpleCov.start do
|
10
|
+
add_filter 'spec'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'httpi'
|
15
|
+
require 'rspec'
|
8
16
|
|
9
17
|
RSpec.configure do |config|
|
10
18
|
config.mock_with :mocha
|
19
|
+
config.order = 'random'
|
11
20
|
end
|
12
21
|
|
13
22
|
HTTPI.log = false
|
14
23
|
|
15
|
-
require
|
16
|
-
require
|
24
|
+
require 'support/fixture'
|
25
|
+
require 'support/matchers'
|