cs-httpi 0.9.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,91 @@
|
|
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
|
+
CERT_TYPES = [:pem, :der]
|
13
|
+
|
14
|
+
# Returns whether SSL configuration is present.
|
15
|
+
def present?
|
16
|
+
(verify_mode == :none) || (cert && cert_key)
|
17
|
+
rescue TypeError, Errno::ENOENT
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
# Accessor for the cert key file to validate SSL certificates.
|
22
|
+
attr_accessor :cert_key_file
|
23
|
+
|
24
|
+
# Accessor for the cert key password to validate SSL certificates.
|
25
|
+
attr_accessor :cert_key_password
|
26
|
+
|
27
|
+
# Accessor for the cert file to validate SSL connections.
|
28
|
+
attr_accessor :cert_file
|
29
|
+
|
30
|
+
# Accessor for the cacert file to validate SSL certificates.
|
31
|
+
attr_accessor :ca_cert_file
|
32
|
+
|
33
|
+
# Returns the cert type to validate SSL certificates PEM|DER.
|
34
|
+
def cert_type
|
35
|
+
@cert_type ||= :pem
|
36
|
+
end
|
37
|
+
|
38
|
+
# Sets the cert type to validate SSL certificates PEM|DER.
|
39
|
+
def cert_type=(type)
|
40
|
+
raise ArgumentError, "Invalid SSL cert type: #{type}" unless CERT_TYPES.include? type
|
41
|
+
@cert_type = type
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the SSL verify mode. Defaults to <tt>:peer</tt>.
|
45
|
+
def verify_mode
|
46
|
+
@verify_mode ||= :peer
|
47
|
+
end
|
48
|
+
|
49
|
+
# Sets the SSL verify mode. Expects one of <tt>HTTPI::Auth::SSL::VERIFY_MODES</tt>.
|
50
|
+
def verify_mode=(mode)
|
51
|
+
raise ArgumentError, "Invalid SSL verify mode: #{mode}" unless VERIFY_MODES.include? mode
|
52
|
+
@verify_mode = mode
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns an <tt>OpenSSL::X509::Certificate</tt> for the +cert_file+.
|
56
|
+
def cert
|
57
|
+
@cert ||= OpenSSL::X509::Certificate.new File.read(cert_file) if cert_file
|
58
|
+
end
|
59
|
+
|
60
|
+
# Sets the +OpenSSL+ certificate.
|
61
|
+
attr_writer :cert
|
62
|
+
|
63
|
+
# Returns an <tt>OpenSSL::X509::Certificate</tt> for the +ca_cert_file+.
|
64
|
+
def ca_cert
|
65
|
+
@ca_cert ||= OpenSSL::X509::Certificate.new File.read(ca_cert_file)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Sets the +OpenSSL+ ca certificate.
|
69
|
+
attr_writer :ca_cert
|
70
|
+
|
71
|
+
# Returns an <tt>OpenSSL::PKey::RSA</tt> for the +cert_key_file+.
|
72
|
+
def cert_key
|
73
|
+
@cert_key ||= OpenSSL::PKey::RSA.new(File.read(cert_key_file), cert_key_password) if cert_key_file
|
74
|
+
end
|
75
|
+
|
76
|
+
# Sets the +OpenSSL+ certificate key.
|
77
|
+
attr_writer :cert_key
|
78
|
+
|
79
|
+
# Returns the SSL verify mode as a <tt>OpenSSL::SSL::VERIFY_*</tt> constant.
|
80
|
+
def openssl_verify_mode
|
81
|
+
case verify_mode
|
82
|
+
when :none then OpenSSL::SSL::VERIFY_NONE
|
83
|
+
when :peer then OpenSSL::SSL::VERIFY_PEER
|
84
|
+
when :fail_if_no_peer_cert then OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
85
|
+
when :client_once then OpenSSL::SSL::VERIFY_CLIENT_ONCE
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module HTTPI
|
2
|
+
class DimeRecord < Struct.new('DimeRecord', :version, :first, :last, :chunked, :type_format, :options, :id, :type, :data)
|
3
|
+
end
|
4
|
+
|
5
|
+
class Dime < Array
|
6
|
+
BINARY = 1
|
7
|
+
XML = 2
|
8
|
+
|
9
|
+
def initialize(body)
|
10
|
+
bytes = body.unpack('C*')
|
11
|
+
|
12
|
+
while bytes.length > 0
|
13
|
+
record = DimeRecord.new
|
14
|
+
|
15
|
+
# Shift out bitfields for the first fields
|
16
|
+
byte = bytes.shift
|
17
|
+
record.version = (byte >> 3) & 31 # 5 bits DIME format version (always 1)
|
18
|
+
record.first = (byte >> 2) & 1 # 1 bit Set if this is the first part in the message
|
19
|
+
record.last = (byte >> 1) & 1 # 1 bit Set if this is the last part in the message
|
20
|
+
record.chunked = byte & 1 # 1 bit This file is broken into chunked parts
|
21
|
+
record.type_format = (bytes.shift >> 4) & 15 # 4 bits Type of file in the part (1 for binary data, 2 for XML)
|
22
|
+
# 4 bits Reserved (skipped in the above command)
|
23
|
+
|
24
|
+
# Fetch big-endian lengths
|
25
|
+
lengths = [] # we can't use a hash since the order will be screwed in Ruby 1.8
|
26
|
+
lengths << [:options, (bytes.shift << 8) | bytes.shift] # 2 bytes Length of the "options" field
|
27
|
+
lengths << [:id, (bytes.shift << 8) | bytes.shift] # 2 bytes Length of the "ID" or "name" field
|
28
|
+
lengths << [:type, (bytes.shift << 8) | bytes.shift] # 2 bytes Length of the "type" field
|
29
|
+
lengths << [:data, (bytes.shift << 24) | (bytes.shift << 16) | (bytes.shift << 8) | bytes.shift] # 4 bytes Size of the included file
|
30
|
+
|
31
|
+
# Read in padded data
|
32
|
+
lengths.each do |attribute_set|
|
33
|
+
attribute, length = attribute_set
|
34
|
+
content = bytes.slice!(0, length).pack('C*')
|
35
|
+
if attribute == :data && record.type_format == BINARY
|
36
|
+
content = StringIO.new(content)
|
37
|
+
end
|
38
|
+
|
39
|
+
record.send "#{attribute.to_s}=", content
|
40
|
+
|
41
|
+
bytes.slice!(0, 4 - (length & 3)) if (length & 3) != 0
|
42
|
+
end
|
43
|
+
|
44
|
+
self << record
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def xml_records
|
49
|
+
select { |r| r.type_format == XML }
|
50
|
+
end
|
51
|
+
|
52
|
+
def binary_records
|
53
|
+
select { |r| r.type_format == BINARY }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "uri"
|
2
|
+
require "cs-httpi/auth/config"
|
3
|
+
require "rack/utils"
|
4
|
+
|
5
|
+
module HTTPI
|
6
|
+
|
7
|
+
# = HTTPI::Request
|
8
|
+
#
|
9
|
+
# Represents an HTTP request and contains various methods for customizing that request.
|
10
|
+
class Request
|
11
|
+
|
12
|
+
# Available attribute writers.
|
13
|
+
ATTRIBUTES = [:url, :proxy, :headers, :body, :open_timeout, :read_timeout]
|
14
|
+
|
15
|
+
# Accepts a Hash of +args+ to mass assign attributes and authentication credentials.
|
16
|
+
def initialize(args = {})
|
17
|
+
if args.kind_of? String
|
18
|
+
self.url = args
|
19
|
+
elsif args.kind_of?(Hash) && !args.empty?
|
20
|
+
mass_assign args
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Sets the +url+ to access. Raises an +ArgumentError+ unless the +url+ is valid.
|
25
|
+
def url=(url)
|
26
|
+
@url = normalize_url! url
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the +url+ to access.
|
30
|
+
attr_reader :url
|
31
|
+
|
32
|
+
# Sets the +proxy+ to use. Raises an +ArgumentError+ unless the +proxy+ is valid.
|
33
|
+
def proxy=(proxy)
|
34
|
+
@proxy = normalize_url! proxy
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the +proxy+ to use.
|
38
|
+
attr_reader :proxy
|
39
|
+
|
40
|
+
# Returns whether to use SSL.
|
41
|
+
def ssl?
|
42
|
+
return @ssl unless @ssl.nil?
|
43
|
+
!!(url.to_s =~ /^https/)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Sets whether to use SSL.
|
47
|
+
attr_writer :ssl
|
48
|
+
|
49
|
+
# Returns a Hash of HTTP headers. Defaults to return an empty Hash.
|
50
|
+
def headers
|
51
|
+
@headers ||= Rack::Utils::HeaderHash.new
|
52
|
+
end
|
53
|
+
|
54
|
+
# Sets the Hash of HTTP headers.
|
55
|
+
def headers=(headers)
|
56
|
+
@headers = Rack::Utils::HeaderHash.new(headers)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Adds a header information to accept gzipped content.
|
60
|
+
def gzip
|
61
|
+
headers["Accept-Encoding"] = "gzip,deflate"
|
62
|
+
end
|
63
|
+
|
64
|
+
attr_accessor :open_timeout, :read_timeout
|
65
|
+
attr_reader :body
|
66
|
+
|
67
|
+
def body=(new_value)
|
68
|
+
if new_value.is_a?(Hash)
|
69
|
+
@body = new_value.map {|k,v| "#{k}=#{v}" }.join "&"
|
70
|
+
else
|
71
|
+
@body = new_value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns the <tt>HTTPI::Authentication</tt> object.
|
76
|
+
def auth
|
77
|
+
@auth ||= Auth::Config.new
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns whether any authentication credentials were specified.
|
81
|
+
def auth?
|
82
|
+
!!auth.type
|
83
|
+
end
|
84
|
+
|
85
|
+
# Expects a Hash of +args+ to assign.
|
86
|
+
def mass_assign(args)
|
87
|
+
ATTRIBUTES.each { |key| send("#{key}=", args[key]) if args[key] }
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# Expects a +url+, validates its validity and returns a +URI+ object.
|
93
|
+
def normalize_url!(url)
|
94
|
+
raise ArgumentError, "Invalid URL: #{url}" unless url.to_s =~ /^http/
|
95
|
+
url.kind_of?(URI) ? url : URI(url)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "zlib"
|
2
|
+
require "stringio"
|
3
|
+
require "cs-httpi/dime"
|
4
|
+
require "rack/utils"
|
5
|
+
|
6
|
+
module HTTPI
|
7
|
+
|
8
|
+
# = HTTPI::Response
|
9
|
+
#
|
10
|
+
# Represents an HTTP response and contains various response details.
|
11
|
+
class Response
|
12
|
+
|
13
|
+
# Range of HTTP response codes considered to be successful.
|
14
|
+
SuccessfulResponseCodes = 200..299
|
15
|
+
|
16
|
+
# Initializer expects an HTTP response +code+, +headers+ and +body+.
|
17
|
+
def initialize(code, headers, body)
|
18
|
+
self.code = code.to_i
|
19
|
+
self.headers = Rack::Utils::HeaderHash.new(headers)
|
20
|
+
self.raw_body = body
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :code, :headers, :raw_body, :attachments
|
24
|
+
|
25
|
+
# Returns whether the HTTP response is considered successful.
|
26
|
+
def error?
|
27
|
+
!SuccessfulResponseCodes.include? code.to_i
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns whether the HTTP response is a multipart response.
|
31
|
+
def multipart?
|
32
|
+
!!(headers["Content-Type"] =~ /^multipart/i)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns any DIME attachments.
|
36
|
+
def attachments
|
37
|
+
decode_body unless @body
|
38
|
+
@attachments ||= []
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns the HTTP response body.
|
42
|
+
def body
|
43
|
+
decode_body unless @body
|
44
|
+
@body
|
45
|
+
end
|
46
|
+
|
47
|
+
attr_writer :body
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def decode_body
|
52
|
+
return @body = "" if !raw_body || raw_body.empty?
|
53
|
+
|
54
|
+
body = gzipped_response? ? decoded_gzip_body : raw_body
|
55
|
+
@body = dime_response? ? decoded_dime_body(body) : body
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns whether the response is gzipped.
|
59
|
+
def gzipped_response?
|
60
|
+
headers["Content-Encoding"] == "gzip" || raw_body[0..1] == "\x1f\x8b"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns whether this is a DIME response.
|
64
|
+
def dime_response?
|
65
|
+
headers["Content-Type"] == "application/dime"
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns the gzip decoded response body.
|
69
|
+
def decoded_gzip_body
|
70
|
+
gzip = Zlib::GzipReader.new StringIO.new(raw_body)
|
71
|
+
raise ArgumentError.new "couldn't create gzip reader" unless gzip
|
72
|
+
gzip.read
|
73
|
+
ensure
|
74
|
+
gzip.close if gzip
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns the DIME decoded response body.
|
78
|
+
def decoded_dime_body(body = nil)
|
79
|
+
dime = Dime.new(body || raw_body)
|
80
|
+
self.attachments = dime.binary_records
|
81
|
+
dime.xml_records.first.data
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project xmlns="http://www.netbeans.org/ns/project/1">
|
3
|
+
<type>org.netbeans.modules.ruby.rubyproject</type>
|
4
|
+
<configuration>
|
5
|
+
<data xmlns="http://www.netbeans.org/ns/ruby-project/1">
|
6
|
+
<name>cs-httpi</name>
|
7
|
+
<source-roots>
|
8
|
+
<root id="src.dir"/>
|
9
|
+
</source-roots>
|
10
|
+
<test-roots>
|
11
|
+
<root id="test.src.dir"/>
|
12
|
+
</test-roots>
|
13
|
+
</data>
|
14
|
+
</configuration>
|
15
|
+
</project>
|
@@ -0,0 +1,232 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "cs-httpi/adapter/curb"
|
3
|
+
require "cs-httpi/request"
|
4
|
+
|
5
|
+
# curb does not run on jruby
|
6
|
+
unless RUBY_PLATFORM =~ /java/
|
7
|
+
require "curb"
|
8
|
+
|
9
|
+
describe HTTPI::Adapter::Curb do
|
10
|
+
let(:adapter) { HTTPI::Adapter::Curb.new }
|
11
|
+
let(:curb) { Curl::Easy.any_instance }
|
12
|
+
|
13
|
+
describe "#get" do
|
14
|
+
before do
|
15
|
+
curb.expects(:http_get)
|
16
|
+
curb.expects(:response_code).returns(200)
|
17
|
+
curb.expects(:header_str).returns("Accept-encoding: utf-8")
|
18
|
+
curb.expects(:body_str).returns(Fixture.xml)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns a valid HTTPI::Response" do
|
22
|
+
adapter.get(basic_request).should match_response(:body => Fixture.xml)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#post" do
|
27
|
+
before do
|
28
|
+
curb.expects(:http_post)
|
29
|
+
curb.expects(:response_code).returns(200)
|
30
|
+
curb.expects(:header_str).returns("Accept-encoding: utf-8")
|
31
|
+
curb.expects(:body_str).returns(Fixture.xml)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns a valid HTTPI::Response" do
|
35
|
+
adapter.post(basic_request).should match_response(:body => Fixture.xml)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#post" do
|
40
|
+
it "sends the body in the request" do
|
41
|
+
curb.expects(:http_post).with('xml=hi&name=123')
|
42
|
+
adapter.post(basic_request { |request| request.body = 'xml=hi&name=123' } )
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#head" do
|
47
|
+
before do
|
48
|
+
curb.expects(:http_head)
|
49
|
+
curb.expects(:response_code).returns(200)
|
50
|
+
curb.expects(:header_str).returns("Accept-encoding: utf-8")
|
51
|
+
curb.expects(:body_str).returns(Fixture.xml)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "returns a valid HTTPI::Response" do
|
55
|
+
adapter.head(basic_request).should match_response(:body => Fixture.xml)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#put" do
|
60
|
+
before do
|
61
|
+
curb.expects(:http_put)
|
62
|
+
curb.expects(:response_code).returns(200)
|
63
|
+
curb.expects(:header_str).returns("Accept-encoding: utf-8")
|
64
|
+
curb.expects(:body_str).returns(Fixture.xml)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "returns a valid HTTPI::Response" do
|
68
|
+
adapter.put(basic_request).should match_response(:body => Fixture.xml)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#put" do
|
73
|
+
it "sends the body in the request" do
|
74
|
+
curb.expects(:http_put).with('xml=hi&name=123')
|
75
|
+
adapter.put(basic_request { |request| request.body = 'xml=hi&name=123' } )
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#delete" do
|
80
|
+
before do
|
81
|
+
curb.expects(:http_delete)
|
82
|
+
curb.expects(:response_code).returns(200)
|
83
|
+
curb.expects(:header_str).returns("Accept-encoding: utf-8")
|
84
|
+
curb.expects(:body_str).returns("")
|
85
|
+
end
|
86
|
+
|
87
|
+
it "returns a valid HTTPI::Response" do
|
88
|
+
adapter.delete(basic_request).should match_response(:body => "")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "settings:" do
|
93
|
+
before { curb.stubs(:http_get) }
|
94
|
+
|
95
|
+
describe "url" do
|
96
|
+
it "always sets the request url" do
|
97
|
+
curb.expects(:url=).with(basic_request.url.to_s)
|
98
|
+
adapter.get(basic_request)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "proxy_url" do
|
103
|
+
it "is not set unless it's specified" do
|
104
|
+
curb.expects(:proxy_url=).never
|
105
|
+
adapter.get(basic_request)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "is set if specified" do
|
109
|
+
request = basic_request { |request| request.proxy = "http://proxy.example.com" }
|
110
|
+
|
111
|
+
curb.expects(:proxy_url=).with(request.proxy.to_s)
|
112
|
+
adapter.get(request)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "timeout" do
|
117
|
+
it "is not set unless it's specified" do
|
118
|
+
curb.expects(:timeout=).never
|
119
|
+
adapter.get(basic_request)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "is set if specified" do
|
123
|
+
request = basic_request { |request| request.read_timeout = 30 }
|
124
|
+
|
125
|
+
curb.expects(:timeout=).with(30)
|
126
|
+
adapter.get(request)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "connect_timeout" do
|
131
|
+
it "is not set unless it's specified" do
|
132
|
+
curb.expects(:connect_timeout=).never
|
133
|
+
adapter.get(basic_request)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "is set if specified" do
|
137
|
+
request = basic_request { |request| request.open_timeout = 30 }
|
138
|
+
|
139
|
+
curb.expects(:connect_timeout=).with(30)
|
140
|
+
adapter.get(request)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "headers" do
|
145
|
+
it "is always set" do
|
146
|
+
curb.expects(:headers=).with({})
|
147
|
+
adapter.get(basic_request)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "verbose" do
|
152
|
+
it "is always set to false" do
|
153
|
+
curb.expects(:verbose=).with(false)
|
154
|
+
adapter.get(basic_request)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "http_auth_types" do
|
159
|
+
it "is set to :basic for HTTP basic auth" do
|
160
|
+
request = basic_request { |request| request.auth.basic "username", "password" }
|
161
|
+
|
162
|
+
curb.expects(:http_auth_types=).with(:basic)
|
163
|
+
adapter.get(request)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "is set to :digest for HTTP digest auth" do
|
167
|
+
request = basic_request { |request| request.auth.digest "username", "password" }
|
168
|
+
|
169
|
+
curb.expects(:http_auth_types=).with(:digest)
|
170
|
+
adapter.get(request)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "username and password" do
|
175
|
+
it "is set for HTTP basic auth" do
|
176
|
+
request = basic_request { |request| request.auth.basic "username", "password" }
|
177
|
+
|
178
|
+
curb.expects(:username=).with("username")
|
179
|
+
curb.expects(:password=).with("password")
|
180
|
+
adapter.get(request)
|
181
|
+
end
|
182
|
+
|
183
|
+
it "is set for HTTP digest auth" do
|
184
|
+
request = basic_request { |request| request.auth.digest "username", "password" }
|
185
|
+
|
186
|
+
curb.expects(:username=).with("username")
|
187
|
+
curb.expects(:password=).with("password")
|
188
|
+
adapter.get(request)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context "(for SSL client auth)" do
|
193
|
+
let(:ssl_auth_request) do
|
194
|
+
basic_request do |request|
|
195
|
+
request.auth.ssl.cert_key_file = "spec/fixtures/client_key.pem"
|
196
|
+
request.auth.ssl.cert_file = "spec/fixtures/client_cert.pem"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
it "cert_key, cert and ssl_verify_peer should be set" do
|
201
|
+
curb.expects(:cert_key=).with(ssl_auth_request.auth.ssl.cert_key_file)
|
202
|
+
curb.expects(:cert=).with(ssl_auth_request.auth.ssl.cert_file)
|
203
|
+
curb.expects(:ssl_verify_peer=).with(true)
|
204
|
+
curb.expects(:certtype=).with(ssl_auth_request.auth.ssl.cert_type.to_s.upcase)
|
205
|
+
|
206
|
+
adapter.get(ssl_auth_request)
|
207
|
+
end
|
208
|
+
|
209
|
+
it "sets the cert_type to DER if specified" do
|
210
|
+
ssl_auth_request.auth.ssl.cert_type = :der
|
211
|
+
curb.expects(:certtype=).with(:der.to_s.upcase)
|
212
|
+
|
213
|
+
adapter.get(ssl_auth_request)
|
214
|
+
end
|
215
|
+
|
216
|
+
it "sets the cacert if specified" do
|
217
|
+
ssl_auth_request.auth.ssl.ca_cert_file = "spec/fixtures/client_cert.pem"
|
218
|
+
curb.expects(:cacert=).with(ssl_auth_request.auth.ssl.ca_cert_file)
|
219
|
+
|
220
|
+
adapter.get(ssl_auth_request)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def basic_request
|
226
|
+
request = HTTPI::Request.new :url => "http://example.com"
|
227
|
+
yield request if block_given?
|
228
|
+
request
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
end
|