httpi 2.0.0.rc1 → 2.0.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.
- data/CHANGELOG.md +9 -1
- data/Gemfile +0 -1
- data/httpi.gemspec +5 -5
- data/lib/httpi.rb +13 -11
- data/lib/httpi/adapter/curb.rb +3 -0
- data/lib/httpi/adapter/httpclient.rb +3 -0
- data/lib/httpi/adapter/net_http.rb +3 -0
- data/lib/httpi/request.rb +15 -0
- data/lib/httpi/version.rb +1 -1
- data/spec/httpi/adapter/net_http_spec.rb +84 -10
- data/spec/httpi/error_spec.rb +43 -0
- data/spec/httpi/httpi_spec.rb +15 -3
- data/spec/httpi/request_spec.rb +29 -0
- data/spec/integration/curb_spec.rb +99 -0
- data/spec/integration/em_http_spec.rb +81 -0
- data/spec/integration/httpclient_spec.rb +94 -0
- data/spec/integration/net_http_spec.rb +86 -0
- data/spec/integration/support/application.rb +56 -0
- data/spec/integration/support/server.rb +84 -0
- data/spec/spec_helper.rb +7 -3
- data/spec/support/error_helper.rb +26 -0
- metadata +98 -111
- data/spec/integration/fixtures/ca.pem +0 -23
- data/spec/integration/fixtures/htdigest +0 -1
- data/spec/integration/fixtures/htpasswd +0 -2
- data/spec/integration/fixtures/subca.pem +0 -21
- data/spec/integration/request_spec.rb +0 -112
- data/spec/integration/server.rb +0 -39
- data/spec/integration/ssl_server.rb +0 -70
- data/spec/integration/ssl_spec.rb +0 -102
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
## 2.0.0
|
1
|
+
## 2.0.0 (2012-12-16)
|
2
|
+
|
3
|
+
* Feature: [#66](https://github.com/savonrb/httpi/pull/66) adds a `query` method
|
4
|
+
to the request.
|
5
|
+
|
6
|
+
* Fix: [#68](https://github.com/savonrb/httpi/issues/68) request does not yield
|
7
|
+
adapter client.
|
8
|
+
|
9
|
+
## 2.0.0.rc1 (2012-11-10)
|
2
10
|
|
3
11
|
* Feature: [#63](https://github.com/savonrb/httpi/pull/63) adds support for
|
4
12
|
EventMachine::HttpRequest. Additional information at [#40](https://github.com/savonrb/httpi/pull/40).
|
data/Gemfile
CHANGED
@@ -4,7 +4,6 @@ gemspec
|
|
4
4
|
gem "jruby-openssl", :platforms => :jruby
|
5
5
|
|
6
6
|
# http clients
|
7
|
-
gem "mock-server", :git => "https://github.com/djanowski/mock-server.git"
|
8
7
|
gem "httpclient", "~> 2.3", :require => false
|
9
8
|
gem "curb", "~> 0.8", :require => false, :platforms => :ruby
|
10
9
|
gem 'em-http-request', :require => false, :platforms => [:ruby, :jruby]
|
data/httpi.gemspec
CHANGED
@@ -10,16 +10,16 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.email = "me@rubiii.com"
|
11
11
|
s.homepage = "http://github.com/savonrb/#{s.name}"
|
12
12
|
s.summary = "Common interface for Ruby's HTTP libraries"
|
13
|
-
s.description =
|
13
|
+
s.description = s.summary
|
14
14
|
|
15
15
|
s.rubyforge_project = s.name
|
16
16
|
|
17
17
|
s.add_dependency "rack"
|
18
18
|
|
19
|
-
s.add_development_dependency "rake",
|
20
|
-
s.add_development_dependency "rspec",
|
21
|
-
s.add_development_dependency "mocha",
|
22
|
-
s.add_development_dependency "
|
19
|
+
s.add_development_dependency "rake", "~> 10.0"
|
20
|
+
s.add_development_dependency "rspec", "~> 2.12"
|
21
|
+
s.add_development_dependency "mocha", "~> 0.13"
|
22
|
+
s.add_development_dependency "puma", ">= 2.0.0.b3"
|
23
23
|
|
24
24
|
s.files = `git ls-files`.split("\n")
|
25
25
|
s.require_path = "lib"
|
data/lib/httpi.rb
CHANGED
@@ -85,9 +85,11 @@ module HTTPI
|
|
85
85
|
class NotSupportedError < Error; end
|
86
86
|
class NotImplementedError < Error; end
|
87
87
|
|
88
|
+
module ConnectionError; end
|
89
|
+
|
88
90
|
class SSLError < Error
|
89
91
|
def initialize(message = nil, original = $!)
|
90
|
-
super(message)
|
92
|
+
super(message || original.message)
|
91
93
|
@original = original
|
92
94
|
end
|
93
95
|
attr_reader :original
|
@@ -96,33 +98,33 @@ module HTTPI
|
|
96
98
|
class << self
|
97
99
|
|
98
100
|
# Executes an HTTP GET request.
|
99
|
-
def get(request, adapter = nil)
|
101
|
+
def get(request, adapter = nil, &block)
|
100
102
|
request = Request.new(request) if request.kind_of? String
|
101
|
-
request(:get, request, adapter)
|
103
|
+
request(:get, request, adapter, &block)
|
102
104
|
end
|
103
105
|
|
104
106
|
# Executes an HTTP POST request.
|
105
|
-
def post(*args)
|
107
|
+
def post(*args, &block)
|
106
108
|
request, adapter = request_and_adapter_from(args)
|
107
|
-
request(:post, request, adapter)
|
109
|
+
request(:post, request, adapter, &block)
|
108
110
|
end
|
109
111
|
|
110
112
|
# Executes an HTTP HEAD request.
|
111
|
-
def head(request, adapter = nil)
|
113
|
+
def head(request, adapter = nil, &block)
|
112
114
|
request = Request.new(request) if request.kind_of? String
|
113
|
-
request(:head, request, adapter)
|
115
|
+
request(:head, request, adapter, &block)
|
114
116
|
end
|
115
117
|
|
116
118
|
# Executes an HTTP PUT request.
|
117
|
-
def put(*args)
|
119
|
+
def put(*args, &block)
|
118
120
|
request, adapter = request_and_adapter_from(args)
|
119
|
-
request(:put, request, adapter)
|
121
|
+
request(:put, request, adapter, &block)
|
120
122
|
end
|
121
123
|
|
122
124
|
# Executes an HTTP DELETE request.
|
123
|
-
def delete(request, adapter = nil)
|
125
|
+
def delete(request, adapter = nil, &block)
|
124
126
|
request = Request.new(request) if request.kind_of? String
|
125
|
-
request(:delete, request, adapter)
|
127
|
+
request(:delete, request, adapter, &block)
|
126
128
|
end
|
127
129
|
|
128
130
|
# Executes an HTTP request for the given +method+.
|
data/lib/httpi/adapter/curb.rb
CHANGED
@@ -26,6 +26,9 @@ module HTTPI
|
|
26
26
|
respond_with @client.request(method, @request.url, nil, @request.body, @request.headers)
|
27
27
|
rescue OpenSSL::SSL::SSLError
|
28
28
|
raise SSLError
|
29
|
+
rescue Errno::ECONNREFUSED # connection refused
|
30
|
+
$!.extend ConnectionError
|
31
|
+
raise
|
29
32
|
end
|
30
33
|
|
31
34
|
private
|
data/lib/httpi/request.rb
CHANGED
@@ -31,6 +31,21 @@ module HTTPI
|
|
31
31
|
# Returns the +url+ to access.
|
32
32
|
attr_reader :url
|
33
33
|
|
34
|
+
# Sets the +query+ from +url+. Raises an +ArgumentError+ unless the +url+ is valid.
|
35
|
+
def query=(query)
|
36
|
+
raise ArgumentError, "Invalid URL: #{self.url}" unless self.url.respond_to?(:query)
|
37
|
+
if query.kind_of?(Hash)
|
38
|
+
query = Rack::Utils.build_query(query)
|
39
|
+
end
|
40
|
+
query = query.to_s unless query.is_a?(String)
|
41
|
+
self.url.query = query
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the +query+ from +url+.
|
45
|
+
def query
|
46
|
+
self.url.query if self.url.respond_to?(:query)
|
47
|
+
end
|
48
|
+
|
34
49
|
# Sets the +proxy+ to use. Raises an +ArgumentError+ unless the +proxy+ is valid.
|
35
50
|
def proxy=(proxy)
|
36
51
|
@proxy = normalize_url! proxy
|
data/lib/httpi/version.rb
CHANGED
@@ -1,18 +1,92 @@
|
|
1
1
|
require "spec_helper"
|
2
|
-
require "
|
3
|
-
require "httpi/request"
|
4
|
-
|
5
|
-
HTTPI::Adapter.load_adapter(:net_http)
|
2
|
+
require "integration/support/server"
|
6
3
|
|
7
4
|
describe HTTPI::Adapter::NetHTTP do
|
8
5
|
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
subject(:adapter) { :net_http }
|
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 "executes GET requests" do
|
26
|
+
response = HTTPI.get(@server.url, adapter)
|
27
|
+
response.body.should eq("get")
|
28
|
+
response.headers["Content-Type"].should eq("text/plain")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "executes POST requests" do
|
32
|
+
response = HTTPI.post(@server.url, "<some>xml</some>", adapter)
|
33
|
+
response.body.should eq("post")
|
34
|
+
response.headers["Content-Type"].should eq("text/plain")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "executes HEAD requests" do
|
38
|
+
response = HTTPI.head(@server.url, adapter)
|
39
|
+
response.code.should == 200
|
40
|
+
response.headers["Content-Type"].should eq("text/plain")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "executes PUT requests" do
|
44
|
+
response = HTTPI.put(@server.url, "<some>xml</some>", adapter)
|
45
|
+
response.body.should eq("put")
|
46
|
+
response.headers["Content-Type"].should eq("text/plain")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "executes DELETE requests" do
|
50
|
+
response = HTTPI.delete(@server.url, adapter)
|
51
|
+
response.body.should eq("delete")
|
52
|
+
response.headers["Content-Type"].should eq("text/plain")
|
53
|
+
end
|
54
|
+
|
55
|
+
it "supports basic authentication" do
|
56
|
+
request = HTTPI::Request.new(@server.url + "basic-auth")
|
57
|
+
request.auth.basic("admin", "secret")
|
58
|
+
|
59
|
+
response = HTTPI.get(request, adapter)
|
60
|
+
response.body.should eq("basic-auth")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# it does not support digest auth
|
65
|
+
|
66
|
+
context "https requests" do
|
67
|
+
before :all do
|
68
|
+
@server = IntegrationServer.run(:ssl => true)
|
69
|
+
end
|
70
|
+
|
71
|
+
after :all do
|
72
|
+
@server.stop
|
73
|
+
end
|
74
|
+
|
75
|
+
# it does not raise when no certificate was set up
|
76
|
+
|
77
|
+
it "works when set up properly" do
|
78
|
+
request = HTTPI::Request.new(@server.url)
|
79
|
+
request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file
|
80
|
+
|
81
|
+
response = HTTPI.get(request, adapter)
|
82
|
+
expect(response.body).to eq("get")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
12
88
|
|
13
|
-
|
14
|
-
HTTPI::Adapter::NetHTTP.new(request)
|
15
|
-
}
|
89
|
+
__END__
|
16
90
|
|
17
91
|
describe "#request(:get)" do
|
18
92
|
it "should return a valid HTTPI::Response" do
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "support/error_helper"
|
3
|
+
|
4
|
+
describe HTTPI do
|
5
|
+
include ErrorHelper
|
6
|
+
|
7
|
+
context "with :httpclient" do
|
8
|
+
it "tags Errno::ECONNREFUSED with HTTPI::ConnectionError" do
|
9
|
+
expect_error(Errno::ECONNREFUSED, "Connection refused - connect(2)").to be_tagged_with(HTTPI::ConnectionError)
|
10
|
+
end
|
11
|
+
|
12
|
+
def fake_error(error, message)
|
13
|
+
request(:httpclient) { |client| client.expects(:request).raises(error, message) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
unless RUBY_PLATFORM =~ /java/
|
18
|
+
context "with :curb" do
|
19
|
+
it "tags Curl::Err::ConnectionFailedError with HTTPI::ConnectionError" do
|
20
|
+
expect_error(Curl::Err::ConnectionFailedError, "Curl::Err::ConnectionFailedError").to be_tagged_with(HTTPI::ConnectionError)
|
21
|
+
end
|
22
|
+
|
23
|
+
def fake_error(error, message)
|
24
|
+
request(:curb) { |client| client.expects(:send).raises(error, message) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "with :net_http" do
|
30
|
+
it "tags Errno::ECONNREFUSED with HTTPI::ConnectionError" do
|
31
|
+
expect_error(Errno::ECONNREFUSED, "Connection refused - connect(2)").to be_tagged_with(HTTPI::ConnectionError)
|
32
|
+
end
|
33
|
+
|
34
|
+
def fake_error(error, message)
|
35
|
+
request(:net_http) { |client| client.expects(:start).raises(error, message) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def request(adapter)
|
40
|
+
HTTPI.get("http://example.com", adapter) { |client| yield client }
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/spec/httpi/httpi_spec.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
require "spec_helper"
|
2
|
-
|
2
|
+
|
3
|
+
# find out why httpi doesn't load these automatically. [dh, 2012-12-15]
|
4
|
+
unless RUBY_VERSION < "1.9"
|
5
|
+
require "em-synchrony"
|
6
|
+
require "em-http-request"
|
7
|
+
end
|
8
|
+
unless RUBY_PLATFORM =~ /java/
|
9
|
+
require "curb"
|
10
|
+
end
|
3
11
|
|
4
12
|
describe HTTPI do
|
5
13
|
let(:client) { HTTPI }
|
@@ -196,15 +204,19 @@ describe HTTPI do
|
|
196
204
|
:httpclient => lambda { HTTPClient },
|
197
205
|
:curb => lambda { Curl::Easy },
|
198
206
|
:net_http => lambda { Net::HTTP },
|
199
|
-
:em_http => lambda { EventMachine::
|
207
|
+
:em_http => lambda { EventMachine::HttpConnection }
|
200
208
|
}
|
201
209
|
|
202
210
|
context "using #{adapter}" do
|
203
211
|
before { opts[:class].any_instance.expects(:request).with(method) }
|
204
212
|
|
205
|
-
it "yields the HTTP client instance
|
213
|
+
it "#request yields the HTTP client instance" do
|
206
214
|
expect { |b| client.request(method, request, adapter, &b) }.to yield_with_args(client_class[adapter].call)
|
207
215
|
end
|
216
|
+
|
217
|
+
it "##{method} yields the HTTP client instance" do
|
218
|
+
expect { |b| client.send(method, request, adapter, &b) }.to yield_with_args(client_class[adapter].call)
|
219
|
+
end
|
208
220
|
end
|
209
221
|
end
|
210
222
|
end
|
data/spec/httpi/request_spec.rb
CHANGED
@@ -43,6 +43,35 @@ describe HTTPI::Request do
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
describe "#query" do
|
47
|
+
it "raises an ArgumentError if url not respond to query" do
|
48
|
+
expect { request.query = "q=query" }.to raise_error(ArgumentError)
|
49
|
+
end
|
50
|
+
it "lets you specify query parameter as String" do
|
51
|
+
request.url = "http://example.com"
|
52
|
+
request.query = "q=query"
|
53
|
+
request.url.to_s.should == "http://example.com?q=query"
|
54
|
+
end
|
55
|
+
it "lets you specify query parameter as Hash" do
|
56
|
+
request.url = "http://example.com"
|
57
|
+
request.query = {:q => "query"}
|
58
|
+
request.url.to_s.should == "http://example.com?q=query"
|
59
|
+
end
|
60
|
+
it "getter return nil for invalid url" do
|
61
|
+
request.query.should be_nil
|
62
|
+
end
|
63
|
+
it "getter return String for query parameter as String" do
|
64
|
+
request.url = "http://example.com"
|
65
|
+
request.query = "q=query"
|
66
|
+
request.query.should == "q=query"
|
67
|
+
end
|
68
|
+
it "getter return String for query parameter as Hash" do
|
69
|
+
request.url = "http://example.com"
|
70
|
+
request.query = {:q => "query"}
|
71
|
+
request.query.should == "q=query"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
46
75
|
describe "#proxy" do
|
47
76
|
it "lets you specify the proxy URL to use as a String" do
|
48
77
|
request.proxy = "http://proxy.example.com"
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "integration/support/server"
|
3
|
+
|
4
|
+
describe HTTPI::Adapter::Curb do
|
5
|
+
|
6
|
+
# curb is not supported on jruby
|
7
|
+
unless RUBY_PLATFORM =~ /java/
|
8
|
+
|
9
|
+
subject(:adapter) { :curb }
|
10
|
+
|
11
|
+
context "http requests" do
|
12
|
+
before :all do
|
13
|
+
@server = IntegrationServer.run
|
14
|
+
end
|
15
|
+
|
16
|
+
after :all do
|
17
|
+
@server.stop
|
18
|
+
end
|
19
|
+
|
20
|
+
it "sends and receives HTTP headers" do
|
21
|
+
request = HTTPI::Request.new(@server.url + "x-header")
|
22
|
+
request.headers["X-Header"] = "HTTPI"
|
23
|
+
|
24
|
+
response = HTTPI.get(request, adapter)
|
25
|
+
response.body.should include("HTTPI")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "executes GET requests" do
|
29
|
+
response = HTTPI.get(@server.url, adapter)
|
30
|
+
response.body.should eq("get")
|
31
|
+
response.headers["Content-Type"].should eq("text/plain")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "executes POST requests" do
|
35
|
+
response = HTTPI.post(@server.url, "<some>xml</some>", adapter)
|
36
|
+
response.body.should eq("post")
|
37
|
+
response.headers["Content-Type"].should eq("text/plain")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "executes HEAD requests" do
|
41
|
+
response = HTTPI.head(@server.url, adapter)
|
42
|
+
response.code.should == 200
|
43
|
+
response.headers["Content-Type"].should eq("text/plain")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "executes PUT requests" do
|
47
|
+
response = HTTPI.put(@server.url, "<some>xml</some>", adapter)
|
48
|
+
response.body.should eq("put")
|
49
|
+
response.headers["Content-Type"].should eq("text/plain")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "executes DELETE requests" do
|
53
|
+
response = HTTPI.delete(@server.url, adapter)
|
54
|
+
response.body.should eq("delete")
|
55
|
+
response.headers["Content-Type"].should eq("text/plain")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "supports basic authentication" do
|
59
|
+
request = HTTPI::Request.new(@server.url + "basic-auth")
|
60
|
+
request.auth.basic("admin", "secret")
|
61
|
+
|
62
|
+
response = HTTPI.get(request, adapter)
|
63
|
+
response.body.should eq("basic-auth")
|
64
|
+
end
|
65
|
+
|
66
|
+
it "supports digest authentication" do
|
67
|
+
request = HTTPI::Request.new(@server.url + "digest-auth")
|
68
|
+
request.auth.digest("admin", "secret")
|
69
|
+
|
70
|
+
response = HTTPI.get(request, adapter)
|
71
|
+
response.body.should eq("digest-auth")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "https requests" do
|
76
|
+
before :all do
|
77
|
+
@server = IntegrationServer.run(:ssl => true)
|
78
|
+
end
|
79
|
+
|
80
|
+
after :all do
|
81
|
+
@server.stop
|
82
|
+
end
|
83
|
+
|
84
|
+
it "raises when no certificate was set up" do
|
85
|
+
expect { HTTPI.post(@server.url, "", adapter) }.to raise_error(HTTPI::SSLError)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "works when set up properly" do
|
89
|
+
request = HTTPI::Request.new(@server.url)
|
90
|
+
request.auth.ssl.ca_cert_file = IntegrationServer.ssl_ca_file
|
91
|
+
|
92
|
+
response = HTTPI.get(request, adapter)
|
93
|
+
expect(response.body).to eq("get")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|