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,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
|