cs-httpi 0.9.5.1

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.
Files changed (48) hide show
  1. data/.autotest +5 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +8 -0
  5. data/CHANGELOG.md +66 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE +20 -0
  8. data/README.md +229 -0
  9. data/Rakefile +18 -0
  10. data/autotest/discover.rb +1 -0
  11. data/cs-httpi.gemspec +26 -0
  12. data/lib/cs-httpi.rb +198 -0
  13. data/lib/cs-httpi/adapter.rb +67 -0
  14. data/lib/cs-httpi/adapter/curb.rb +119 -0
  15. data/lib/cs-httpi/adapter/httpclient.rb +98 -0
  16. data/lib/cs-httpi/adapter/net_http.rb +115 -0
  17. data/lib/cs-httpi/auth/config.rb +78 -0
  18. data/lib/cs-httpi/auth/ssl.rb +91 -0
  19. data/lib/cs-httpi/dime.rb +56 -0
  20. data/lib/cs-httpi/request.rb +99 -0
  21. data/lib/cs-httpi/response.rb +85 -0
  22. data/lib/cs-httpi/version.rb +5 -0
  23. data/nbproject/private/private.properties +2 -0
  24. data/nbproject/private/rake-d.txt +0 -0
  25. data/nbproject/project.properties +7 -0
  26. data/nbproject/project.xml +15 -0
  27. data/spec/cs-httpi/adapter/curb_spec.rb +232 -0
  28. data/spec/cs-httpi/adapter/httpclient_spec.rb +164 -0
  29. data/spec/cs-httpi/adapter/net_http_spec.rb +142 -0
  30. data/spec/cs-httpi/adapter_spec.rb +55 -0
  31. data/spec/cs-httpi/auth/config_spec.rb +117 -0
  32. data/spec/cs-httpi/auth/ssl_spec.rb +128 -0
  33. data/spec/cs-httpi/httpi_spec.rb +284 -0
  34. data/spec/cs-httpi/request_spec.rb +140 -0
  35. data/spec/cs-httpi/response_spec.rb +125 -0
  36. data/spec/fixtures/attachment.gif +0 -0
  37. data/spec/fixtures/client_cert.pem +16 -0
  38. data/spec/fixtures/client_key.pem +15 -0
  39. data/spec/fixtures/xml.gz +0 -0
  40. data/spec/fixtures/xml.xml +10 -0
  41. data/spec/fixtures/xml_dime.dime +0 -0
  42. data/spec/fixtures/xml_dime.xml +1 -0
  43. data/spec/integration/request_spec.rb +95 -0
  44. data/spec/integration/server.rb +39 -0
  45. data/spec/spec_helper.rb +12 -0
  46. data/spec/support/fixture.rb +27 -0
  47. data/spec/support/matchers.rb +19 -0
  48. metadata +158 -0
@@ -0,0 +1,67 @@
1
+ require "cs-httpi/adapter/httpclient"
2
+ require "cs-httpi/adapter/curb"
3
+ require "cs-httpi/adapter/net_http"
4
+
5
+ module HTTPI
6
+
7
+ # = HTTPI::Adapter
8
+ #
9
+ # Manages the adapter classes. Currently supports:
10
+ #
11
+ # * httpclient
12
+ # * curb
13
+ # * net/http
14
+ module Adapter
15
+
16
+ ADAPTERS = {
17
+ :httpclient => { :class => HTTPClient, :require => "httpclient" },
18
+ :curb => { :class => Curb, :require => "curb" },
19
+ :net_http => { :class => NetHTTP, :require => "net/https" }
20
+ }
21
+
22
+ LOAD_ORDER = [:httpclient, :curb, :net_http]
23
+
24
+ class << self
25
+
26
+ def use=(adapter)
27
+ return @adapter = nil if adapter.nil?
28
+
29
+ validate_adapter! adapter
30
+ load_adapter adapter
31
+ @adapter = adapter
32
+ end
33
+
34
+ def use
35
+ @adapter ||= default_adapter
36
+ end
37
+
38
+ def load(adapter)
39
+ adapter = adapter ? validate_adapter!(adapter) : use
40
+ [adapter, ADAPTERS[adapter][:class]]
41
+ end
42
+
43
+ private
44
+
45
+ def validate_adapter!(adapter)
46
+ raise ArgumentError, "Invalid HTTPI adapter: #{adapter}" unless ADAPTERS[adapter]
47
+ adapter
48
+ end
49
+
50
+ def default_adapter
51
+ LOAD_ORDER.each do |adapter|
52
+ begin
53
+ load_adapter adapter
54
+ return adapter
55
+ rescue LoadError
56
+ next
57
+ end
58
+ end
59
+ end
60
+
61
+ def load_adapter(adapter)
62
+ require ADAPTERS[adapter][:require]
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,119 @@
1
+ require "cs-httpi/response"
2
+
3
+ module HTTPI
4
+ module Adapter
5
+
6
+ # = HTTPI::Adapter::Curb
7
+ #
8
+ # Adapter for the Curb client.
9
+ # http://rubygems.org/gems/curb
10
+ class Curb
11
+
12
+ def initialize(request = nil)
13
+ end
14
+
15
+ # Returns a memoized <tt>Curl::Easy</tt> instance.
16
+ def client
17
+ @client ||= Curl::Easy.new
18
+ end
19
+
20
+ # Executes an HTTP GET request.
21
+ # @see HTTPI.get
22
+ def get(request)
23
+ do_request(request) { |client| client.http_get }
24
+ end
25
+
26
+ # Executes an HTTP POST request.
27
+ # @see HTTPI.post
28
+ def post(request)
29
+ do_request(request) { |client| client.http_post request.body }
30
+ end
31
+
32
+ # Executes an HTTP HEAD request.
33
+ # @see HTTPI.head
34
+ def head(request)
35
+ do_request(request) { |client| client.http_head }
36
+ end
37
+
38
+ # Executes an HTTP PUT request.
39
+ # @see HTTPI.put
40
+ def put(request)
41
+ do_request(request) { |client| client.http_put request.body }
42
+ end
43
+
44
+ # Executes an HTTP DELETE request.
45
+ # @see HTTPI.delete
46
+ def delete(request)
47
+ do_request(request) { |client| client.http_delete }
48
+ end
49
+
50
+ private
51
+
52
+ def do_request(request)
53
+ setup_client request
54
+ yield client
55
+ respond_with client
56
+ end
57
+
58
+ def setup_client(request)
59
+ basic_setup request
60
+ setup_http_auth request if request.auth.http?
61
+ setup_ssl_auth request.auth.ssl if request.auth.ssl?
62
+ end
63
+
64
+ def basic_setup(request)
65
+ client.url = request.url.to_s
66
+ client.proxy_url = request.proxy.to_s if request.proxy
67
+ client.timeout = request.read_timeout if request.read_timeout
68
+ client.connect_timeout = request.open_timeout if request.open_timeout
69
+ client.headers = request.headers.to_hash
70
+ client.verbose = false
71
+ end
72
+
73
+ def setup_http_auth(request)
74
+ client.http_auth_types = request.auth.type
75
+ client.username, client.password = *request.auth.credentials
76
+ end
77
+
78
+ def setup_ssl_auth(ssl)
79
+ client.cert_key = ssl.cert_key_file
80
+ client.cert = ssl.cert_file
81
+ client.cacert = ssl.ca_cert_file if ssl.ca_cert_file
82
+ client.certtype = ssl.cert_type.to_s.upcase
83
+ client.ssl_verify_peer = ssl.verify_mode == :peer
84
+ end
85
+
86
+ def respond_with(client)
87
+ status, headers = parse_header_string(client.header_str)
88
+ Response.new client.response_code, headers, client.body_str
89
+ end
90
+
91
+ # Borrowed from Webmock's Curb adapter:
92
+ # http://github.com/bblimke/webmock/blob/master/lib/webmock/http_lib_adapters/curb.rb
93
+ def parse_header_string(header_string)
94
+ status, headers = nil, {}
95
+ return [status, headers] unless header_string
96
+
97
+ header_string.split(/\r\n/).each do |header|
98
+ if header =~ %r|^HTTP/1.[01] \d\d\d (.*)|
99
+ status = $1
100
+ else
101
+ parts = header.split(':', 2)
102
+ unless parts.empty?
103
+ parts[1].strip! unless parts[1].nil?
104
+ if headers.has_key?(parts[0])
105
+ headers[parts[0]] = [headers[parts[0]]] unless headers[parts[0]].kind_of? Array
106
+ headers[parts[0]] << parts[1]
107
+ else
108
+ headers[parts[0]] = parts[1]
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ [status, headers]
115
+ end
116
+
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,98 @@
1
+ require "cs-httpi/response"
2
+
3
+ module HTTPI
4
+ module Adapter
5
+
6
+ # = HTTPI::Adapter::HTTPClient
7
+ #
8
+ # Adapter for the HTTPClient client.
9
+ # http://rubygems.org/gems/httpclient
10
+ class HTTPClient
11
+
12
+ def initialize(request = nil)
13
+ end
14
+
15
+ # Returns a memoized <tt>HTTPClient</tt> instance.
16
+ def client
17
+ @client ||= ::HTTPClient.new
18
+ end
19
+
20
+ # Executes an HTTP GET request.
21
+ # @see HTTPI.get
22
+ def get(request)
23
+ do_request request do |url, headers|
24
+ client.get url, nil, headers
25
+ end
26
+ end
27
+
28
+ # Executes an HTTP POST request.
29
+ # @see HTTPI.post
30
+ def post(request)
31
+ do_request request do |url, headers, body|
32
+ client.post url, body, headers
33
+ end
34
+ end
35
+
36
+ # Executes an HTTP HEAD request.
37
+ # @see HTTPI.head
38
+ def head(request)
39
+ do_request request do |url, headers|
40
+ client.head url, nil, headers
41
+ end
42
+ end
43
+
44
+ # Executes an HTTP PUT request.
45
+ # @see HTTPI.put
46
+ def put(request)
47
+ do_request request do |url, headers, body|
48
+ client.put url, body, headers
49
+ end
50
+ end
51
+
52
+ # Executes an HTTP DELETE request.
53
+ # @see HTTPI.delete
54
+ def delete(request)
55
+ do_request request do |url, headers|
56
+ client.delete url, headers
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def do_request(request)
63
+ setup_client request
64
+ respond_with yield(request.url, request.headers, request.body)
65
+ end
66
+
67
+ def setup_client(request)
68
+ basic_setup request
69
+ setup_auth request if request.auth.http?
70
+ setup_ssl_auth request.auth.ssl if request.auth.ssl?
71
+ end
72
+
73
+ def basic_setup(request)
74
+ client.proxy = request.proxy if request.proxy
75
+ client.connect_timeout = request.open_timeout if request.open_timeout
76
+ client.receive_timeout = request.read_timeout if request.read_timeout
77
+ end
78
+
79
+ def setup_auth(request)
80
+ client.set_auth request.url, *request.auth.credentials
81
+ end
82
+
83
+ def setup_ssl_auth(ssl)
84
+ unless ssl.verify_mode == :none
85
+ client.ssl_config.client_cert = ssl.cert
86
+ client.ssl_config.client_key = ssl.cert_key
87
+ client.ssl_config.client_ca = ssl.ca_cert if ssl.ca_cert_file
88
+ end
89
+ client.ssl_config.verify_mode = ssl.openssl_verify_mode
90
+ end
91
+
92
+ def respond_with(response)
93
+ Response.new response.code, Hash[*response.header.all.flatten], response.content
94
+ end
95
+
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,115 @@
1
+ require "uri"
2
+ require "cs-httpi/response"
3
+
4
+ module HTTPI
5
+ module Adapter
6
+
7
+ # = HTTPI::Adapter::NetHTTP
8
+ #
9
+ # Adapter for the Net::HTTP client.
10
+ # http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/
11
+ class NetHTTP
12
+
13
+ def initialize(request)
14
+ self.client = new_client request
15
+ end
16
+
17
+ attr_reader :client
18
+
19
+ # Executes an HTTP GET request.
20
+ # @see HTTPI.get
21
+ def get(request)
22
+ do_request :get, request do |http, get|
23
+ http.request get
24
+ end
25
+ end
26
+
27
+ # Executes an HTTP POST request.
28
+ # @see HTTPI.post
29
+ def post(request)
30
+ do_request :post, request do |http, post|
31
+ post.body = request.body
32
+ http.request post
33
+ end
34
+ end
35
+
36
+ # Executes an HTTP HEAD request.
37
+ # @see HTTPI.head
38
+ def head(request)
39
+ do_request :head, request do |http, head|
40
+ http.request head
41
+ end
42
+ end
43
+
44
+ # Executes an HTTP PUT request.
45
+ # @see HTTPI.put
46
+ def put(request)
47
+ do_request :put, request do |http, put|
48
+ put.body = request.body
49
+ http.request put
50
+ end
51
+ end
52
+
53
+ # Executes an HTTP DELETE request.
54
+ # @see HTTPI.delete
55
+ def delete(request)
56
+ do_request :delete, request do |http, delete|
57
+ http.request delete
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ attr_writer :client
64
+
65
+ def new_client(request)
66
+ proxy = request.proxy || URI("")
67
+ Net::HTTP::Proxy(proxy.host, proxy.port).new request.url.host, request.url.port
68
+ end
69
+
70
+ def do_request(type, request)
71
+ setup_client request
72
+ setup_ssl_auth request.auth.ssl if request.auth.ssl?
73
+
74
+ respond_with(client.start do |http|
75
+ yield http, request_client(type, request)
76
+ end)
77
+ end
78
+
79
+ def setup_client(request)
80
+ client.use_ssl = request.ssl?
81
+ client.open_timeout = request.open_timeout if request.open_timeout
82
+ client.read_timeout = request.read_timeout if request.read_timeout
83
+ end
84
+
85
+ def setup_ssl_auth(ssl)
86
+ client.key = ssl.cert_key
87
+ client.cert = ssl.cert
88
+ client.ca_file = ssl.ca_cert_file if ssl.ca_cert_file
89
+ client.verify_mode = ssl.openssl_verify_mode
90
+ end
91
+
92
+ def request_client(type, request)
93
+ request_class = case type
94
+ when :get then Net::HTTP::Get
95
+ when :post then Net::HTTP::Post
96
+ when :head then Net::HTTP::Head
97
+ when :put then Net::HTTP::Put
98
+ when :delete then Net::HTTP::Delete
99
+ end
100
+
101
+ request_client = request_class.new request.url.request_uri, request.headers
102
+ request_client.basic_auth *request.auth.credentials if request.auth.basic?
103
+
104
+ request_client
105
+ end
106
+
107
+ def respond_with(response)
108
+ headers = response.to_hash
109
+ headers.each { |key, value| headers[key] = value[0] }
110
+ Response.new response.code, headers, response.body
111
+ end
112
+
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,78 @@
1
+ require "cs-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
+ # Only available with the httpi-ntlm gem.
47
+ def ntlm(*args)
48
+ raise "Install the httpi-ntlm gem for experimental NTLM support"
49
+ end
50
+
51
+ # Only available with the httpi-ntlm gem.
52
+ def ntlm?
53
+ raise "Install the httpi-ntlm gem for experimental NTLM support"
54
+ end
55
+
56
+ # Returns the <tt>HTTPI::Auth::SSL</tt> object.
57
+ def ssl
58
+ @ssl ||= SSL.new
59
+ end
60
+
61
+ # Returns whether to use SSL client auth.
62
+ def ssl?
63
+ ssl.present?
64
+ end
65
+
66
+ # Shortcut method for returning the credentials for the authentication specified.
67
+ # Returns +nil+ unless any authentication credentials were specified.
68
+ def credentials
69
+ return unless type
70
+ send type
71
+ end
72
+
73
+ # Accessor for the authentication type in use.
74
+ attr_accessor :type
75
+
76
+ end
77
+ end
78
+ end