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.
@@ -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.beta.22)
18
- rspec-core (= 2.0.0.beta.22)
19
- rspec-expectations (= 2.0.0.beta.22)
20
- rspec-mocks (= 2.0.0.beta.22)
21
- rspec-core (2.0.0.beta.22)
22
- rspec-expectations (2.0.0.beta.22)
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.beta.22)
25
- rspec-core (= 2.0.0.beta.22)
26
- rspec-expectations (= 2.0.0.beta.22)
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 (= 2.0.0.beta.22)
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 :url => "http://example.com"
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.basic_auth "username", "password"
35
+ request.auth.basic "username", "password"
36
36
 
37
37
  HTTPI.get request, :curb
38
38
 
39
- HTTPI also comes with some shortcuts. This executes a PUT request:
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 these accessors:
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
- It also contains methods for setting up authentication:
105
+ ### Usage example
105
106
 
106
- #basic_auth(username, password) # HTTP basic auth credentials
107
- #digest_auth(username, password) # HTTP digest auth credentials
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
- We appreciate any help and feedback, so please get in touch!
179
+ Any help and feedback appreciated. So please get in touch!
@@ -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
@@ -59,20 +59,29 @@ module HTTPI
59
59
 
60
60
  def setup_client(request)
61
61
  basic_setup request
62
- setup_auth request if request.auth?
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.timeout = request.read_timeout
68
- client.connect_timeout = request.open_timeout
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 setup_auth(request)
74
- client.http_auth_types = request.auth_type
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 |client, url, headers|
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 |client, url, headers, body|
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 |client, url, headers|
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 |client, url, headers, body|
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 |client, url, headers|
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(client, request.url, request.headers, request.body)
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
- auth_setup request if request.auth?
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 auth_setup(request)
80
- client.set_auth request.url.to_s, *request.credentials
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 = !!(request.url.to_s =~ /^https/)
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 = auth_setup request_client, request if request.auth?
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