httpi 0.1.0 → 0.2.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/Gemfile +1 -1
- data/Gemfile.lock +28 -0
- data/README.rdoc +68 -39
- data/Rakefile +28 -2
- data/lib/httpi/adapter.rb +1 -1
- data/lib/httpi/adapter/curb.rb +26 -34
- data/lib/httpi/adapter/httpclient.rb +23 -25
- data/lib/httpi/client.rb +63 -5
- data/lib/httpi/request.rb +73 -0
- data/lib/httpi/version.rb +1 -1
- data/spec/fixtures/xml.gz +0 -0
- data/spec/fixtures/xml.xml +10 -0
- data/spec/httpi/adapter/curb_spec.rb +29 -69
- data/spec/httpi/adapter/httpclient_spec.rb +25 -66
- data/spec/httpi/adapter_spec.rb +11 -12
- data/spec/httpi/client_spec.rb +89 -8
- data/spec/httpi/request_spec.rb +104 -0
- data/spec/httpi/response_spec.rb +6 -8
- data/spec/spec_helper.rb +1 -1
- data/spec/support/fixture.rb +19 -0
- data/spec/support/matchers.rb +2 -2
- metadata +13 -12
- data/lib/httpi/adapter/base.rb +0 -16
- data/lib/httpi/interface.rb +0 -21
- data/spec/fixtures/gzip.gz +0 -0
- data/spec/httpi/interface_spec.rb +0 -33
- data/spec/support/helper_methods.rb +0 -41
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
curb (0.7.8)
|
5
|
+
diff-lcs (1.1.2)
|
6
|
+
httpclient (2.1.5.2)
|
7
|
+
mocha (0.9.8)
|
8
|
+
rake
|
9
|
+
rake (0.8.7)
|
10
|
+
rspec (2.0.0.beta.22)
|
11
|
+
rspec-core (= 2.0.0.beta.22)
|
12
|
+
rspec-expectations (= 2.0.0.beta.22)
|
13
|
+
rspec-mocks (= 2.0.0.beta.22)
|
14
|
+
rspec-core (2.0.0.beta.22)
|
15
|
+
rspec-expectations (2.0.0.beta.22)
|
16
|
+
diff-lcs (>= 1.1.2)
|
17
|
+
rspec-mocks (2.0.0.beta.22)
|
18
|
+
rspec-core (= 2.0.0.beta.22)
|
19
|
+
rspec-expectations (= 2.0.0.beta.22)
|
20
|
+
|
21
|
+
PLATFORMS
|
22
|
+
ruby
|
23
|
+
|
24
|
+
DEPENDENCIES
|
25
|
+
curb (~> 0.7.8)
|
26
|
+
httpclient (~> 2.1.5)
|
27
|
+
mocha (~> 0.9.8)
|
28
|
+
rspec (= 2.0.0.beta.22)
|
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= HTTPI
|
2
2
|
|
3
|
-
HTTPI provides a common interface for
|
3
|
+
HTTPI provides a common interface for Ruby HTTP libraries.
|
4
4
|
|
5
5
|
== Installation
|
6
6
|
|
@@ -8,78 +8,107 @@ The gem is available through {Rubygems}[http://rubygems.org/gems/httpi] and can
|
|
8
8
|
|
9
9
|
$ gem install httpi
|
10
10
|
|
11
|
-
==
|
11
|
+
== Basic examples
|
12
12
|
|
13
|
-
|
14
|
-
* {curb}[http://rubygems.org/gems/curb] ~> 0.7.8
|
13
|
+
Let's create the most basic request object and execute a GET request:
|
15
14
|
|
16
|
-
|
15
|
+
request = HTTPI::Request.new :url => "http://example.com"
|
16
|
+
HTTPI::Client.get request
|
17
17
|
|
18
|
-
|
18
|
+
And a POST request with a request object:
|
19
19
|
|
20
|
-
|
20
|
+
request = HTTPI::Request.new
|
21
|
+
request.url = "http://post.example.com"
|
22
|
+
request.body = "send me"
|
23
|
+
|
24
|
+
HTTPI::Client.post request
|
21
25
|
|
22
|
-
|
26
|
+
Or a GET request using HTTP basic auth and the Curb adapter:
|
23
27
|
|
24
|
-
HTTPI::
|
28
|
+
request = HTTPI::Request.new
|
29
|
+
request.url = "http://auth.example.com"
|
30
|
+
request.basic_auth "username", "password"
|
31
|
+
|
32
|
+
HTTPI::Client.get request, :curb
|
25
33
|
|
26
|
-
|
34
|
+
HTTPI also comes with some shortcuts. This executes a GET request:
|
27
35
|
|
28
|
-
HTTPI::
|
36
|
+
HTTPI::Client.get "http://example.com"
|
29
37
|
|
30
|
-
|
38
|
+
And here's a POST:
|
31
39
|
|
32
|
-
|
40
|
+
HTTPI::Client.post "http://example.com", "<some>xml</some>"
|
33
41
|
|
34
|
-
|
42
|
+
== HTTPI::Request
|
35
43
|
|
36
|
-
|
37
|
-
client.headers # => { "Accept-Encoding" => "gzip" }
|
44
|
+
The HTTPI::Request serves as a common denominator of options that HTTPI adapters need to support. It represents an HTTP request and lets you customize various settings:
|
38
45
|
|
39
|
-
|
46
|
+
* [url] the URL to access
|
47
|
+
* [proxy] the proxy server to use
|
48
|
+
* [headers] a Hash of HTTP headers
|
49
|
+
* [body] the HTTP request body
|
50
|
+
* [open_timeout] the open timeout (sec)
|
51
|
+
* [read_timeout] the read timeout (sec)
|
40
52
|
|
41
|
-
|
53
|
+
It also contains methods for setting up authentication:
|
42
54
|
|
43
|
-
|
44
|
-
client.proxy # => #<URI::HTTP:0x1026240f0 URL:http://proxy.example.com>
|
55
|
+
* [basic_auth] HTTP basic auth credentials
|
45
56
|
|
46
|
-
|
57
|
+
==== TODO:
|
47
58
|
|
48
|
-
|
59
|
+
* Add support for HTTP digest authentication
|
60
|
+
* Add support for SSL client authentication
|
49
61
|
|
50
|
-
|
62
|
+
== HTTPI::Client
|
51
63
|
|
52
|
-
|
64
|
+
The HTTPI::Client uses one of the available adapters to execute HTTP requests. It currently supports GET and POST requests:
|
53
65
|
|
54
|
-
===
|
66
|
+
=== GET
|
55
67
|
|
56
|
-
|
68
|
+
* get(request, adapter = nil)
|
69
|
+
* get(url, adapter = nil)
|
57
70
|
|
58
|
-
|
71
|
+
=== POST
|
59
72
|
|
60
|
-
|
73
|
+
* post(request, adapter = nil)
|
74
|
+
* post(url, body, adapter = nil)
|
61
75
|
|
62
|
-
|
76
|
+
You can specify the adapter to use per request. Request methods always returns an HTTPI::Response.
|
63
77
|
|
64
|
-
|
78
|
+
==== TODO:
|
79
|
+
|
80
|
+
* Add support for HEAD, PUT and DELETE requests
|
81
|
+
|
82
|
+
== HTTPI::Adapter
|
83
|
+
|
84
|
+
HTTPI uses adapters to support multiple HTTP libraries. It currently contains adapters for:
|
85
|
+
|
86
|
+
* {httpclient}[http://rubygems.org/gems/httpclient] ~> 2.1.5
|
87
|
+
* {curb}[http://rubygems.org/gems/curb] ~> 0.7.8
|
88
|
+
|
89
|
+
By default, HTTPI uses the HTTPClient. But changing the default is fairly easy:
|
90
|
+
|
91
|
+
HTTPI::Adapter.use = :curb
|
92
|
+
|
93
|
+
You can find a list of supported adapters via:
|
94
|
+
|
95
|
+
HTTPI::Adapter.adapters # returns a Hash of supported adapters
|
65
96
|
|
66
97
|
== HTTPI::Response
|
67
98
|
|
68
|
-
|
99
|
+
As mentioned before, every request method return an HTTPI::Response. It contains the response code, headers and body.
|
69
100
|
|
70
|
-
response =
|
101
|
+
response = HTTPI::Client.get request
|
71
102
|
|
72
103
|
response.code # => 200
|
73
104
|
response.headers # => { "Content-Encoding" => "gzip" }
|
74
105
|
response.body # => "<!DOCTYPE HTML PUBLIC ..."
|
75
106
|
|
76
|
-
|
77
|
-
|
78
|
-
I would appreciate any help to support additional libraries and methods!
|
107
|
+
==== TODO
|
79
108
|
|
80
|
-
|
109
|
+
* Return the original HTTPI::Request for debugging purposes
|
110
|
+
* Return the time it took to execute the request
|
81
111
|
|
82
|
-
|
112
|
+
== Participate
|
83
113
|
|
84
|
-
|
85
|
-
* add timeout methods
|
114
|
+
We appreciate any help and feedback, so please get in touch!
|
data/Rakefile
CHANGED
@@ -1,8 +1,34 @@
|
|
1
|
+
require "rake"
|
2
|
+
|
1
3
|
begin
|
2
|
-
require "
|
4
|
+
require "yard"
|
5
|
+
|
6
|
+
YARD::Rake::YardocTask.new do |t|
|
7
|
+
t.files = ["README.rdoc", "lib/**/*.rb"]
|
8
|
+
end
|
9
|
+
rescue LoadError
|
10
|
+
desc message = %{"gem install yard" to generate documentation}
|
11
|
+
task("yard") { abort message }
|
12
|
+
end
|
13
|
+
|
14
|
+
begin
|
15
|
+
require "metric_fu"
|
16
|
+
|
17
|
+
MetricFu::Configuration.run do |c|
|
18
|
+
c.metrics = [:churn, :flog, :flay, :reek, :roodi, :saikuro] # :rcov seems to be broken
|
19
|
+
c.graphs = [:flog, :flay, :reek, :roodi]
|
20
|
+
c.rcov[:rcov_opts] << "-Ilib -Ispec"
|
21
|
+
end
|
22
|
+
rescue LoadError
|
23
|
+
desc message = %{"gem install metric_fu" to generate metrics}
|
24
|
+
task("metrics:all") { abort message }
|
25
|
+
end
|
3
26
|
|
27
|
+
begin
|
28
|
+
require "rspec/core/rake_task"
|
29
|
+
|
4
30
|
RSpec::Core::RakeTask.new do |t|
|
5
|
-
t.
|
31
|
+
t.rspec_opts = %w(-fd -c)
|
6
32
|
end
|
7
33
|
rescue LoadError
|
8
34
|
task :spec do
|
data/lib/httpi/adapter.rb
CHANGED
data/lib/httpi/adapter/curb.rb
CHANGED
@@ -1,56 +1,48 @@
|
|
1
1
|
require "httpi/response"
|
2
|
-
require "httpi/adapter/base"
|
3
2
|
|
4
3
|
module HTTPI
|
5
4
|
module Adapter
|
6
|
-
|
7
|
-
include Base
|
5
|
+
class Curb
|
8
6
|
|
9
|
-
def
|
7
|
+
def initialize
|
10
8
|
require "curb"
|
11
9
|
end
|
12
10
|
|
13
|
-
def
|
14
|
-
|
11
|
+
def get(request)
|
12
|
+
get_request(request) { |client| client.http_get }
|
15
13
|
end
|
16
14
|
|
17
|
-
def
|
18
|
-
client.
|
15
|
+
def post(request)
|
16
|
+
post_request(request) { |client, body| client.http_post body }
|
19
17
|
end
|
20
18
|
|
21
|
-
|
22
|
-
client.headers = headers
|
23
|
-
end
|
24
|
-
|
25
|
-
def proxy
|
26
|
-
proxy = client.proxy_url
|
27
|
-
proxy.kind_of?(URI) ? proxy : URI(proxy)
|
28
|
-
end
|
29
|
-
|
30
|
-
def proxy=(proxy)
|
31
|
-
client.proxy_url = proxy
|
32
|
-
end
|
19
|
+
private
|
33
20
|
|
34
|
-
def
|
35
|
-
client
|
36
|
-
client
|
21
|
+
def get_request(request)
|
22
|
+
client = client_for request
|
23
|
+
yield client
|
24
|
+
respond_with client
|
37
25
|
end
|
38
26
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
27
|
+
def post_request(request)
|
28
|
+
request.url = request.url.to_s
|
29
|
+
request.url.gsub!('?wsdl', '') if request.url =~ /\?wsdl$/
|
30
|
+
|
31
|
+
client = client_for request
|
32
|
+
yield client, request.body
|
33
|
+
respond_with client
|
43
34
|
end
|
44
35
|
|
45
|
-
def
|
46
|
-
client
|
47
|
-
client.
|
48
|
-
|
36
|
+
def client_for(request)
|
37
|
+
client = Curl::Easy.new request.url.to_s
|
38
|
+
client.timeout = request.read_timeout
|
39
|
+
client.connect_timeout = request.open_timeout
|
40
|
+
client.headers = request.headers
|
41
|
+
client.verbose = false
|
42
|
+
client
|
49
43
|
end
|
50
44
|
|
51
|
-
|
52
|
-
|
53
|
-
def respond
|
45
|
+
def respond_with(client)
|
54
46
|
Response.new client.response_code, client.headers, client.body_str
|
55
47
|
end
|
56
48
|
|
@@ -1,47 +1,45 @@
|
|
1
1
|
require "httpi/response"
|
2
|
-
require "httpi/adapter/base"
|
3
2
|
|
4
3
|
module HTTPI
|
5
4
|
module Adapter
|
6
|
-
|
7
|
-
include Base
|
5
|
+
class HTTPClient
|
8
6
|
|
9
|
-
def
|
7
|
+
def initialize
|
10
8
|
require "httpclient"
|
11
9
|
end
|
12
10
|
|
13
|
-
def
|
14
|
-
|
11
|
+
def get(request)
|
12
|
+
get_request request do |client, url, headers|
|
13
|
+
client.get url, nil, headers
|
14
|
+
end
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
|
17
|
+
def post(request)
|
18
|
+
post_request request do |client, url, headers, body|
|
19
|
+
client.post url, body, headers
|
20
|
+
end
|
19
21
|
end
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
def proxy
|
24
|
-
client.proxy
|
25
|
-
end
|
26
|
-
|
27
|
-
def proxy=(proxy)
|
28
|
-
client.proxy = proxy
|
29
|
-
end
|
23
|
+
private
|
30
24
|
|
31
|
-
def
|
32
|
-
client
|
25
|
+
def get_request(request)
|
26
|
+
client = client_for request
|
27
|
+
respond_with yield(client, request.url, request.headers)
|
33
28
|
end
|
34
29
|
|
35
|
-
def
|
36
|
-
|
30
|
+
def post_request(request)
|
31
|
+
client = client_for request
|
32
|
+
respond_with yield(client, request.url, request.headers, request.body)
|
37
33
|
end
|
38
34
|
|
39
|
-
def
|
40
|
-
|
35
|
+
def client_for(request)
|
36
|
+
client = ::HTTPClient.new
|
37
|
+
client.proxy = request.proxy if request.proxy
|
38
|
+
client.connect_timeout = request.open_timeout
|
39
|
+
client.receive_timeout = request.read_timeout
|
40
|
+
client
|
41
41
|
end
|
42
42
|
|
43
|
-
private
|
44
|
-
|
45
43
|
def respond_with(response)
|
46
44
|
Response.new response.code, Hash[response.header.all], response.content
|
47
45
|
end
|
data/lib/httpi/client.rb
CHANGED
@@ -1,12 +1,70 @@
|
|
1
|
-
require "httpi/
|
1
|
+
require "httpi/request"
|
2
|
+
require "httpi/adapter"
|
2
3
|
|
3
4
|
module HTTPI
|
4
5
|
class Client
|
5
|
-
|
6
|
+
class << self
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
# Executes an HTTP GET request and returns an <tt>HTTPI::Response</tt>.
|
9
|
+
#
|
10
|
+
# ==== Example
|
11
|
+
#
|
12
|
+
# Accepts an <tt>HTTPI::Request</tt> and an optional adapter:
|
13
|
+
#
|
14
|
+
# request = HTTPI::Request.new :url => "http://example.com"
|
15
|
+
# HTTPI::Client.get request, :httpclient
|
16
|
+
#
|
17
|
+
# ==== Shortcut
|
18
|
+
#
|
19
|
+
# You can also just pass a URL and an optional adapter if you don't
|
20
|
+
# need to configure the request:
|
21
|
+
#
|
22
|
+
# HTTPI::Client.get "http://example.com", :curb
|
23
|
+
def get(request, adapter = nil)
|
24
|
+
request = Request.new :url => request if request.kind_of? String
|
25
|
+
find_adapter(adapter).get request
|
26
|
+
end
|
27
|
+
|
28
|
+
# Executes an HTTP POST request and returns an <tt>HTTPI::Response</tt>.
|
29
|
+
#
|
30
|
+
# ==== Example
|
31
|
+
#
|
32
|
+
# Accepts an <tt>HTTPI::Request</tt> and an optional adapter:
|
33
|
+
#
|
34
|
+
# request = HTTPI::Request.new
|
35
|
+
# request.url = "http://example.com"
|
36
|
+
# request.body = "<some>xml</some>"
|
37
|
+
#
|
38
|
+
# HTTPI::Client.post request, :httpclient
|
39
|
+
#
|
40
|
+
# ==== Shortcut
|
41
|
+
#
|
42
|
+
# You can also just pass a URL, a request body and an optional adapter
|
43
|
+
# if you don't need to configure the request:
|
44
|
+
#
|
45
|
+
# HTTPI::Client.post "http://example.com", "<some>xml</some>", :curb
|
46
|
+
def post(*args)
|
47
|
+
request, adapter = extract_post_args(args)
|
48
|
+
find_adapter(adapter).post request
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
10
52
|
|
53
|
+
# Checks whether +args+ contains of an <tt>HTTPI::Request</tt> or a URL
|
54
|
+
# and a request body plus an optional adapter and returns an Array with
|
55
|
+
# an <tt>HTTPI::Request</tt> and (if given) an adapter.
|
56
|
+
def extract_post_args(args)
|
57
|
+
return args if args.first.kind_of? Request
|
58
|
+
[Request.new(:url => args[0], :body => args[1]), args[2]]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Accepts an +adapter+ (defaults to <tt>Adapter.use</tt>) and returns
|
62
|
+
# a new instance of the adapter to use.
|
63
|
+
def find_adapter(adapter)
|
64
|
+
adapter ||= Adapter.use
|
65
|
+
Adapter.find(adapter).new
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
11
69
|
end
|
12
70
|
end
|