httpi 2.0.0.rc1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|