httpi 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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