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.
- data/.autotest +5 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +66 -0
- data/Gemfile +9 -0
- data/LICENSE +20 -0
- data/README.md +229 -0
- data/Rakefile +18 -0
- data/autotest/discover.rb +1 -0
- data/cs-httpi.gemspec +26 -0
- data/lib/cs-httpi.rb +198 -0
- data/lib/cs-httpi/adapter.rb +67 -0
- data/lib/cs-httpi/adapter/curb.rb +119 -0
- data/lib/cs-httpi/adapter/httpclient.rb +98 -0
- data/lib/cs-httpi/adapter/net_http.rb +115 -0
- data/lib/cs-httpi/auth/config.rb +78 -0
- data/lib/cs-httpi/auth/ssl.rb +91 -0
- data/lib/cs-httpi/dime.rb +56 -0
- data/lib/cs-httpi/request.rb +99 -0
- data/lib/cs-httpi/response.rb +85 -0
- data/lib/cs-httpi/version.rb +5 -0
- data/nbproject/private/private.properties +2 -0
- data/nbproject/private/rake-d.txt +0 -0
- data/nbproject/project.properties +7 -0
- data/nbproject/project.xml +15 -0
- data/spec/cs-httpi/adapter/curb_spec.rb +232 -0
- data/spec/cs-httpi/adapter/httpclient_spec.rb +164 -0
- data/spec/cs-httpi/adapter/net_http_spec.rb +142 -0
- data/spec/cs-httpi/adapter_spec.rb +55 -0
- data/spec/cs-httpi/auth/config_spec.rb +117 -0
- data/spec/cs-httpi/auth/ssl_spec.rb +128 -0
- data/spec/cs-httpi/httpi_spec.rb +284 -0
- data/spec/cs-httpi/request_spec.rb +140 -0
- data/spec/cs-httpi/response_spec.rb +125 -0
- data/spec/fixtures/attachment.gif +0 -0
- data/spec/fixtures/client_cert.pem +16 -0
- data/spec/fixtures/client_key.pem +15 -0
- data/spec/fixtures/xml.gz +0 -0
- data/spec/fixtures/xml.xml +10 -0
- data/spec/fixtures/xml_dime.dime +0 -0
- data/spec/fixtures/xml_dime.xml +1 -0
- data/spec/integration/request_spec.rb +95 -0
- data/spec/integration/server.rb +39 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/fixture.rb +27 -0
- data/spec/support/matchers.rb +19 -0
- 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
|