httpi 0.5.0 → 0.6.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.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
data/Gemfile.lock
CHANGED
@@ -14,16 +14,16 @@ GEM
|
|
14
14
|
mocha (0.9.8)
|
15
15
|
rake
|
16
16
|
rake (0.8.7)
|
17
|
-
rspec (2.0.0
|
18
|
-
rspec-core (= 2.0.0
|
19
|
-
rspec-expectations (= 2.0.0
|
20
|
-
rspec-mocks (= 2.0.0
|
21
|
-
rspec-core (2.0.0
|
22
|
-
rspec-expectations (2.0.0
|
17
|
+
rspec (2.0.0)
|
18
|
+
rspec-core (= 2.0.0)
|
19
|
+
rspec-expectations (= 2.0.0)
|
20
|
+
rspec-mocks (= 2.0.0)
|
21
|
+
rspec-core (2.0.0)
|
22
|
+
rspec-expectations (2.0.0)
|
23
23
|
diff-lcs (>= 1.1.2)
|
24
|
-
rspec-mocks (2.0.0
|
25
|
-
rspec-core (= 2.0.0
|
26
|
-
rspec-expectations (= 2.0.0
|
24
|
+
rspec-mocks (2.0.0)
|
25
|
+
rspec-core (= 2.0.0)
|
26
|
+
rspec-expectations (= 2.0.0)
|
27
27
|
webmock (1.3.5)
|
28
28
|
addressable (>= 2.1.1)
|
29
29
|
crack (>= 0.1.7)
|
@@ -36,5 +36,5 @@ DEPENDENCIES
|
|
36
36
|
httpclient (~> 2.1.5)
|
37
37
|
httpi!
|
38
38
|
mocha (~> 0.9.8)
|
39
|
-
rspec (
|
39
|
+
rspec (~> 2.0.0)
|
40
40
|
webmock (~> 1.3.5)
|
data/README.md
CHANGED
@@ -17,7 +17,7 @@ Some examples
|
|
17
17
|
|
18
18
|
Executing a POST request with the most basic request object:
|
19
19
|
|
20
|
-
request = HTTPI::Request.new
|
20
|
+
request = HTTPI::Request.new "http://example.com"
|
21
21
|
HTTPI.get request
|
22
22
|
|
23
23
|
Here's a POST request with a request object:
|
@@ -32,11 +32,11 @@ And a GET request using HTTP basic auth and the Curb adapter:
|
|
32
32
|
|
33
33
|
request = HTTPI::Request.new
|
34
34
|
request.url = "http://auth.example.com"
|
35
|
-
request.
|
35
|
+
request.auth.basic "username", "password"
|
36
36
|
|
37
37
|
HTTPI.get request, :curb
|
38
38
|
|
39
|
-
HTTPI also comes
|
39
|
+
HTTPI also comes shortcuts. This executes a PUT request:
|
40
40
|
|
41
41
|
HTTPI.put "http://example.com", "<some>xml</some>"
|
42
42
|
|
@@ -92,23 +92,54 @@ HTTPI::Request
|
|
92
92
|
--------------
|
93
93
|
|
94
94
|
The `HTTPI::Request` serves as a common denominator of options that HTTPI adapters need to support.
|
95
|
-
It represents an HTTP request and lets you customize various settings through
|
95
|
+
It represents an HTTP request and lets you customize various settings through the following methods:
|
96
96
|
|
97
97
|
#url # the URL to access
|
98
98
|
#proxy # the proxy server to use
|
99
|
+
#ssl # whether to use SSL
|
99
100
|
#headers # a Hash of HTTP headers
|
100
101
|
#body # the HTTP request body
|
101
102
|
#open_timeout # the open timeout (sec)
|
102
103
|
#read_timeout # the read timeout (sec)
|
103
104
|
|
104
|
-
|
105
|
+
### Usage example
|
105
106
|
|
106
|
-
|
107
|
-
|
107
|
+
request = HTTPI::Request.new
|
108
|
+
request.url = "http://example.com"
|
109
|
+
request.read_timeout = 30
|
110
|
+
|
111
|
+
HTTPI::Auth
|
112
|
+
-----------
|
113
|
+
|
114
|
+
`HTTPI::Auth` supports HTTP basic and digest authentication.
|
115
|
+
|
116
|
+
#basic(username, password) # HTTP basic auth credentials
|
117
|
+
#digest(username, password) # HTTP digest auth credentials
|
118
|
+
|
119
|
+
### Usage example
|
120
|
+
|
121
|
+
request = HTTPI::Request.new
|
122
|
+
request.auth.basic "username", "password"
|
123
|
+
|
124
|
+
HTTPI::Auth::SSL
|
125
|
+
----------------
|
126
|
+
|
127
|
+
`HTTPI::Auth::SSL` manages SSL client authentication.
|
128
|
+
|
129
|
+
#cert_key_file # the private key file to use
|
130
|
+
#cert_file # the certificate file to use
|
131
|
+
#ca_cert_file # the ca certificate file to use
|
132
|
+
#verify_mode # one of [:none, :peer, :fail_if_no_peer_cert, :client_once]
|
133
|
+
|
134
|
+
### Usage example
|
135
|
+
|
136
|
+
request = HTTPI::Request.new
|
137
|
+
request.auth.ssl.cert_key_file = "client_key.pem"
|
138
|
+
request.auth.ssl.cert_file = "client_cert.pem"
|
139
|
+
request.auth.ssl.verify_mode = :none
|
108
140
|
|
109
141
|
### TODO
|
110
142
|
|
111
|
-
* Add support for SSL client authentication
|
112
143
|
* Add support for NTLM authentication
|
113
144
|
|
114
145
|
HTTPI::Adapter
|
@@ -145,4 +176,4 @@ It contains the response code, headers and body.
|
|
145
176
|
Participate
|
146
177
|
-----------
|
147
178
|
|
148
|
-
|
179
|
+
Any help and feedback appreciated. So please get in touch!
|
data/lib/httpi.rb
CHANGED
@@ -69,6 +69,9 @@ require "httpi/adapter"
|
|
69
69
|
# http.follow_redirect_count = 3 # HTTPClient example
|
70
70
|
# end
|
71
71
|
module HTTPI
|
72
|
+
|
73
|
+
REQUEST_METHODS = [:get, :post, :head, :put, :delete]
|
74
|
+
|
72
75
|
class << self
|
73
76
|
|
74
77
|
# Executes an HTTP GET request.
|
@@ -121,6 +124,12 @@ module HTTPI
|
|
121
124
|
end
|
122
125
|
end
|
123
126
|
|
127
|
+
# Executes an HTTP request for the given +method+.
|
128
|
+
def request(method, request, adapter = nil)
|
129
|
+
raise ArgumentError, "Invalid request method: #{method}" unless REQUEST_METHODS.include? method
|
130
|
+
send method, request, adapter
|
131
|
+
end
|
132
|
+
|
124
133
|
private
|
125
134
|
|
126
135
|
# Checks whether +args+ contains of an <tt>HTTPI::Request</tt> or a URL
|
data/lib/httpi/adapter/curb.rb
CHANGED
@@ -59,20 +59,29 @@ module HTTPI
|
|
59
59
|
|
60
60
|
def setup_client(request)
|
61
61
|
basic_setup request
|
62
|
-
|
62
|
+
setup_http_auth request if request.auth.http?
|
63
|
+
setup_ssl_auth request.auth.ssl if request.auth.ssl?
|
63
64
|
end
|
64
65
|
|
65
66
|
def basic_setup(request)
|
66
67
|
client.url = request.url.to_s
|
67
|
-
client.
|
68
|
-
client.
|
68
|
+
client.proxy_url = request.proxy.to_s if request.proxy
|
69
|
+
client.timeout = request.read_timeout if request.read_timeout
|
70
|
+
client.connect_timeout = request.open_timeout if request.open_timeout
|
69
71
|
client.headers = request.headers
|
70
72
|
client.verbose = false
|
71
73
|
end
|
72
74
|
|
73
|
-
def
|
74
|
-
client.http_auth_types = request.
|
75
|
-
client.username, client.password = *request.credentials
|
75
|
+
def setup_http_auth(request)
|
76
|
+
client.http_auth_types = request.auth.type
|
77
|
+
client.username, client.password = *request.auth.credentials
|
78
|
+
end
|
79
|
+
|
80
|
+
def setup_ssl_auth(ssl)
|
81
|
+
client.cert_key = ssl.cert_key_file
|
82
|
+
client.cert = ssl.cert_file
|
83
|
+
client.cacert = ssl.ca_cert_file if ssl.ca_cert_file
|
84
|
+
client.ssl_verify_peer = ssl.verify_mode == :peer
|
76
85
|
end
|
77
86
|
|
78
87
|
def respond_with(client)
|
@@ -22,7 +22,7 @@ module HTTPI
|
|
22
22
|
# Executes an HTTP GET request.
|
23
23
|
# @see HTTPI.get
|
24
24
|
def get(request)
|
25
|
-
do_request request do |
|
25
|
+
do_request request do |url, headers|
|
26
26
|
client.get url, nil, headers
|
27
27
|
end
|
28
28
|
end
|
@@ -30,7 +30,7 @@ module HTTPI
|
|
30
30
|
# Executes an HTTP POST request.
|
31
31
|
# @see HTTPI.post
|
32
32
|
def post(request)
|
33
|
-
do_request request do |
|
33
|
+
do_request request do |url, headers, body|
|
34
34
|
client.post url, body, headers
|
35
35
|
end
|
36
36
|
end
|
@@ -38,7 +38,7 @@ module HTTPI
|
|
38
38
|
# Executes an HTTP HEAD request.
|
39
39
|
# @see HTTPI.head
|
40
40
|
def head(request)
|
41
|
-
do_request request do |
|
41
|
+
do_request request do |url, headers|
|
42
42
|
client.head url, nil, headers
|
43
43
|
end
|
44
44
|
end
|
@@ -46,7 +46,7 @@ module HTTPI
|
|
46
46
|
# Executes an HTTP PUT request.
|
47
47
|
# @see HTTPI.put
|
48
48
|
def put(request)
|
49
|
-
do_request request do |
|
49
|
+
do_request request do |url, headers, body|
|
50
50
|
client.put url, body, headers
|
51
51
|
end
|
52
52
|
end
|
@@ -54,30 +54,39 @@ module HTTPI
|
|
54
54
|
# Executes an HTTP DELETE request.
|
55
55
|
# @see HTTPI.delete
|
56
56
|
def delete(request)
|
57
|
-
do_request request do |
|
57
|
+
do_request request do |url, headers|
|
58
58
|
client.delete url, headers
|
59
59
|
end
|
60
60
|
end
|
61
|
+
|
61
62
|
private
|
62
63
|
|
63
64
|
def do_request(request)
|
64
65
|
setup_client request
|
65
|
-
respond_with yield(
|
66
|
+
respond_with yield(request.url, request.headers, request.body)
|
66
67
|
end
|
67
68
|
|
68
69
|
def setup_client(request)
|
69
70
|
basic_setup request
|
70
|
-
|
71
|
+
setup_http_auth request if request.auth.http?
|
72
|
+
setup_ssl_auth request.auth.ssl if request.auth.ssl?
|
71
73
|
end
|
72
74
|
|
73
75
|
def basic_setup(request)
|
74
76
|
client.proxy = request.proxy if request.proxy
|
75
|
-
client.connect_timeout = request.open_timeout
|
76
|
-
client.receive_timeout = request.read_timeout
|
77
|
+
client.connect_timeout = request.open_timeout if request.open_timeout
|
78
|
+
client.receive_timeout = request.read_timeout if request.read_timeout
|
79
|
+
end
|
80
|
+
|
81
|
+
def setup_http_auth(request)
|
82
|
+
client.set_auth request.url, *request.auth.credentials
|
77
83
|
end
|
78
84
|
|
79
|
-
def
|
80
|
-
client.
|
85
|
+
def setup_ssl_auth(ssl)
|
86
|
+
client.ssl_config.client_cert = ssl.cert
|
87
|
+
client.ssl_config.client_key = ssl.cert_key
|
88
|
+
client.ssl_config.client_ca = ssl.ca_cert if ssl.ca_cert_file
|
89
|
+
client.ssl_config.verify_mode = ssl.openssl_verify_mode
|
81
90
|
end
|
82
91
|
|
83
92
|
def respond_with(response)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "uri"
|
1
2
|
require "httpi/response"
|
2
3
|
|
3
4
|
module HTTPI
|
@@ -9,7 +10,7 @@ module HTTPI
|
|
9
10
|
# http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/
|
10
11
|
class NetHTTP
|
11
12
|
|
12
|
-
# Requires the "net/https" library.
|
13
|
+
# Requires the "net/https" library and sets up a new client.
|
13
14
|
def initialize(request)
|
14
15
|
require "net/https"
|
15
16
|
self.client = new_client request
|
@@ -70,6 +71,7 @@ module HTTPI
|
|
70
71
|
|
71
72
|
def do_request(type, request)
|
72
73
|
setup_client request
|
74
|
+
setup_ssl_auth request.auth.ssl if request.auth.ssl?
|
73
75
|
|
74
76
|
respond_with(client.start do |http|
|
75
77
|
yield http, request_client(type, request)
|
@@ -77,9 +79,16 @@ module HTTPI
|
|
77
79
|
end
|
78
80
|
|
79
81
|
def setup_client(request)
|
80
|
-
client.use_ssl =
|
81
|
-
client.open_timeout = request.open_timeout
|
82
|
-
client.read_timeout = request.read_timeout
|
82
|
+
client.use_ssl = request.ssl?
|
83
|
+
client.open_timeout = request.open_timeout if request.open_timeout
|
84
|
+
client.read_timeout = request.read_timeout if request.read_timeout
|
85
|
+
end
|
86
|
+
|
87
|
+
def setup_ssl_auth(ssl)
|
88
|
+
client.key = ssl.cert_key
|
89
|
+
client.cert = ssl.cert
|
90
|
+
client.ca_file = ssl.ca_cert_file if ssl.ca_cert_file
|
91
|
+
client.verify_mode = ssl.openssl_verify_mode
|
83
92
|
end
|
84
93
|
|
85
94
|
def request_client(type, request)
|
@@ -92,12 +101,7 @@ module HTTPI
|
|
92
101
|
end
|
93
102
|
|
94
103
|
request_client = request_class.new request.url.request_uri, request.headers
|
95
|
-
request_client
|
96
|
-
request_client
|
97
|
-
end
|
98
|
-
|
99
|
-
def auth_setup(request_client, request)
|
100
|
-
request_client.basic_auth *request.credentials if request.auth_type == :basic
|
104
|
+
request_client.basic_auth *request.auth.credentials if request.auth.basic?
|
101
105
|
request_client
|
102
106
|
end
|
103
107
|
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require "httpi/auth/ssl"
|
2
|
+
|
3
|
+
module HTTPI
|
4
|
+
module Auth
|
5
|
+
|
6
|
+
# = HTTPI::Auth::Config
|
7
|
+
#
|
8
|
+
# Manages HTTP and SSL auth configuration. Currently supports HTTP basic/digest
|
9
|
+
# and SSL client authentication.
|
10
|
+
class Config
|
11
|
+
|
12
|
+
# Supported authentication types.
|
13
|
+
TYPES = [:basic, :digest, :ssl]
|
14
|
+
|
15
|
+
# Accessor for the HTTP basic auth credentials.
|
16
|
+
def basic(*args)
|
17
|
+
return @basic if args.empty?
|
18
|
+
|
19
|
+
self.type = :basic
|
20
|
+
@basic = args.flatten.compact
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns whether to use HTTP basic auth.
|
24
|
+
def basic?
|
25
|
+
type == :basic
|
26
|
+
end
|
27
|
+
|
28
|
+
# Accessor for the HTTP digest auth credentials.
|
29
|
+
def digest(*args)
|
30
|
+
return @digest if args.empty?
|
31
|
+
|
32
|
+
self.type = :digest
|
33
|
+
@digest = args.flatten.compact
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns whether to use HTTP digest auth.
|
37
|
+
def digest?
|
38
|
+
type == :digest
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns whether to use HTTP basic or dihest auth.
|
42
|
+
def http?
|
43
|
+
type == :basic || type == :digest
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns the <tt>HTTPI::Auth::SSL</tt> object.
|
47
|
+
def ssl
|
48
|
+
@ssl ||= SSL.new
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns whether to use SSL client auth.
|
52
|
+
def ssl?
|
53
|
+
ssl.present?
|
54
|
+
end
|
55
|
+
|
56
|
+
# Shortcut method for returning the credentials for the authentication specified.
|
57
|
+
# Returns +nil+ unless any authentication credentials were specified.
|
58
|
+
def credentials
|
59
|
+
return unless type
|
60
|
+
send type
|
61
|
+
end
|
62
|
+
|
63
|
+
# Accessor for the authentication type in use.
|
64
|
+
attr_accessor :type
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "openssl"
|
2
|
+
|
3
|
+
module HTTPI
|
4
|
+
module Auth
|
5
|
+
|
6
|
+
# = HTTPI::Auth::SSL
|
7
|
+
#
|
8
|
+
# Provides SSL client authentication.
|
9
|
+
class SSL
|
10
|
+
|
11
|
+
VERIFY_MODES = [:none, :peer, :fail_if_no_peer_cert, :client_once]
|
12
|
+
|
13
|
+
# Returns whether SSL configuration is present.
|
14
|
+
def present?
|
15
|
+
cert && cert_key
|
16
|
+
rescue TypeError, Errno::ENOENT
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
# Accessor for the cert key file to validate SSL certificates.
|
21
|
+
attr_accessor :cert_key_file
|
22
|
+
|
23
|
+
# Accessor for the cert file to validate SSL connections.
|
24
|
+
attr_accessor :cert_file
|
25
|
+
|
26
|
+
# Accessor for the cacert file to validate SSL certificates.
|
27
|
+
attr_accessor :ca_cert_file
|
28
|
+
|
29
|
+
# Returns the SSL verify mode. Defaults to <tt>:peer</tt>.
|
30
|
+
def verify_mode
|
31
|
+
@verify_mode ||= :peer
|
32
|
+
end
|
33
|
+
|
34
|
+
# Sets the SSL verify mode. Expects one of <tt>HTTPI::Auth::SSL::VERIFY_MODES</tt>.
|
35
|
+
def verify_mode=(mode)
|
36
|
+
raise ArgumentError, "Invalid SSL verify mode: #{mode}" unless VERIFY_MODES.include? mode
|
37
|
+
@verify_mode = mode
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns an <tt>OpenSSL::X509::Certificate</tt> for the +cert_file+.
|
41
|
+
def cert
|
42
|
+
@cert ||= OpenSSL::X509::Certificate.new File.read(cert_file)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Sets the +OpenSSL+ certificate.
|
46
|
+
attr_writer :cert
|
47
|
+
|
48
|
+
# Returns an <tt>OpenSSL::X509::Certificate</tt> for the +ca_cert_file+.
|
49
|
+
def ca_cert
|
50
|
+
@ca_cert ||= OpenSSL::X509::Certificate.new File.read(ca_cert_file)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Sets the +OpenSSL+ ca certificate.
|
54
|
+
attr_writer :ca_cert
|
55
|
+
|
56
|
+
# Returns an <tt>OpenSSL::PKey::RSA</tt> for the +cert_key_file+.
|
57
|
+
def cert_key
|
58
|
+
@cert_key ||= OpenSSL::PKey::RSA.new File.read(cert_key_file)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Sets the +OpenSSL+ certificate key.
|
62
|
+
attr_writer :cert_key
|
63
|
+
|
64
|
+
# Returns the SSL verify mode as a <tt>OpenSSL::SSL::VERIFY_*</tt> constant.
|
65
|
+
def openssl_verify_mode
|
66
|
+
case verify_mode
|
67
|
+
when :none then OpenSSL::SSL::VERIFY_NONE
|
68
|
+
when :peer then OpenSSL::SSL::VERIFY_PEER
|
69
|
+
when :fail_if_no_peer_cert then OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
70
|
+
when :client_once then OpenSSL::SSL::VERIFY_CLIENT_ONCE
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|