summaryrefslogtreecommitdiff
path: root/lib/vendor/excon/tests
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vendor/excon/tests')
-rw-r--r--lib/vendor/excon/tests/authorization_header_tests.rb29
-rw-r--r--lib/vendor/excon/tests/bad_tests.rb47
-rw-r--r--lib/vendor/excon/tests/basic_tests.rb349
-rw-r--r--lib/vendor/excon/tests/complete_responses.rb31
-rw-r--r--lib/vendor/excon/tests/data/127.0.0.1.cert.crt14
-rw-r--r--lib/vendor/excon/tests/data/127.0.0.1.cert.key15
-rw-r--r--lib/vendor/excon/tests/data/excon.cert.crt14
-rw-r--r--lib/vendor/excon/tests/data/excon.cert.key15
-rw-r--r--lib/vendor/excon/tests/data/xs1
-rw-r--r--lib/vendor/excon/tests/error_tests.rb145
-rw-r--r--lib/vendor/excon/tests/header_tests.rb119
-rw-r--r--lib/vendor/excon/tests/middlewares/canned_response_tests.rb34
-rw-r--r--lib/vendor/excon/tests/middlewares/capture_cookies_tests.rb34
-rw-r--r--lib/vendor/excon/tests/middlewares/decompress_tests.rb157
-rw-r--r--lib/vendor/excon/tests/middlewares/escape_path_tests.rb36
-rw-r--r--lib/vendor/excon/tests/middlewares/idempotent_tests.rb131
-rw-r--r--lib/vendor/excon/tests/middlewares/instrumentation_tests.rb315
-rw-r--r--lib/vendor/excon/tests/middlewares/mock_tests.rb304
-rw-r--r--lib/vendor/excon/tests/middlewares/redirect_follower_tests.rb80
-rw-r--r--lib/vendor/excon/tests/pipeline_tests.rb40
-rw-r--r--lib/vendor/excon/tests/proxy_tests.rb306
-rw-r--r--lib/vendor/excon/tests/query_string_tests.rb87
-rw-r--r--lib/vendor/excon/tests/rackups/basic.rb41
-rw-r--r--lib/vendor/excon/tests/rackups/basic.ru3
-rw-r--r--lib/vendor/excon/tests/rackups/basic_auth.ru14
-rw-r--r--lib/vendor/excon/tests/rackups/deflater.ru4
-rw-r--r--lib/vendor/excon/tests/rackups/proxy.ru18
-rw-r--r--lib/vendor/excon/tests/rackups/query_string.ru13
-rw-r--r--lib/vendor/excon/tests/rackups/redirecting.ru23
-rw-r--r--lib/vendor/excon/tests/rackups/redirecting_with_cookie.ru40
-rw-r--r--lib/vendor/excon/tests/rackups/request_headers.ru15
-rw-r--r--lib/vendor/excon/tests/rackups/request_methods.ru21
-rw-r--r--lib/vendor/excon/tests/rackups/response_header.ru18
-rw-r--r--lib/vendor/excon/tests/rackups/ssl.ru16
-rw-r--r--lib/vendor/excon/tests/rackups/ssl_mismatched_cn.ru15
-rw-r--r--lib/vendor/excon/tests/rackups/ssl_verify_peer.ru16
-rw-r--r--lib/vendor/excon/tests/rackups/streaming.ru30
-rw-r--r--lib/vendor/excon/tests/rackups/thread_safety.ru17
-rw-r--r--lib/vendor/excon/tests/rackups/timeout.ru14
-rw-r--r--lib/vendor/excon/tests/rackups/webrick_patch.rb34
-rw-r--r--lib/vendor/excon/tests/request_headers_tests.rb21
-rw-r--r--lib/vendor/excon/tests/request_method_tests.rb47
-rw-r--r--lib/vendor/excon/tests/request_tests.rb59
-rw-r--r--lib/vendor/excon/tests/response_tests.rb197
-rwxr-xr-xlib/vendor/excon/tests/servers/bad.rb20
-rwxr-xr-xlib/vendor/excon/tests/servers/eof.rb17
-rwxr-xr-xlib/vendor/excon/tests/servers/error.rb20
-rwxr-xr-xlib/vendor/excon/tests/servers/good.rb350
-rw-r--r--lib/vendor/excon/tests/test_helper.rb306
-rw-r--r--lib/vendor/excon/tests/thread_safety_tests.rb39
-rw-r--r--lib/vendor/excon/tests/timeout_tests.rb12
-rw-r--r--lib/vendor/excon/tests/utils_tests.rb81
52 files changed, 3824 insertions, 0 deletions
diff --git a/lib/vendor/excon/tests/authorization_header_tests.rb b/lib/vendor/excon/tests/authorization_header_tests.rb
new file mode 100644
index 0000000..400a362
--- /dev/null
+++ b/lib/vendor/excon/tests/authorization_header_tests.rb
@@ -0,0 +1,29 @@
+Shindo.tests('Excon basics (Authorization data redacted)') do
+ with_rackup('basic_auth.ru') do
+ cases = [
+ ['user & pass', 'http://user1:pass1@foo.com/', 'Basic dXNlcjE6cGFzczE='],
+ ['email & pass', 'http://foo%40bar.com:pass1@foo.com/', 'Basic Zm9vQGJhci5jb206cGFzczE='],
+ ['user no pass', 'http://three_user@foo.com/', 'Basic dGhyZWVfdXNlcjo='],
+ ['pass no user', 'http://:derppass@foo.com/', 'Basic OmRlcnBwYXNz']
+ ]
+ cases.each do |desc,url,auth_header|
+ conn = nil
+
+ test("authorization header concealed for #{desc}") do
+ conn = Excon.new(url)
+ !conn.inspect.include?(auth_header)
+ end
+
+ if conn.data[:password]
+ test("password param concealed for #{desc}") do
+ !conn.inspect.include?(conn.data[:password])
+ end
+ end
+
+ test("password param remains correct for #{desc}") do
+ conn.data[:password] == URI.parse(url).password
+ end
+
+ end
+ end
+end
diff --git a/lib/vendor/excon/tests/bad_tests.rb b/lib/vendor/excon/tests/bad_tests.rb
new file mode 100644
index 0000000..1069cf3
--- /dev/null
+++ b/lib/vendor/excon/tests/bad_tests.rb
@@ -0,0 +1,47 @@
+Shindo.tests('Excon bad server interaction') do
+
+ with_server('bad') do
+
+ tests('bad server: causes EOFError') do
+
+ tests('with no content length and no chunking') do
+ tests('without a block') do
+ tests('response.body').returns('hello') do
+ connection = Excon.new('http://127.0.0.1:9292')
+
+ connection.request(:method => :get, :path => '/eof/no_content_length_and_no_chunking').body
+ end
+ end
+
+ tests('with a block') do
+ tests('body from chunks').returns('hello') do
+ connection = Excon.new('http://127.0.0.1:9292')
+
+ body = ""
+ response_block = lambda {|chunk, remaining, total| body << chunk }
+
+ connection.request(:method => :get, :path => '/eof/no_content_length_and_no_chunking', :response_block => response_block)
+
+ body
+ end
+ end
+
+ end
+
+ end
+
+ end
+
+ with_server('eof') do
+
+ tests('eof server: causes EOFError') do
+
+ tests('request').raises(Excon::Errors::SocketError) do
+ Excon.get('http://127.0.0.1:9292/eof')
+ end
+
+ end
+
+ end
+
+end
diff --git a/lib/vendor/excon/tests/basic_tests.rb b/lib/vendor/excon/tests/basic_tests.rb
new file mode 100644
index 0000000..f8ee529
--- /dev/null
+++ b/lib/vendor/excon/tests/basic_tests.rb
@@ -0,0 +1,349 @@
+require 'json'
+
+Shindo.tests('Excon basics') do
+ with_rackup('basic.ru') do
+ basic_tests
+
+ tests('explicit uri passed to connection') do
+ tests('GET /content-length/100').returns(200) do
+ connection = Excon::Connection.new({
+ :host => '127.0.0.1',
+ :hostname => '127.0.0.1',
+ :nonblock => false,
+ :port => 9292,
+ :scheme => 'http',
+ :ssl_verify_peer => false
+ })
+ response = connection.request(:method => :get, :path => '/content-length/100')
+ response[:status]
+ end
+ end
+ end
+end
+
+Shindo.tests('Excon streaming basics') do
+ pending if RUBY_PLATFORM == 'java' # need to find suitable server for jruby
+ with_unicorn('streaming.ru') do
+ # expected values: the response, in pieces, and a timeout after each piece
+ res = %w{Hello streamy world}
+ timeout = 0.1
+
+ # expect the full response as a string
+ # and expect it to take a (timeout * pieces) seconds
+ tests('simple blocking request on streaming endpoint').returns([res.join(''),'response time ok']) do
+ start = Time.now
+ ret = Excon.get('http://127.0.0.1:9292/streamed/simple').body
+
+ if Time.now - start <= timeout*3
+ [ret, 'streaming response came too quickly']
+ else
+ [ret, 'response time ok']
+ end
+ end
+
+ # expect the full response as a string and expect it to
+ # take a (timeout * pieces) seconds (with fixed Content-Length header)
+ tests('simple blocking request on streaming endpoint with fixed length').returns([res.join(''),'response time ok']) do
+ start = Time.now
+ ret = Excon.get('http://127.0.0.1:9292/streamed/fixed_length').body
+
+ if Time.now - start <= timeout*3
+ [ret, 'streaming response came too quickly']
+ else
+ [ret, 'response time ok']
+ end
+ end
+
+ # expect each response piece to arrive to the body right away
+ # and wait for timeout until next one arrives
+ def timed_streaming_test(endpoint, timeout)
+ ret = []
+ timing = 'response times ok'
+ start = Time.now
+ Excon.get(endpoint, :response_block => lambda do |c,r,t|
+ # add the response
+ ret.push(c)
+ # check if the timing is ok
+ # each response arrives after timeout and before timeout + 1
+ cur_time = Time.now - start
+ if cur_time < ret.length * timeout or cur_time > (ret.length+1) * timeout
+ timing = 'response time not ok!'
+ end
+ end)
+ # validate the final timing
+ if Time.now - start <= timeout*3
+ timing = 'final timing was not ok!'
+ end
+ [ret, timing]
+ end
+
+ tests('simple request with response_block on streaming endpoint').returns([res,'response times ok']) do
+ timed_streaming_test('http://127.0.0.1:9292/streamed/simple', timeout)
+ end
+
+ tests('simple request with response_block on streaming endpoint with fixed length').returns([res,'response times ok']) do
+ timed_streaming_test('http://127.0.0.1:9292/streamed/fixed_length', timeout)
+ end
+
+ end
+end
+
+Shindo.tests('Excon basics (Basic Auth Pass)') do
+ with_rackup('basic_auth.ru') do
+ basic_tests('http://test_user:test_password@127.0.0.1:9292')
+ user, pass, uri = ['test_user', 'test_password', 'http://127.0.0.1:9292'].map(&:freeze)
+
+ tests('with frozen args').returns(200) do
+ connection = Excon.new(uri, :method => :get, :password => pass, :path => '/content-length/100', :user => user)
+ response = connection.request
+ response.status
+ end
+
+ tests('with user/pass on request').returns(200) do
+ connection = Excon.new(uri, :method => :get, :path => '/content-length/100')
+ response = connection.request(:user => user, :password => pass)
+ response.status
+ end
+
+ tests('with user/pass on connection and request').returns(200) do
+ connection = Excon.new(uri, :method => :get, :password => 'incorrect_password', :path => '/content-length/100', :user => 'incorrect_user')
+ response = connection.request(user: user, password: pass)
+ response.status
+ end
+ end
+end
+
+Shindo.tests('Excon basics (Basic Auth Fail)') do
+ with_rackup('basic_auth.ru') do
+ cases = [
+ ['correct user, no password', 'http://test_user@127.0.0.1:9292'],
+ ['correct user, wrong password', 'http://test_user:fake_password@127.0.0.1:9292'],
+ ['wrong user, correct password', 'http://fake_user:test_password@127.0.0.1:9292']
+ ]
+ cases.each do |desc,url|
+ tests("response.status for #{desc}").returns(401) do
+ connection = Excon.new(url)
+ response = connection.request(:method => :get, :path => '/content-length/100')
+ response.status
+ end
+ end
+ end
+end
+
+Shindo.tests('Excon basics (ssl)') do
+ with_rackup('ssl.ru') do
+ basic_tests('https://127.0.0.1:9443')
+ end
+end
+
+Shindo.tests('Excon ssl verify peer (ssl)') do
+ with_rackup('ssl.ru') do
+ connection = nil
+ test do
+ ssl_ca_file = File.join(File.dirname(__FILE__), 'data', '127.0.0.1.cert.crt')
+ connection = Excon.new('https://127.0.0.1:9443', :ssl_verify_peer => true, :ssl_ca_file => ssl_ca_file )
+ true
+ end
+
+ tests('response.status').returns(200) do
+ response = connection.request(:method => :get, :path => '/content-length/100')
+
+ response.status
+ end
+ end
+
+ with_rackup('ssl_mismatched_cn.ru') do
+ connection = nil
+ test do
+ ssl_ca_file = File.join(File.dirname(__FILE__), 'data', 'excon.cert.crt')
+ connection = Excon.new('https://127.0.0.1:9443', :ssl_verify_peer => true, :ssl_ca_file => ssl_ca_file, :ssl_verify_peer_host => 'Excon' )
+ true
+ end
+
+ tests('response.status').returns(200) do
+ response = connection.request(:method => :get, :path => '/content-length/100')
+
+ response.status
+ end
+ end
+end
+
+Shindo.tests('Excon ssl verify peer (ssl cert store)') do
+ with_rackup('ssl.ru') do
+ connection = nil
+ test do
+ ssl_ca_cert = File.read(File.join(File.dirname(__FILE__), 'data', '127.0.0.1.cert.crt'))
+ ssl_cert_store = OpenSSL::X509::Store.new
+ ssl_cert_store.add_cert OpenSSL::X509::Certificate.new ssl_ca_cert
+ connection = Excon.new('https://127.0.0.1:9443', :ssl_verify_peer => true, :ssl_cert_store => ssl_cert_store )
+ true
+ end
+
+ tests('response.status').returns(200) do
+ response = connection.request(:method => :get, :path => '/content-length/100')
+
+ response.status
+ end
+ end
+end
+
+Shindo.tests('Excon basics (ssl file)',['focus']) do
+ with_rackup('ssl_verify_peer.ru') do
+
+ tests('GET /content-length/100').raises(Excon::Errors::SocketError) do
+ connection = Excon::Connection.new({
+ :host => '127.0.0.1',
+ :hostname => '127.0.0.1',
+ :nonblock => false,
+ :port => 8443,
+ :scheme => 'https',
+ :ssl_verify_peer => false
+ })
+ connection.request(:method => :get, :path => '/content-length/100')
+ end
+
+ cert_key_path = File.join(File.dirname(__FILE__), 'data', 'excon.cert.key')
+ cert_crt_path = File.join(File.dirname(__FILE__), 'data', 'excon.cert.crt')
+ basic_tests('https://127.0.0.1:8443', client_key: cert_key_path, client_cert: cert_crt_path)
+
+ cert_key_data = File.read cert_key_path
+ cert_crt_data = File.read cert_crt_path
+ basic_tests('https://127.0.0.1:8443', client_key_data: cert_key_data, client_cert_data: cert_crt_data)
+ end
+end
+
+Shindo.tests('Excon basics (ssl file paths)',['focus']) do
+ with_rackup('ssl_verify_peer.ru') do
+
+ tests('GET /content-length/100').raises(Excon::Errors::SocketError) do
+ connection = Excon::Connection.new({
+ :host => '127.0.0.1',
+ :hostname => '127.0.0.1',
+ :nonblock => false,
+ :port => 8443,
+ :scheme => 'https',
+ :ssl_verify_peer => false
+ })
+ connection.request(:method => :get, :path => '/content-length/100')
+ end
+
+ basic_tests('https://127.0.0.1:8443',
+ :private_key_path => File.join(File.dirname(__FILE__), 'data', 'excon.cert.key'),
+ :certificate_path => File.join(File.dirname(__FILE__), 'data', 'excon.cert.crt')
+ )
+
+ end
+end
+
+Shindo.tests('Excon basics (ssl string)', ['focus']) do
+ with_rackup('ssl_verify_peer.ru') do
+ basic_tests('https://127.0.0.1:8443',
+ :private_key => File.read(File.join(File.dirname(__FILE__), 'data', 'excon.cert.key')),
+ :certificate => File.read(File.join(File.dirname(__FILE__), 'data', 'excon.cert.crt'))
+ )
+ end
+end
+
+Shindo.tests('Excon basics (Unix socket)') do
+ pending if RUBY_PLATFORM == 'java' # need to find suitable server for jruby
+
+ file_name = '/tmp/unicorn.sock'
+ with_unicorn('basic.ru', 'unix://'+file_name) do
+ basic_tests("unix:/", :socket => file_name)
+
+ tests('explicit uri passed to connection') do
+ tests('GET /content-length/100').returns(200) do
+ connection = Excon::Connection.new({
+ :socket => file_name,
+ :nonblock => false,
+ :scheme => 'unix',
+ :ssl_verify_peer => false
+ })
+ response = connection.request(:method => :get, :path => '/content-length/100')
+ response[:status]
+ end
+ end
+
+ tests('http Host header is empty') do
+ tests('GET /headers').returns("") do
+ connection = Excon::Connection.new({
+ :socket => file_name,
+ :nonblock => false,
+ :scheme => 'unix',
+ :ssl_verify_peer => false
+ })
+ response = connection.request(:method => :get, :path => '/headers')
+ JSON.parse(response.body)['HTTP_HOST']
+ end
+ end
+ end
+end
+
+Shindo.tests('Excon basics (reusable local port)') do
+ class CustomSocket < Socket
+ def initialize
+ super(AF_INET, SOCK_STREAM, 0)
+ setsockopt(SOL_SOCKET, SO_REUSEADDR, true)
+ if defined?(SO_REUSEPORT)
+ setsockopt(SOL_SOCKET, SO_REUSEPORT, true)
+ end
+ end
+
+ def bind(address, port)
+ super(Socket.pack_sockaddr_in(port, address))
+ end
+
+ def connect(address, port)
+ super(Socket.pack_sockaddr_in(port, address))
+ end
+
+ def http_get(path)
+ print "GET /content-length/10 HTTP/1.0\r\n\r\n"
+ read.split("\r\n\r\n", 2)[1]
+ end
+
+ def self.ip_address_list
+ if Socket.respond_to?(:ip_address_list)
+ Socket.ip_address_list.select(&:ipv4?).map(&:ip_address)
+ else
+ `ifconfig`.scan(/inet.*?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/).flatten
+ end
+ end
+
+ def self.find_alternate_ip(ip)
+ ip_address_list.detect {|a| a != ip } || '127.0.0.1'
+ end
+ end
+
+ with_rackup('basic.ru', '0.0.0.0') do
+ connection = Excon.new("http://127.0.0.1:9292/echo",
+ :reuseaddr => true, # enable address and port reuse
+ :persistent => true # keep the socket open
+ )
+ response = connection.get
+
+ tests('has a local port').returns(true) do
+ response.local_port.to_s =~ /\d{4,5}/ ? true : false
+ end
+
+ tests('local port can be re-bound').returns('x' * 10) do
+ # create a socket with address/port reuse enabled
+ s = CustomSocket.new
+
+ # bind to the same local port and address used in the get above (won't work without reuse options on both sockets)
+ s.bind(response.local_address, response.local_port)
+
+ # connect to the server on a different address than was used for the initial connection to avoid duplicate 5-tuples of: {protcol, src_port, src_addr, dst_port, dst_addr}
+ s.connect(CustomSocket.find_alternate_ip(response.local_address), 9292)
+
+ # send the request
+ body = s.http_get("/content-length/10")
+
+ # close both the sockets
+ s.close
+ connection.reset
+
+ body
+ end
+ end
+end
diff --git a/lib/vendor/excon/tests/complete_responses.rb b/lib/vendor/excon/tests/complete_responses.rb
new file mode 100644
index 0000000..1dc79f7
--- /dev/null
+++ b/lib/vendor/excon/tests/complete_responses.rb
@@ -0,0 +1,31 @@
+Shindo.tests('Excon Response Validation') do
+ env_init
+
+ with_server('good') do
+ tests('good responses with complete headers') do
+ 100.times do
+ res = Excon.get('http://127.0.0.1:9292/chunked/simple')
+ returns(true) { res.body == "hello world" }
+ returns(true) { res.status_line == "HTTP/1.1 200 OK\r\n" }
+ returns(true) { res.status == 200}
+ returns(true) { res.reason_phrase == "OK" }
+ returns(true) { res.remote_ip == "127.0.0.1" }
+ end
+ end
+ end
+
+ with_server('error') do
+ tests('error responses with complete headers') do
+ 100.times do
+ res = Excon.get('http://127.0.0.1:9292/error/not_found')
+ returns(true) { res.body == "server says not found" }
+ returns(true) { res.status_line == "HTTP/1.1 404 Not Found\r\n" }
+ returns(true) { res.status == 404}
+ returns(true) { res.reason_phrase == "Not Found" }
+ returns(true) { res.remote_ip == "127.0.0.1" }
+ end
+ end
+ end
+
+ env_restore
+end
diff --git a/lib/vendor/excon/tests/data/127.0.0.1.cert.crt b/lib/vendor/excon/tests/data/127.0.0.1.cert.crt
new file mode 100644
index 0000000..b2684a9
--- /dev/null
+++ b/lib/vendor/excon/tests/data/127.0.0.1.cert.crt
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICEzCCAXwCCQC94mWSE0+JcjANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzELMAkGA1UECBMCQ0ExDjAMBgNVBAoTBUV4Y29uMQ4wDAYDVQQLEwVFeGNvbjES
+MBAGA1UEAxMJMTI3LjAuMC4xMB4XDTE0MTAyODIwMjMzMVoXDTE5MTAyNzIwMjMz
+MVowTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQ4wDAYDVQQKEwVFeGNvbjEO
+MAwGA1UECxMFRXhjb24xEjAQBgNVBAMTCTEyNy4wLjAuMTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAvqlKlQMoS4q9jgsm+sBh7B9jEJVYHqNBluqgLubMEmjs
+xFZUIicx+LmMPfUdnqtGDihR7q3yh/xeJuzzux38FBwTBDl8NRXWSyRkJqdi9XUA
+qihAlkqDoZ6Eb867isF7C5FEqohAuCE0FUaYU1HY3bV/foLqxEbyvQVwaRZ4rjkC
+AwEAATANBgkqhkiG9w0BAQUFAAOBgQCRxnrtbFJrBT4duYtOVuG/j8G46bf1DPrF
+wuRf38gdO2Ldu+kdNRMhQrgSA9CfkjwwQpcVK2gZTuGTdmtqTnvIKilsomtG3tFK
+ThWxuW6HrU9XgZ5KXIguVnL5tjYBNslsCFiQUeU/b8GF2MyMkOGUIC0p411ZB9v/
+mTKRgzf/qQ==
+-----END CERTIFICATE-----
diff --git a/lib/vendor/excon/tests/data/127.0.0.1.cert.key b/lib/vendor/excon/tests/data/127.0.0.1.cert.key
new file mode 100644
index 0000000..9e8a2c9
--- /dev/null
+++ b/lib/vendor/excon/tests/data/127.0.0.1.cert.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQC+qUqVAyhLir2OCyb6wGHsH2MQlVgeo0GW6qAu5swSaOzEVlQi
+JzH4uYw99R2eq0YOKFHurfKH/F4m7PO7HfwUHBMEOXw1FdZLJGQmp2L1dQCqKECW
+SoOhnoRvzruKwXsLkUSqiEC4ITQVRphTUdjdtX9+gurERvK9BXBpFniuOQIDAQAB
+AoGAEwJB41VrQQzWFUFbY4imuqnucIrTPEq+kVNXIRX1pqg7Yt/Qh48s1kV5i/vS
+Ni2RUHwInylMku5AXNUm/7LfnN1zCHiYVkddL6df73BdzKfM86j+eQJdqye3AOkZ
+GKrutsE8AEwOBCPtM9z3EbbAQZQpBBGyvAH3z8/GFLa34LkCQQDwEhEJleUGxiSR
+anm43iFWsNBqW680YSz3kh1O7aC+09u8BOvOJ6azOMBYgxBno0IR9Oe7k0iBl+8e
+YJmAuCVHAkEAy0/wdYeKwv9Dd3y9I+lS11VvaQaY2dmFmhbkPl/AAjUHju5ZF7me
+Znwpq0jLlKRlKatVjkO/mkOeWs1/8MhQfwJBAO5VkVKJ3IjAF7fCFDvjUwfEm/Sr
+NyJyQvk5tx0PrqEkpSZhYFUXaljNQ6/b1mJ9Yu9+yrye+MGnu73Vuy9eIasCQFT4
+fejA0y+X+5xul6Xwl9zDKiLczPkPPhUeSBoBbn/9pcEIwFd4DkmKzud1LxBafKUj
+pEgm7GcOp5oPlM8PCQUCQQCtPFpgobUK9nRewxWagUL+xlEo6C1CPFhTwtQvnyi9
+6UwgxZtOdzAc3xRvHo4uK3OwGuOklqkpIeiZg3hoZb6B
+-----END RSA PRIVATE KEY-----
diff --git a/lib/vendor/excon/tests/data/excon.cert.crt b/lib/vendor/excon/tests/data/excon.cert.crt
new file mode 100644
index 0000000..8218e49
--- /dev/null
+++ b/lib/vendor/excon/tests/data/excon.cert.crt
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICLzCCAZgCCQCidUHPgYe2GTANBgkqhkiG9w0BAQUFADBcMQswCQYDVQQGEwJV
+UzELMAkGA1UECBMCQ0ExDjAMBgNVBAoTBUV4Y29uMQ4wDAYDVQQDEwVFeGNvbjEg
+MB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20wHhcNMTMwMjI4MTczOTE4
+WhcNMTYxMTI0MTczOTE4WjBcMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExDjAM
+BgNVBAoTBUV4Y29uMQ4wDAYDVQQDEwVFeGNvbjEgMB4GCSqGSIb3DQEJARYRYWRt
+aW5AZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKM+fgjX
+QfkMpepEWQBO7pJLQgoYY0EntYSgmFF/9E+fcokCWAHtmF5SBtpbWJRz3BcZ/bfq
+zYYlbTAWu3nsXwsp/6Fn4dv1jvUAreAH3QV4nm8kU8FcoQ8O085UruEHIDTpZec2
+hBLTcU7dDbxAdMJLZSpkxi75I8iB9+PKGYfRAgMBAAEwDQYJKoZIhvcNAQEFBQAD
+gYEAMJvD5vR3k3EkWodu318aQEgQWpy+KONsqVuL48qYevbNiEnc91Gao9i7bu66
+LIJFcJ/OKLvPuIOXY5KDaCo8zo/RYD2uFJK4uauQVUltfnz9CM3bMxIZpChAipNW
+Crnwin6S9W9SGjJ8PY4kwRv7T9NBOsjP7YG3Zpb1YSETKug=
+-----END CERTIFICATE-----
diff --git a/lib/vendor/excon/tests/data/excon.cert.key b/lib/vendor/excon/tests/data/excon.cert.key
new file mode 100644
index 0000000..c28c0a0
--- /dev/null
+++ b/lib/vendor/excon/tests/data/excon.cert.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQCjPn4I10H5DKXqRFkATu6SS0IKGGNBJ7WEoJhRf/RPn3KJAlgB
+7ZheUgbaW1iUc9wXGf236s2GJW0wFrt57F8LKf+hZ+Hb9Y71AK3gB90FeJ5vJFPB
+XKEPDtPOVK7hByA06WXnNoQS03FO3Q28QHTCS2UqZMYu+SPIgffjyhmH0QIDAQAB
+AoGACOChIgHyyIRzkWXeITIprzMAiGQDIcvzBx9kqSn4M0xMgj7qYlB1dMupK77D
+9m7GjUsQjSvruVvXsEHMODkugeqo/3pZWMj+WnXBtc+30Jfi1kzkTjk/dL0jG0hq
+rrb+10dS/jfhlUptgzG3tnDHOS1AqEhwH3zXSqn/AoNy5DECQQDV1f+1pGhLTf66
+6u9IJc6MZz5zw2avdk9O6qo6et+gmtq1FIpvw7S3zP8M0uOq0+g88PHQSgBeJ8BZ
+9YUWdH9XAkEAw264uoNVCpEpscfbGPRkDZXZE8nhmqhzkWBZAMcsqjdTcMdW0tVB
+8zdNSGg7GWM5svSKrJcx++Xxpyu1AftBFwJABvF77Bn6iPdvXgJi4qTXoBd6H6go
+nWnqCVX1URDMUhq1H0wbcqWYKJ+vaGswmUtoLxJjx6+fc282/7TJLYF64QJBAIbQ
+ZVw8ZriwZLu/61Mum6qHeUTeWePPWlGpzhvsSdJt8gB1cl5kQGdf+c7+H+6mdVIO
+wW7HqfJjsCyqyOXCBicCQQDS8aqD1iSfOi7J8DNrX1LnGudqdn+I7YITeQWZd07a
+uEiTDzuaxaDtvUrN+jS0I9K1Vnn2UQCwqhvFaARHzgVB
+-----END RSA PRIVATE KEY-----
diff --git a/lib/vendor/excon/tests/data/xs b/lib/vendor/excon/tests/data/xs
new file mode 100644
index 0000000..762ca2a
--- /dev/null
+++ b/lib/vendor/excon/tests/data/xs
@@ -0,0 +1 @@
+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
diff --git a/lib/vendor/excon/tests/error_tests.rb b/lib/vendor/excon/tests/error_tests.rb
new file mode 100644
index 0000000..c1bf15f
--- /dev/null
+++ b/lib/vendor/excon/tests/error_tests.rb
@@ -0,0 +1,145 @@
+
+
+Shindo.tests('HTTPStatusError request/response debugging') do
+
+ # Regression against e300458f2d9330cb265baeb8973120d08c665d9
+ tests('Excon::Error knows about pertinent errors') do
+ expected = [
+ 100,
+ 101,
+ (200..206).to_a,
+ (300..307).to_a,
+ (400..417).to_a,
+ 422,
+ 429,
+ (500..504).to_a
+ ]
+ expected.flatten == Excon::Error.status_errors.keys
+ end
+
+ tests('new returns an Error').returns(true) do
+ Excon::Error.new('bar').class == Excon::Error
+ end
+
+ tests('new raises errors for bad URIs').returns(true) do
+ begin
+ Excon.new('foo')
+ false
+ rescue => err
+ err.to_s.include? 'foo'
+ end
+ end
+
+ tests('new raises errors for bad paths').returns(true) do
+ begin
+ Excon.new('http://localhost', path: "foo\r\nbar: baz")
+ false
+ rescue => err
+ err.to_s.include? "foo\r\nbar: baz"
+ end
+ end
+
+ tests('can raise standard error and catch standard error').returns(true) do
+ begin
+ raise Excon::Error::Client.new('foo')
+ rescue Excon::Error => e
+ true
+ end
+ end
+
+ tests('can raise legacy errors and catch legacy errors').returns(true) do
+ begin
+ raise Excon::Errors::Error.new('bar')
+ rescue Excon::Errors::Error => e
+ true
+ end
+ end
+
+ tests('can raise standard error and catch legacy errors').returns(true) do
+ begin
+ raise Excon::Error::NotFound.new('bar')
+ rescue Excon::Errors::Error => e
+ true
+ end
+ end
+
+ tests('can raise with status_error() and catch with standard error').returns(true) do
+ begin
+ raise Excon::Error.status_error({expects: 200}, {status: 400})
+ rescue Excon::Error
+ true
+ end
+ end
+
+
+ tests('can raise with status_error() and catch with legacy error').returns(true) do
+ begin
+ raise Excon::Error.status_error({expects: 200}, {status: 400})
+ rescue Excon::Errors::BadRequest
+ true
+ end
+ end
+
+ tests('can raise with legacy status_error() and catch with legacy').returns(true) do
+ begin
+ raise Excon::Errors.status_error({expects: 200}, {status: 400})
+ rescue Excon::Errors::BadRequest
+ true
+ end
+ end
+
+
+ tests('can raise with legacy status_error() and catch with standard').returns(true) do
+ begin
+ raise Excon::Errors.status_error({expects: 200}, {status: 400})
+ rescue Excon::Error
+ true
+ end
+ end
+
+ with_server('error') do
+
+ tests('message does not include response or response info').returns(true) do
+ begin
+ Excon.get('http://127.0.0.1:9292/error/not_found', :expects => 200)
+ rescue Excon::Errors::HTTPStatusError => err
+ err.message.include?('Expected(200) <=> Actual(404 Not Found)') &&
+ !err.message.include?('excon.error.request') &&
+ !err.message.include?('excon.error.response')
+ end
+ end
+
+ tests('message includes only request info').returns(true) do
+ begin
+ Excon.get('http://127.0.0.1:9292/error/not_found', :expects => 200,
+ :debug_request => true)
+ rescue Excon::Errors::HTTPStatusError => err
+ err.message.include?('Expected(200) <=> Actual(404 Not Found)') &&
+ err.message.include?('excon.error.request') &&
+ !err.message.include?('excon.error.response')
+ end
+ end
+
+ tests('message includes only response info').returns(true) do
+ begin
+ Excon.get('http://127.0.0.1:9292/error/not_found', :expects => 200,
+ :debug_response => true)
+ rescue Excon::Errors::HTTPStatusError => err
+ err.message.include?('Expected(200) <=> Actual(404 Not Found)') &&
+ !err.message.include?('excon.error.request') &&
+ err.message.include?('excon.error.response')
+ end
+ end
+
+ tests('message include request and response info').returns(true) do
+ begin
+ Excon.get('http://127.0.0.1:9292/error/not_found', :expects => 200,
+ :debug_request => true, :debug_response => true)
+ rescue Excon::Errors::HTTPStatusError => err
+ err.message.include?('Expected(200) <=> Actual(404 Not Found)') &&
+ err.message.include?('excon.error.request') &&
+ err.message.include?('excon.error.response')
+ end
+ end
+ end
+end
diff --git a/lib/vendor/excon/tests/header_tests.rb b/lib/vendor/excon/tests/header_tests.rb
new file mode 100644
index 0000000..a779b05
--- /dev/null
+++ b/lib/vendor/excon/tests/header_tests.rb
@@ -0,0 +1,119 @@
+Shindo.tests('Excon response header support') do
+ env_init
+
+ tests('Excon::Headers storage') do
+ headers = Excon::Headers.new
+ headers['Exact-Case'] = 'expected'
+ headers['Another-Fixture'] = 'another'
+
+ tests('stores and retrieves as received').returns('expected') do
+ headers['Exact-Case']
+ end
+
+ tests('enumerates keys as received') do
+ ks = headers.keys
+ tests('contains Exact-Case').returns(true) { ks.include? 'Exact-Case' }
+ tests('contains Another-Fixture').returns(true) { ks.include? 'Another-Fixture' }
+ end
+
+ tests('supports case-insensitive access').returns('expected') do
+ headers['EXACT-CASE']
+ end
+
+ tests('but still returns nil for missing keys').returns(nil) do
+ headers['Missing-Header']
+ end
+
+ tests('Hash methods that should support case-insensitive access') do
+ if {}.respond_to? :assoc
+ tests('#assoc').returns(%w{exact-case expected}) do
+ headers.assoc('exact-Case')
+ end
+ end
+
+ tests('#delete') do
+ tests('with just a key').returns('yes') do
+ headers['Extra'] = 'yes'
+ headers.delete('extra')
+ end
+
+ tests('with a proc').returns('called with notpresent') do
+ headers.delete('notpresent') { |k| "called with #{k}" }
+ end
+ end
+
+ tests('#fetch') do
+ tests('when present').returns('expected') { headers.fetch('exact-CASE') }
+ tests('with a default value').returns('default') { headers.fetch('missing', 'default') }
+ tests('with a default proc').returns('got missing') do
+ headers.fetch('missing') { |k| "got #{k}" }
+ end
+ end
+
+ tests('#has_key?') do
+ tests('when present').returns(true) { headers.has_key?('EXACT-case') }
+ tests('when absent').returns(false) { headers.has_key?('missing') }
+ end
+
+ tests('#values_at') do
+ tests('all present').returns(%w{expected another}) do
+ headers.values_at('exACT-cASE', 'anotheR-fixturE')
+ end
+ tests('some missing').returns(['expected', nil]) do
+ headers.values_at('exact-case', 'missing-header')
+ end
+ end
+ end
+ end
+
+ with_rackup('response_header.ru') do
+
+ tests('Response#get_header') do
+ connection = nil
+ response = nil
+
+ tests('with variable header capitalization') do
+
+ tests('response.get_header("mixedcase-header")').returns('MixedCase') do
+ connection = Excon.new('http://foo.com:8080', :proxy => 'http://127.0.0.1:9292')
+ response = connection.request(:method => :get, :path => '/foo')
+
+ response.get_header("mixedcase-header")
+ end
+
+ tests('response.get_header("uppercase-header")').returns('UPPERCASE') do
+ response.get_header("uppercase-header")
+ end
+
+ tests('response.get_header("lowercase-header")').returns('lowercase') do
+ response.get_header("lowercase-header")
+ end
+
+ end
+
+ tests('when provided key capitalization varies') do
+
+ tests('response.get_header("MIXEDCASE-HEADER")').returns('MixedCase') do
+ response.get_header("MIXEDCASE-HEADER")
+ end
+
+ tests('response.get_header("MiXeDcAsE-hEaDeR")').returns('MixedCase') do
+ response.get_header("MiXeDcAsE-hEaDeR")
+ end
+
+ end
+
+ tests('when header is unavailable') do
+
+ tests('response.get_header("missing")').returns(nil) do
+ response.get_header("missing")
+ end
+
+ end
+
+ end
+
+ end
+
+ env_restore
+end
diff --git a/lib/vendor/excon/tests/middlewares/canned_response_tests.rb b/lib/vendor/excon/tests/middlewares/canned_response_tests.rb
new file mode 100644
index 0000000..e4a70c1
--- /dev/null
+++ b/lib/vendor/excon/tests/middlewares/canned_response_tests.rb
@@ -0,0 +1,34 @@
+Shindo.tests("Excon support for middlewares that return canned responses") do
+ the_body = "canned"
+
+ canned_response_middleware = Class.new(Excon::Middleware::Base) do
+ define_method :request_call do |params|
+ params[:response] = {
+ :body => the_body,
+ :headers => {},
+ :status => 200
+ }
+ super(params)
+ end
+ end
+
+ tests('does not mutate the canned response body').returns(the_body) do
+ Excon.get(
+ 'http://some-host.com/some-path',
+ :middlewares => [canned_response_middleware] + Excon.defaults[:middlewares]
+ ).body
+ end
+
+ tests('yields non-mutated body to response_block').returns(the_body) do
+ body = ''
+ response_block = lambda { |chunk, _, _| body << chunk }
+ Excon.get(
+ 'http://some-host.com/some-path',
+ :middlewares => [canned_response_middleware] + Excon.defaults[:middlewares],
+ :response_block => response_block
+ )
+ body
+ end
+
+end
+
diff --git a/lib/vendor/excon/tests/middlewares/capture_cookies_tests.rb b/lib/vendor/excon/tests/middlewares/capture_cookies_tests.rb
new file mode 100644
index 0000000..0e681ce
--- /dev/null
+++ b/lib/vendor/excon/tests/middlewares/capture_cookies_tests.rb
@@ -0,0 +1,34 @@
+Shindo.tests("Excon redirecting with cookie preserved") do
+ env_init
+
+ with_rackup('redirecting_with_cookie.ru') do
+ tests('second request will send cookies set by the first').returns('ok') do
+ Excon.get(
+ 'http://127.0.0.1:9292',
+ :path => '/sets_cookie',
+ :middlewares => Excon.defaults[:middlewares] + [Excon::Middleware::CaptureCookies, Excon::Middleware::RedirectFollower]
+ ).body
+ end
+
+ tests('second request will send multiple cookies set by the first').returns('ok') do
+ Excon.get(
+ 'http://127.0.0.1:9292',
+ :path => '/sets_multi_cookie',
+ :middlewares => Excon.defaults[:middlewares] + [Excon::Middleware::CaptureCookies, Excon::Middleware::RedirectFollower]
+ ).body
+ end
+ end
+
+ with_rackup('redirecting.ru') do
+ tests("runs normally when there are no cookies set").returns('ok') do
+ Excon.post(
+ 'http://127.0.0.1:9292',
+ :path => '/first',
+ :middlewares => Excon.defaults[:middlewares] + [Excon::Middleware::CaptureCookies, Excon::Middleware::RedirectFollower],
+ :body => "a=Some_content"
+ ).body
+ end
+ end
+
+ env_restore
+end
diff --git a/lib/vendor/excon/tests/middlewares/decompress_tests.rb b/lib/vendor/excon/tests/middlewares/decompress_tests.rb
new file mode 100644
index 0000000..aebba34
--- /dev/null
+++ b/lib/vendor/excon/tests/middlewares/decompress_tests.rb
@@ -0,0 +1,157 @@
+Shindo.tests('Excon Decompress Middleware') do
+ env_init
+
+ with_server('good') do
+
+ before do
+ @connection ||= Excon.new(
+ 'http://127.0.0.1:9292/echo/content-encoded',
+ :method => :post,
+ :body => 'hello world',
+ :middlewares => Excon.defaults[:middlewares] + [Excon::Middleware::Decompress]
+ )
+ end
+
+ tests('gzip') do
+ resp = nil
+
+ tests('response body decompressed').returns('hello world') do
+ resp = @connection.request(
+ :headers => { 'Accept-Encoding' => 'gzip, deflate;q=0' }
+ )
+ resp[:body]
+ end
+
+ tests('server sent content-encoding').returns('gzip') do
+ resp[:headers]['Content-Encoding-Sent']
+ end
+
+ tests('removes processed encoding from header').returns('') do
+ resp[:headers]['Content-Encoding']
+ end
+
+ tests('empty response body').returns('') do
+ resp = @connection.request(:body => '')
+ resp[:body]
+ end
+ end
+
+ tests('deflate') do
+ resp = nil
+
+ tests('response body decompressed').returns('hello world') do
+ resp = @connection.request(
+ :headers => { 'Accept-Encoding' => 'gzip;q=0, deflate' }
+ )
+ resp[:body]
+ end
+
+ tests('server sent content-encoding').returns('deflate') do
+ resp[:headers]['Content-Encoding-Sent']
+ end
+
+ tests('removes processed encoding from header').returns('') do
+ resp[:headers]['Content-Encoding']
+ end
+ end
+
+ tests('with pre-encoding') do
+ resp = nil
+
+ tests('server sent content-encoding').returns('other, gzip') do
+ resp = @connection.request(
+ :headers => { 'Accept-Encoding' => 'gzip, deflate;q=0',
+ 'Content-Encoding-Pre' => 'other' }
+ )
+ resp[:headers]['Content-Encoding-Sent']
+ end
+
+ tests('processed encoding removed from header').returns('other') do
+ resp[:headers]['Content-Encoding']
+ end
+
+ tests('response body decompressed').returns('hello world') do
+ resp[:body]
+ end
+
+ end
+
+ tests('with post-encoding') do
+ resp = nil
+
+ tests('server sent content-encoding').returns('gzip, other') do
+ resp = @connection.request(
+ :headers => { 'Accept-Encoding' => 'gzip, deflate;q=0',
+ 'Content-Encoding-Post' => 'other' }
+ )
+ resp[:headers]['Content-Encoding-Sent']
+ end
+
+ tests('unprocessed since last applied is unknown').returns('gzip, other') do
+ resp[:headers]['Content-Encoding']
+ end
+
+ tests('response body still compressed').returns('hello world') do
+ Zlib::GzipReader.new(StringIO.new(resp[:body])).read
+ end
+
+ end
+
+ tests('with a :response_block') do
+ captures = nil
+ resp = nil
+
+ tests('server sent content-encoding').returns('gzip') do
+ captures = capture_response_block do |block|
+ resp = @connection.request(
+ :headers => { 'Accept-Encoding' => 'gzip'},
+ :response_block => block
+ )
+ end
+ resp[:headers]['Content-Encoding-Sent']
+ end
+
+ tests('unprocessed since :response_block was used').returns('gzip') do
+ resp[:headers]['Content-Encoding']
+ end
+
+ tests(':response_block passed unprocessed data').returns('hello world') do
+ body = captures.map {|capture| capture[0] }.join
+ Zlib::GzipReader.new(StringIO.new(body)).read
+ end
+
+ end
+
+ tests('adds Accept-Encoding if needed') do
+
+ tests('without a :response_block').returns('deflate, gzip') do
+ resp = Excon.post(
+ 'http://127.0.0.1:9292/echo/request',
+ :body => 'hello world',
+ :middlewares => Excon.defaults[:middlewares] +
+ [Excon::Middleware::Decompress]
+ )
+ request = Marshal.load(resp.body)
+ request[:headers]['Accept-Encoding']
+ end
+
+ tests('with a :response_block').returns(nil) do
+ captures = capture_response_block do |block|
+ Excon.post(
+ 'http://127.0.0.1:9292/echo/request',
+ :body => 'hello world',
+ :response_block => block,
+ :middlewares => Excon.defaults[:middlewares] +
+ [Excon::Middleware::Decompress]
+ )
+ end
+ request = Marshal.load(captures.map {|capture| capture[0] }.join)
+ request[:headers]['Accept-Encoding']
+ end
+
+ end
+
+ end
+
+ env_restore
+end
diff --git a/lib/vendor/excon/tests/middlewares/escape_path_tests.rb b/lib/vendor/excon/tests/middlewares/escape_path_tests.rb
new file mode 100644
index 0000000..f354a0f
--- /dev/null
+++ b/lib/vendor/excon/tests/middlewares/escape_path_tests.rb
@@ -0,0 +1,36 @@
+Shindo.tests('Excon Decompress Middleware') do
+ env_init
+ with_rackup('basic.ru') do
+ tests('encoded uri passed to connection') do
+ tests('GET /echo%20dirty').returns(200) do
+ connection = Excon::Connection.new({
+ :host => '127.0.0.1',
+ :hostname => '127.0.0.1',
+ :middlewares => Excon.defaults[:middlewares] + [Excon::Middleware::EscapePath],
+ :nonblock => false,
+ :port => 9292,
+ :scheme => 'http',
+ :ssl_verify_peer => false
+ })
+ response = connection.request(:method => :get, :path => '/echo%20dirty')
+ response[:status]
+ end
+ end
+
+ tests('unencoded uri passed to connection') do
+ tests('GET /echo dirty').returns(200) do
+ connection = Excon::Connection.new({
+ :host => '127.0.0.1',
+ :hostname => '127.0.0.1',
+ :middlewares => Excon.defaults[:middlewares] + [Excon::Middleware::EscapePath],
+ :nonblock => false,
+ :port => 9292,
+ :scheme => 'http',
+ :ssl_verify_peer => false
+ })
+ response = connection.request(:method => :get, :path => '/echo dirty')
+ response[:status]
+ end
+ end
+ end
+end
diff --git a/lib/vendor/excon/tests/middlewares/idempotent_tests.rb b/lib/vendor/excon/tests/middlewares/idempotent_tests.rb
new file mode 100644
index 0000000..4c58bce
--- /dev/null
+++ b/lib/vendor/excon/tests/middlewares/idempotent_tests.rb
@@ -0,0 +1,131 @@
+Shindo.tests('Excon request idempotencey') do
+
+ before do
+ @connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ end
+
+ after do
+ # flush any existing stubs after each test
+ Excon.stubs.clear
+ end
+
+ tests("Non-idempotent call with an erroring socket").raises(Excon::Errors::SocketError) do
+ run_count = 0
+ Excon.stub({:method => :get}) { |params|
+ run_count += 1
+ if run_count <= 3 # First 3 calls fail.
+ raise Excon::Errors::SocketError.new(Exception.new "Mock Error")
+ else
+ {:body => params[:body], :headers => params[:headers], :status => 200}
+ end
+ }
+
+ @connection.request(:method => :get, :path => '/some-path')
+ end
+
+ tests("Idempotent request with socket erroring first 3 times").returns(200) do
+ run_count = 0
+ Excon.stub({:method => :get}) { |params|
+ run_count += 1
+ if run_count <= 3 # First 3 calls fail.
+ raise Excon::Errors::SocketError.new(Exception.new "Mock Error")
+ else
+ {:body => params[:body], :headers => params[:headers], :status => 200}
+ end
+ }
+
+ response = @connection.request(:method => :get, :idempotent => true, :path => '/some-path')
+ response.status
+ end
+
+ tests("Idempotent request with socket erroring first 5 times").raises(Excon::Errors::SocketError) do
+ run_count = 0
+ Excon.stub({:method => :get}) { |params|
+ run_count += 1
+ if run_count <= 5 # First 5 calls fail.
+ raise Excon::Errors::SocketError.new(Exception.new "Mock Error")
+ else
+ {:body => params[:body], :headers => params[:headers], :status => 200}
+ end
+ }
+
+ response = @connection.request(:method => :get, :idempotent => true, :path => '/some-path')
+ response.status
+ end
+
+ tests("Lowered retry limit with socket erroring first time").returns(200) do
+ run_count = 0
+ Excon.stub({:method => :get}) { |params|
+ run_count += 1
+ if run_count <= 1 # First call fails.
+ raise Excon::Errors::SocketError.new(Exception.new "Mock Error")
+ else
+ {:body => params[:body], :headers => params[:headers], :status => 200}
+ end
+ }
+
+ response = @connection.request(:method => :get, :idempotent => true, :path => '/some-path', :retry_limit => 2)
+ response.status
+ end
+
+ tests("Lowered retry limit with socket erroring first 3 times").raises(Excon::Errors::SocketError) do
+ run_count = 0
+ Excon.stub({:method => :get}) { |params|
+ run_count += 1
+ if run_count <= 3 # First 3 calls fail.
+ raise Excon::Errors::SocketError.new(Exception.new "Mock Error")
+ else
+ {:body => params[:body], :headers => params[:headers], :status => 200}
+ end
+ }
+
+ response = @connection.request(:method => :get, :idempotent => true, :path => '/some-path', :retry_limit => 2)
+ response.status
+ end
+
+ tests("Raised retry limit with socket erroring first 5 times").returns(200) do
+ run_count = 0
+ Excon.stub({:method => :get}) { |params|
+ run_count += 1
+ if run_count <= 5 # First 5 calls fail.
+ raise Excon::Errors::SocketError.new(Exception.new "Mock Error")
+ else
+ {:body => params[:body], :headers => params[:headers], :status => 200}
+ end
+ }
+
+ response = @connection.request(:method => :get, :idempotent => true, :path => '/some-path', :retry_limit => 8)
+ response.status
+ end
+
+ tests("Raised retry limit with socket erroring first 9 times").raises(Excon::Errors::SocketError) do
+ run_count = 0
+ Excon.stub({:method => :get}) { |params|
+ run_count += 1
+ if run_count <= 9 # First 9 calls fail.
+ raise Excon::Errors::SocketError.new(Exception.new "Mock Error")
+ else
+ {:body => params[:body], :headers => params[:headers], :status => 200}
+ end
+ }
+
+ response = @connection.request(:method => :get, :idempotent => true, :path => '/some-path', :retry_limit => 8)
+ response.status
+ end
+
+ tests("Retry limit in constructor with socket erroring first 5 times").returns(200) do
+ run_count = 0
+ Excon.stub({:method => :get}) { |params|
+ run_count += 1
+ if run_count <= 5 # First 5 calls fail.
+ raise Excon::Errors::SocketError.new(Exception.new "Mock Error")
+ else
+ {:body => params[:body], :headers => params[:headers], :status => 200}
+ end
+ }
+
+ response = @connection.request(:method => :get, :idempotent => true, :path => '/some-path', :retry_limit => 6)
+ response.status
+ end
+
+end
diff --git a/lib/vendor/excon/tests/middlewares/instrumentation_tests.rb b/lib/vendor/excon/tests/middlewares/instrumentation_tests.rb
new file mode 100644
index 0000000..cc2f57d
--- /dev/null
+++ b/lib/vendor/excon/tests/middlewares/instrumentation_tests.rb
@@ -0,0 +1,315 @@
+require 'active_support/notifications'
+require 'securerandom'
+
+class SimpleInstrumentor
+ class << self
+ attr_accessor :events, :blocks
+
+ def instrument(name, params = {}, &block)
+ @events << name
+ @blocks << name if block_given?
+
+ yield if block_given?
+ end
+
+ def reset!
+ @events = []
+ @blocks = []
+ end
+ end
+end
+
+Shindo.tests('Excon instrumentation') do
+
+ after do
+ ActiveSupport::Notifications.unsubscribe("excon")
+ ActiveSupport::Notifications.unsubscribe("excon.request")
+ ActiveSupport::Notifications.unsubscribe("excon.response")
+ ActiveSupport::Notifications.unsubscribe("excon.retry")
+ ActiveSupport::Notifications.unsubscribe("excon.error")
+ ActiveSupport::Notifications.unsubscribe("gug")
+ Delorean.back_to_the_present
+ Excon.stubs.clear
+ end
+
+ before do
+ SimpleInstrumentor.reset!
+ end
+
+ def subscribe(match)
+ @events = []
+ ActiveSupport::Notifications.subscribe(match) do |*args|
+ @events << ActiveSupport::Notifications::Event.new(*args)
+ end
+ end
+
+ def make_request(idempotent = false, params = {})
+ connection = Excon.new(
+ 'http://127.0.0.1:9292',
+ :instrumentor => ActiveSupport::Notifications,
+ :mock => true
+ )
+ if idempotent
+ params[:idempotent] = :true
+ end
+ connection.get(params)
+ end
+
+ REQUEST_DELAY_SECONDS = 30
+ def stub_success
+ Excon.stub({:method => :get}) { |params|
+ Delorean.jump REQUEST_DELAY_SECONDS
+ {:body => params[:body], :headers => params[:headers], :status => 200}
+ }
+ end
+
+ def stub_retries
+ run_count = 0
+ Excon.stub({:method => :get}) { |params|
+ run_count += 1
+ if run_count <= 3 # First 3 calls fail.
+ raise Excon::Errors::SocketError.new(Exception.new "Mock Error")
+ else
+ {:body => params[:body], :headers => params[:headers], :status => 200}
+ end
+ }
+ end
+
+ def stub_failure
+ Excon.stub({:method => :get}) { |params|
+ raise Excon::Errors::SocketError.new(Exception.new "Mock Error")
+ }
+ end
+
+ tests('basic notification').returns(['excon.request', 'excon.response']) do
+ subscribe(/excon/)
+ stub_success
+ make_request
+ @events.map(&:name)
+ end
+
+ tests('captures scheme, host, port, and path').returns([:host, :path, :port, :scheme]) do
+ subscribe(/excon/)
+ stub_success
+ make_request
+ [:host, :path, :port, :scheme].select {|k| @events.first.payload.has_key? k}
+ end
+
+ tests('params in request overwrite those in constructor').returns('/cheezburger') do
+ subscribe(/excon/)
+ stub_success
+ make_request(false, :path => '/cheezburger')
+ @events.first.payload[:path]
+ end
+
+ tests('notify on retry').returns(3) do
+ subscribe(/excon/)
+ stub_retries
+ make_request(true)
+ @events.count{|e| e.name =~ /retry/}
+ end
+
+ tests('notify on error').returns(true) do
+ subscribe(/excon/)
+ stub_failure
+ raises(Excon::Errors::SocketError) do
+ make_request
+ end
+
+ @events.any?{|e| e.name =~ /error/}
+ end
+
+ tests('filtering').returns(['excon.request', 'excon.error']) do
+ subscribe(/excon.request/)
+ subscribe(/excon.error/)
+ stub_failure
+ raises(Excon::Errors::SocketError) do
+ make_request(true)
+ end
+
+ @events.map(&:name)
+ end
+
+ tests('more filtering').returns(['excon.retry', 'excon.retry', 'excon.retry']) do
+ subscribe(/excon.retry/)
+ stub_failure
+ raises(Excon::Errors::SocketError) do
+ make_request(true)
+ end
+
+ @events.map(&:name)
+ end
+
+ tests('indicates duration').returns(true) do
+ subscribe(/excon/)
+ stub_success
+ make_request
+ (@events.first.duration/1000 - REQUEST_DELAY_SECONDS).abs < 1
+ end
+
+ tests('standard instrumentor') do
+
+ tests('success').returns(
+ ['excon.request', 'excon.retry', 'excon.retry', 'excon.retry', 'excon.error']) do
+
+ begin
+ original_stderr = $stderr
+ $stderr = captured_stderr = StringIO.new
+ stub_failure
+ connection = Excon.new(
+ 'http://127.0.0.1:9292',
+ :instrumentor => Excon::StandardInstrumentor,
+ :mock => true
+ )
+ raises(Excon::Errors::SocketError) do
+ connection.get(:idempotent => true)
+ end
+
+ captured_stderr.string.split("\n").reject {|line| line =~ %r{^ }}.map {|event| event.split(' ').first}
+ ensure
+ $stderr = original_stderr
+ end
+ end
+
+ tests('authorization header REDACT') do
+
+ @auth_header = 'Basic dXNlcjpwYXNz'
+
+ begin
+ original_stderr = $stderr
+ $stderr = @captured_stderr = StringIO.new
+ stub_failure
+ raises(Excon::Errors::SocketError) do
+ @connection = Excon.new(
+ 'http://user:pass@127.0.0.1:9292',
+ :headers => {
+ 'Authorization' => @auth_header
+ },
+ :instrumentor => Excon::StandardInstrumentor,
+ :mock => true
+ )
+ @connection.get(:idempotent => true)
+ end
+ ensure
+ $stderr = original_stderr
+ end
+
+ test('does not appear in response') do
+ !@captured_stderr.string.include?(@auth_header)
+ end
+
+ test('does not mutate Authorization value') do
+ @connection.data[:headers]['Authorization'] == @auth_header
+ end
+
+ end
+
+ tests('password REDACT') do
+
+ begin
+ original_stderr = $stderr
+ $stderr = @captured_stderr = StringIO.new
+ stub_failure
+ raises(Excon::Errors::SocketError) do
+ @connection = Excon.new(
+ 'http://user:pass@127.0.0.1:9292',
+ :instrumentor => Excon::StandardInstrumentor,
+ :mock => true
+ )
+ @connection.get(:idempotent => true)
+ end
+ ensure
+ $stderr = original_stderr
+ end
+
+ @password_param = '"pass"'
+
+ test('does not appear in response') do
+ !@captured_stderr.string.include?(@password_param)
+ end
+
+ test('does not mutate password value') do
+ @connection.data[:password] == "pass"
+ end
+
+ end
+
+ end
+
+ tests('use our own instrumentor').returns(
+ ['excon.request', 'excon.retry', 'excon.retry', 'excon.retry', 'excon.error']) do
+ stub_failure
+ connection = Excon.new(
+ 'http://127.0.0.1:9292',
+ :instrumentor => SimpleInstrumentor,
+ :mock => true
+ )
+ raises(Excon::Errors::SocketError) do
+ connection.get(:idempotent => true)
+ end
+
+ SimpleInstrumentor.events
+ end
+
+ tests('always passes the block').returns(
+ ['excon.request', 'excon.response']) do
+ stub_success
+ connection = Excon.new(
+ 'http://127.0.0.1:9292',
+ :instrumentor => SimpleInstrumentor,
+ :mock => true
+ )
+ connection.get(:idempotent => true)
+
+ SimpleInstrumentor.blocks
+ end
+
+ tests('does not generate events when not provided').returns(0) do
+ subscribe(/excon/)
+ stub_success
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ connection.get(:idempotent => true)
+ @events.count
+ end
+
+ tests('allows setting the prefix').returns(
+ ['gug.request', 'gug.retry', 'gug.retry','gug.retry', 'gug.error']) do
+ subscribe(/gug/)
+ stub_failure
+ connection = Excon.new(
+ 'http://127.0.0.1:9292',
+ :instrumentor => ActiveSupport::Notifications,
+ :instrumentor_name => 'gug',
+ :mock => true
+ )
+ raises(Excon::Errors::SocketError) do
+ connection.get(:idempotent => true)
+ end
+ @events.map(&:name)
+ end
+
+ tests('allows setting the prefix when not idempotent', 'foo').returns(
+ ['gug.request', 'gug.error']) do
+ subscribe(/gug/)
+ stub_failure
+ connection = Excon.new(
+ 'http://127.0.0.1:9292',
+ :instrumentor => ActiveSupport::Notifications,
+ :instrumentor_name => 'gug',
+ :mock => true
+ )
+ raises(Excon::Errors::SocketError) do
+ connection.get()
+ end
+ @events.map(&:name)
+ end
+
+ with_rackup('basic.ru') do
+ tests('works unmocked').returns(['excon.request', 'excon.response']) do
+ subscribe(/excon/)
+ make_request(false, :mock => false)
+ @events.map(&:name)
+ end
+ end
+end
+
diff --git a/lib/vendor/excon/tests/middlewares/mock_tests.rb b/lib/vendor/excon/tests/middlewares/mock_tests.rb
new file mode 100644
index 0000000..49c25aa
--- /dev/null
+++ b/lib/vendor/excon/tests/middlewares/mock_tests.rb
@@ -0,0 +1,304 @@
+Shindo.tests('Excon stubs') do
+ env_init
+
+ tests("missing stub").raises(Excon::Errors::StubNotFound) do
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ connection.request(:method => :get, :path => '/content-length/100')
+ end
+
+ tests("stub({})").raises(ArgumentError) do
+ Excon.stub({})
+ end
+
+ tests("stub({}, {}) {}").raises(ArgumentError) do
+ Excon.stub({}, {}) {}
+ end
+
+ tests("stub({:method => :get}, {:body => 'body', :status => 200})") do
+ connection = nil
+ response = nil
+
+ tests('response.body').returns('body') do
+ Excon.stub({:method => :get}, {:body => 'body', :status => 200})
+
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ response = connection.request(:method => :get, :path => '/content-length/100')
+
+ response.body
+ end
+
+ tests('response.headers').returns({}) do
+ response.headers
+ end
+
+ tests('response.status').returns(200) do
+ response.status
+ end
+
+ tests('response_block yields body').returns('body') do
+ body = ''
+ response_block = lambda do |chunk, remaining_bytes, total_bytes|
+ body << chunk
+ end
+ connection.request(:method => :get, :path => '/content-length/100', :response_block => response_block)
+ body
+ end
+
+ tests('response.body empty with response_block').returns('') do
+ response_block = lambda { |_, _, _| }
+ connection.request(:method => :get, :path => '/content-length/100', :response_block => response_block).body
+ end
+
+ Excon.stubs.clear
+
+ end
+
+ tests("stub({:path => %r{/tests/(\S+)}}, {:body => $1, :status => 200})") do
+ connection = nil
+ response = nil
+
+ tests('response.body').returns('test') do
+ Excon.stub({:path => %r{/tests/(\S+)}}) do |params|
+ {
+ :body => params[:captures][:path].first,
+ :status => 200
+ }
+ end
+
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ response = connection.request(:method => :get, :path => '/tests/test')
+
+ response.body
+ end
+
+ tests('response.headers').returns({}) do
+ response.headers
+ end
+
+ tests('response.status').returns(200) do
+ response.status
+ end
+
+ Excon.stubs.clear
+
+ end
+
+ tests("stub({:body => 'body', :method => :get}) {|params| {:body => params[:body], :headers => params[:headers], :status => 200}}") do
+ connection = nil
+ response = nil
+
+ tests('response.body').returns('body') do
+ Excon.stub({:body => 'body', :method => :get}) {|params| {:body => params[:body], :headers => params[:headers], :status => 200}}
+
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ response = connection.request(:body => 'body', :method => :get, :path => '/content-length/100')
+
+ response.body
+ end
+
+ tests('response.headers').returns({'Host' => '127.0.0.1:9292', 'User-Agent' => "excon/#{Excon::VERSION}"}) do
+ response.headers
+ end
+
+ tests('response.status').returns(200) do
+ response.status
+ end
+
+ tests('response_block yields body').returns('body') do
+ body = ''
+ response_block = lambda do |chunk, remaining_bytes, total_bytes|
+ body << chunk
+ end
+ connection.request(:body => 'body', :method => :get, :path => '/content-length/100', :response_block => response_block)
+ body
+ end
+
+ tests('response.body empty with response_block').returns('') do
+ response_block = lambda { |_, _, _| }
+ connection.request(:body => 'body', :method => :get, :path => '/content-length/100', :response_block => response_block).body
+ end
+
+ Excon.stubs.clear
+
+ end
+
+ tests("stub({:body => File.open(...), :method => :get}, { :status => 200 })") do
+
+ tests('response.status').returns(200) do
+ file_path = File.join(File.dirname(__FILE__), '..', 'data', 'xs')
+
+ Excon.stub(
+ { :body => File.read(file_path), :method => :get },
+ { :status => 200 }
+ )
+
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ response = connection.request(:body => File.open(file_path), :method => :get, :path => '/')
+
+ response.status
+ end
+
+ Excon.stubs.clear
+
+ end
+
+ tests("invalid stub response").raises(Excon::Errors::InvalidStub) do
+ Excon.stub({:body => 42, :method => :get}, {:status => 200})
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ connection.request(:body => 42, :method => :get, :path => '/').status
+ end
+
+ tests("mismatched stub").raises(Excon::Errors::StubNotFound) do
+ Excon.stub({:method => :post}, {:body => 'body'})
+ Excon.get('http://127.0.0.1:9292/', :mock => true)
+ end
+
+ with_server('good') do
+ tests('allow mismatched stub').returns(200) do
+ Excon.stub({:path => '/echo/request_count'}, {:body => 'body'})
+ Excon.get(
+ 'http://127.0.0.1:9292/echo/request',
+ :mock => true,
+ :allow_unstubbed_requests => true
+ ).status
+ end
+ end
+
+ Excon.stubs.clear
+
+ tests("stub({}, {:body => 'x' * (Excon::DEFAULT_CHUNK_SIZE + 1)})") do
+
+ test("response_block yields body") do
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ Excon.stub({}, {:body => 'x' * (Excon::DEFAULT_CHUNK_SIZE + 1)})
+
+ chunks = []
+ response_block = lambda do |chunk, remaining_bytes, total_bytes|
+ chunks << chunk
+ end
+ connection.request(:method => :get, :path => '/content-length/100', :response_block => response_block)
+ chunks == ['x' * Excon::DEFAULT_CHUNK_SIZE, 'x']
+ end
+
+ tests("response.body empty with response_block").returns('') do
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ Excon.stub({}, {:body => 'x' * (Excon::DEFAULT_CHUNK_SIZE + 1)})
+ response_block = lambda { |_, _, _| }
+ connection.request(:method => :get, :path => '/content-length/100', :response_block => response_block).body
+ end
+
+ end
+
+ Excon.stubs.clear
+
+ tests("stub({:url => 'https://user:pass@foo.bar.com:9999/baz?quux=true'}, {:status => 200})") do
+ test("get(:expects => 200)") do
+ Excon.stub({:url => 'https://user:pass@foo.bar.com:9999/baz?quux=true'}, {:status => 200})
+ Excon.new("https://user:pass@foo.bar.com:9999/baz?quux=true", :mock => true).get(:expects => 200)
+ true
+ end
+ end
+
+ Excon.stubs.clear
+
+ tests("stub({}, {:status => 404, :body => 'Not Found'}") do
+ connection = nil
+
+ tests("request(:expects => 200, :method => :get, :path => '/')").raises(Excon::Errors::NotFound) do
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ Excon.stub({}, {:status => 404, :body => 'Not Found'})
+
+ connection.request(:expects => 200, :method => :get, :path => '/')
+ end
+
+ tests("Expects exception should contain response object").returns(Excon::Response) do
+ begin
+ connection.request(:expects => 200, :method => :get, :path => '/')
+ rescue Excon::Errors::NotFound => e
+ e.response.class
+ end
+ end
+
+ test("request(:expects => 200, :method => :get, :path => '/') with block does not invoke the block since it raises an error") do
+ block_called = false
+ begin
+ response_block = lambda do |_,_,_|
+ block_called = true
+ end
+ connection.request(:expects => 200, :method => :get, :path => '/', :response_block => response_block)
+ rescue Excon::Errors::NotFound
+ end
+ !block_called
+ end
+
+ Excon.stubs.clear
+
+ end
+
+ tests("stub_for({})") do
+ tests("stub_for({})").returns([{}, {}]) do
+ Excon.new('http://127.0.0.1:9292', :mock => true)
+ Excon.stub({}, {})
+
+ Excon.stub_for({})
+ end
+
+ Excon.stubs.clear
+ end
+
+ tests("unstub({})") do
+ connection = nil
+
+ tests("unstub({})").returns([{}, {}]) do
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ Excon.stub({}, {})
+
+ Excon.unstub({})
+ end
+
+ tests("request(:method => :get)").raises(Excon::Errors::StubNotFound) do
+ connection.request(:method => :get)
+ end
+
+ Excon.stubs.clear
+ end
+
+ tests("global stubs") do
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ Excon.stub({}, {:body => '1'})
+ t = Thread.new do
+ Excon.stub({}, {:body => '2'})
+ connection.request(:method => :get).body
+ end
+ tests("get on a different thread").returns('2') do
+ t.join.value
+ end
+ tests("get on main thread").returns('2') do
+ connection.request(:method => :get).body
+ end
+ Excon.stubs.clear
+ end
+
+ tests("thread-local stubs") do
+ original_stubs_value = Excon.defaults[:stubs]
+ Excon.defaults[:stubs] = :local
+
+ connection = Excon.new('http://127.0.0.1:9292', :mock => true)
+ Excon.stub({}, {:body => '1'})
+ t = Thread.new do
+ Excon.stub({}, {:body => '2'})
+ connection.request(:method => :get).body
+ end
+ tests("get on a different thread").returns('2') do
+ t.join.value
+ end
+ tests("get on main thread").returns('1') do
+ connection.request(:method => :get).body
+ end
+ Excon.stubs.clear
+
+ Excon.defaults[:stubs] = original_stubs_value
+ end
+
+ env_restore
+end
diff --git a/lib/vendor/excon/tests/middlewares/redirect_follower_tests.rb b/lib/vendor/excon/tests/middlewares/redirect_follower_tests.rb
new file mode 100644
index 0000000..d99271b
--- /dev/null
+++ b/lib/vendor/excon/tests/middlewares/redirect_follower_tests.rb
@@ -0,0 +1,80 @@
+Shindo.tests('Excon redirector support') do
+ env_init
+
+ tests("request(:method => :get, :path => '/old').body").returns('new') do
+ Excon.stub(
+ { :path => '/old' },
+ {
+ :headers => { 'Location' => 'http://127.0.0.1:9292/new' },
+ :body => 'old',
+ :status => 301
+ }
+ )
+
+ Excon.stub(
+ { :path => '/new' },
+ {
+ :body => 'new',
+ :status => 200
+ }
+ )
+
+ Excon.get(
+ 'http://127.0.0.1:9292',
+ :path => '/old',
+ :middlewares => Excon.defaults[:middlewares] + [Excon::Middleware::RedirectFollower],
+ :mock => true
+ ).body
+ end
+
+ env_restore
+end
+
+Shindo.tests('Excon redirect support for relative Location headers') do
+ env_init
+
+ tests("request(:method => :get, :path => '/old').body").returns('new') do
+ Excon.stub(
+ { :path => '/old' },
+ {
+ :headers => { 'Location' => '/new' },
+ :body => 'old',
+ :status => 301
+ }
+ )
+
+ Excon.stub(
+ { :path => '/new' },
+ {
+ :body => 'new',
+ :status => 200
+ }
+ )
+
+ Excon.get(
+ 'http://127.0.0.1:9292',
+ :path => '/old',
+ :middlewares => Excon.defaults[:middlewares] + [Excon::Middleware::RedirectFollower],
+ :mock => true
+ ).body
+ end
+
+ env_restore
+end
+
+Shindo.tests("Excon redirecting post request") do
+ env_init
+
+ with_rackup('redirecting.ru') do
+ tests("request not have content-length and body").returns('ok') do
+ Excon.post(
+ 'http://127.0.0.1:9292',
+ :path => '/first',
+ :middlewares => Excon.defaults[:middlewares] + [Excon::Middleware::RedirectFollower],
+ :body => "a=Some_content"
+ ).body
+ end
+ end
+
+ env_restore
+end
diff --git a/lib/vendor/excon/tests/pipeline_tests.rb b/lib/vendor/excon/tests/pipeline_tests.rb
new file mode 100644
index 0000000..578762b
--- /dev/null
+++ b/lib/vendor/excon/tests/pipeline_tests.rb
@@ -0,0 +1,40 @@
+Shindo.tests('Pipelined Requests') do
+ with_server('good') do
+
+ tests('with default :persistent => true') do
+ returns(%w{ 1 2 3 4 }, 'connection is persistent') do
+ connection = Excon.new('http://127.0.0.1:9292', :persistent => true)
+
+ ret = []
+ ret << connection.requests([
+ {:method => :get, :path => '/echo/request_count'},
+ {:method => :get, :path => '/echo/request_count'}
+ ]).map(&:body)
+ ret << connection.requests([
+ {:method => :get, :path => '/echo/request_count'},
+ {:method => :get, :path => '/echo/request_count'}
+ ]).map(&:body)
+ ret.flatten
+ end
+ end
+
+ tests('with default :persistent => false') do
+ returns(%w{ 1 2 1 2 }, 'connection is persistent per call to #requests') do
+ connection = Excon.new('http://127.0.0.1:9292', :persistent => false)
+
+ ret = []
+ ret << connection.requests([
+ {:method => :get, :path => '/echo/request_count'},
+ {:method => :get, :path => '/echo/request_count'}
+ ]).map(&:body)
+ ret << connection.requests([
+ {:method => :get, :path => '/echo/request_count'},
+ {:method => :get, :path => '/echo/request_count'}
+ ]).map(&:body)
+ ret.flatten
+ end
+
+ end
+
+ end
+end
diff --git a/lib/vendor/excon/tests/proxy_tests.rb b/lib/vendor/excon/tests/proxy_tests.rb
new file mode 100644
index 0000000..b1a5e2f
--- /dev/null
+++ b/lib/vendor/excon/tests/proxy_tests.rb
@@ -0,0 +1,306 @@
+Shindo.tests('Excon proxy support') do
+ env_init
+
+ tests('proxy configuration') do
+
+ tests('no proxy') do
+ tests('connection.data[:proxy]').returns(nil) do
+ connection = Excon.new('http://foo.com')
+ connection.data[:proxy]
+ end
+ end
+
+ tests('empty proxy') do
+ tests('connection.data[:proxy]').returns(nil) do
+ connection = Excon.new('http://foo.com', :proxy => '')
+ connection.data[:proxy]
+ end
+ end
+
+ tests('with fully-specified proxy: https://myproxy.net:8080') do
+ connection = nil
+
+ tests('connection.data[:proxy][:host]').returns('myproxy.net') do
+ connection = Excon.new('http://foo.com', :proxy => 'https://myproxy.net:8080')
+ connection.data[:proxy][:host]
+ end
+
+ tests('connection.data[:proxy][:port]').returns(8080) do
+ connection.data[:proxy][:port]
+ end
+
+ tests('connection.data[:proxy][:scheme]').returns('https') do
+ connection.data[:proxy][:scheme]
+ end
+ end
+
+ tests('with fully-specified Unix socket proxy: unix:///') do
+ connection = nil
+
+ tests('connection.data[:proxy][:host]').returns(nil) do
+ connection = Excon.new('http://foo.com', :proxy => 'unix:///tmp/myproxy.sock')
+ connection.data[:proxy][:host]
+ end
+
+ tests('connection.data[:proxy][:port]').returns(nil) do
+ connection.data[:proxy][:port]
+ end
+
+ tests('connection.data[:proxy][:scheme]').returns('unix') do
+ connection.data[:proxy][:scheme]
+ end
+
+ tests('connection.data[:proxy][:path]').returns('/tmp/myproxy.sock') do
+ connection.data[:proxy][:path]
+ end
+ end
+
+ def env_proxy_tests(env)
+ env_init(env)
+
+ tests('an http connection') do
+ connection = nil
+
+ tests('connection.data[:proxy][:host]').returns('myproxy') do
+ connection = Excon.new('http://foo.com')
+ connection.data[:proxy][:host]
+ end
+
+ tests('connection.data[:proxy][:port]').returns(8080) do
+ connection.data[:proxy][:port]
+ end
+
+ tests('connection.data[:proxy][:scheme]').returns('http') do
+ connection.data[:proxy][:scheme]
+ end
+
+ tests('with disable_proxy set') do
+ connection = nil
+
+ tests('connection.data[:proxy]').returns(nil) do
+ connection = Excon.new('http://foo.com', :disable_proxy => true)
+ connection.data[:proxy]
+ end
+ end
+ end
+
+ tests('an https connection') do
+ connection = nil
+
+ tests('connection.data[:proxy][:host]').returns('mysecureproxy') do
+ connection = Excon.new('https://secret.com')
+ connection.data[:proxy][:host]
+ end
+
+ tests('connection.data[:proxy][:port]').returns(8081) do
+ connection.data[:proxy][:port]
+ end
+
+ tests('connection.data[:proxy][:scheme]').returns('http') do
+ connection.data[:proxy][:scheme]
+ end
+
+ tests('with disable_proxy set') do
+ connection = nil
+
+ tests('connection.data[:proxy]').returns(nil) do
+ connection = Excon.new('https://foo.com', :disable_proxy => true)
+ connection.data[:proxy]
+ end
+ end
+ end
+
+ tests('http proxy from the environment overrides config') do
+ connection = nil
+
+ tests('connection.data[:proxy][:host]').returns('myproxy') do
+ connection = Excon.new('http://foo.com', :proxy => 'http://hard.coded.proxy:6666')
+ connection.data[:proxy][:host]
+ end
+
+ tests('connection.data[:proxy][:port]').returns(8080) do
+ connection.data[:proxy][:port]
+ end
+ end
+
+ tests('an http connection in no_proxy') do
+ tests('connection.data[:proxy]').returns(nil) do
+ connection = Excon.new('http://somesubdomain.noproxy')
+ connection.data[:proxy]
+ end
+ end
+
+ tests('an http connection not completely matching no_proxy') do
+ tests('connection.data[:proxy][:host]').returns('myproxy') do
+ connection = Excon.new('http://noproxy2')
+ connection.data[:proxy][:host]
+ end
+ end
+
+ tests('an http connection with subdomain in no_proxy') do
+ tests('connection.data[:proxy]').returns(nil) do
+ connection = Excon.new('http://a.subdomain.noproxy2')
+ connection.data[:proxy]
+ end
+ end
+
+ env_restore
+ end
+
+ tests('with complete proxy config from the environment') do
+ env = {
+ 'http_proxy' => 'http://myproxy:8080',
+ 'https_proxy' => 'http://mysecureproxy:8081',
+ 'no_proxy' => 'noproxy, subdomain.noproxy2'
+ }
+ tests('lowercase') { env_proxy_tests(env) }
+ upperenv = {}
+ env.each do |k, v|
+ upperenv[k.upcase] = v
+ end
+ tests('uppercase') { env_proxy_tests(upperenv) }
+ end
+
+ tests('with only http_proxy config from the environment') do
+ env_init({'http_proxy' => 'http://myproxy:8080' })
+
+ tests('an https connection') do
+ connection = nil
+
+ tests('connection.data[:proxy][:host]').returns('myproxy') do
+ connection = Excon.new('https://secret.com')
+ connection.data[:proxy][:host]
+ end
+
+ tests('connection.data[:proxy][:port]').returns(8080) do
+ connection.data[:proxy][:port]
+ end
+
+ tests('connection.data[:proxy][:scheme]').returns('http') do
+ connection.data[:proxy][:scheme]
+ end
+ end
+
+ env_restore
+ end
+
+ tests('with a unix socket proxy config from the environment') do
+ env_init({
+ 'http_proxy' => 'unix:///tmp/myproxy.sock',
+ })
+
+ tests('an https connection') do
+ connection = nil
+
+ tests('connection.data[:proxy][:host]').returns(nil) do
+ connection = Excon.new('https://secret.com')
+ connection.data[:proxy][:host]
+ end
+
+ tests('connection.data[:proxy][:port]').returns(nil) do
+ connection.data[:proxy][:port]
+ end
+
+ tests('connection.data[:proxy][:scheme]').returns('unix') do
+ connection.data[:proxy][:scheme]
+ end
+
+ tests('connection.data[:proxy][:path]').returns('/tmp/myproxy.sock') do
+ connection.data[:proxy][:path]
+ end
+ end
+
+ env_restore
+ end
+
+ end
+
+ with_rackup('proxy.ru') do
+
+ tests('http proxying: http://foo.com:8080') do
+ response = nil
+
+ tests('response.status').returns(200) do
+ connection = Excon.new('http://foo.com:8080', :proxy => 'http://127.0.0.1:9292')
+ response = connection.request(:method => :get, :path => '/bar', :query => {:alpha => 'kappa'})
+
+ response.status
+ end
+
+ # must be absolute form for proxy requests
+ tests('sent Request URI').returns('http://foo.com:8080/bar?alpha=kappa') do
+ response.headers['Sent-Request-Uri']
+ end
+
+ tests('sent Sent-Host header').returns('foo.com:8080') do
+ response.headers['Sent-Host']
+ end
+
+ tests('sent Proxy-Connection header').returns('Keep-Alive') do
+ response.headers['Sent-Proxy-Connection']
+ end
+
+ tests('response.body (proxied content)').returns('proxied content') do
+ response.body
+ end
+ end
+
+ tests('http proxying: http://user:pass@foo.com:8080') do
+ response = nil
+
+ tests('response.status').returns(200) do
+ connection = Excon.new('http://foo.com:8080', :proxy => 'http://user:pass@127.0.0.1:9292')
+ response = connection.request(:method => :get, :path => '/bar', :query => {:alpha => 'kappa'})
+
+ response.status
+ end
+
+ # must be absolute form for proxy requests
+ tests('sent Request URI').returns('http://foo.com:8080/bar?alpha=kappa') do
+ response.headers['Sent-Request-Uri']
+ end
+
+ tests('sent Host header').returns('foo.com:8080') do
+ response.headers['Sent-Host']
+ end
+
+ tests('sent Proxy-Connection header').returns('Keep-Alive') do
+ response.headers['Sent-Proxy-Connection']
+ end
+
+ tests('response.body (proxied content)').returns('proxied content') do
+ response.body
+ end
+ end
+
+ end
+
+ with_unicorn('proxy.ru', 'unix:///tmp/myproxy.sock') do
+ pending if RUBY_PLATFORM == 'java' # need to find suitable server for jruby
+
+ tests('http proxying over unix socket: http://foo.com:8080') do
+ response = nil
+
+ tests('response.status').returns(200) do
+ connection = Excon.new('http://foo.com:8080', :proxy => 'unix:///tmp/myproxy.sock')
+ response = connection.request(:method => :get, :path => '/bar', :query => {:alpha => 'kappa'})
+
+ response.status
+ end
+
+ tests('sent Sent-Host header').returns('foo.com:8080') do
+ response.headers['Sent-Host']
+ end
+
+ tests('sent Proxy-Connection header').returns('Keep-Alive') do
+ response.headers['Sent-Proxy-Connection']
+ end
+
+ tests('response.body (proxied content)').returns('proxied content') do
+ response.body
+ end
+ end
+ end
+
+ env_restore
+end
diff --git a/lib/vendor/excon/tests/query_string_tests.rb b/lib/vendor/excon/tests/query_string_tests.rb
new file mode 100644
index 0000000..0304250
--- /dev/null
+++ b/lib/vendor/excon/tests/query_string_tests.rb
@@ -0,0 +1,87 @@
+Shindo.tests('Excon query string variants') do
+ with_rackup('query_string.ru') do
+ connection = Excon.new('http://127.0.0.1:9292')
+
+ tests(":query => {:foo => 'bar'}") do
+ response = connection.request(:method => :get, :path => '/query', :query => {:foo => 'bar'})
+ query_string = response.body[7..-1] # query string sent
+
+ tests("query string sent").returns('foo=bar') do
+ query_string
+ end
+ end
+
+ tests(":query => {:foo => nil}") do
+ response = connection.request(:method => :get, :path => '/query', :query => {:foo => nil})
+ query_string = response.body[7..-1] # query string sent
+
+ tests("query string sent").returns('foo') do
+ query_string
+ end
+ end
+
+ tests(":query => {:foo => 'bar', :me => nil}") do
+ response = connection.request(:method => :get, :path => '/query', :query => {:foo => 'bar', :me => nil})
+ query_string = response.body[7..-1] # query string sent
+
+ test("query string sent includes 'foo=bar'") do
+ query_string.split('&').include?('foo=bar')
+ end
+
+ test("query string sent includes 'me'") do
+ query_string.split('&').include?('me')
+ end
+ end
+
+ tests(":query => {:foo => 'bar', :me => 'too'}") do
+ response = connection.request(:method => :get, :path => '/query', :query => {:foo => 'bar', :me => 'too'})
+ query_string = response.body[7..-1] # query string sent
+
+ test("query string sent includes 'foo=bar'") do
+ query_string.split('&').include?('foo=bar')
+ end
+
+ test("query string sent includes 'me=too'") do
+ query_string.split('&').include?('me=too')
+ end
+ end
+
+ # You can use an atom or a string for the hash keys, what is shown here is emulating
+ # the Rails and PHP style of serializing a query array with a square brackets suffix.
+ tests(":query => {'foo[]' => ['bar', 'baz'], :me => 'too'}") do
+ response = connection.request(:method => :get, :path => '/query', :query => {'foo[]' => ['bar', 'baz'], :me => 'too'})
+ query_string = response.body[7..-1] # query string sent
+
+ test("query string sent includes 'foo%5B%5D=bar'") do
+ query_string.split('&').include?('foo%5B%5D=bar')
+ end
+
+ test("query string sent includes 'foo%5B%5D=baz'") do
+ query_string.split('&').include?('foo%5B%5D=baz')
+ end
+
+ test("query string sent includes 'me=too'") do
+ query_string.split('&').include?('me=too')
+ end
+ end
+
+ tests(":query => {'foo%=#' => 'bar%=#'}") do
+ response = connection.request(:method => :get, :path => '/query', :query => {'foo%=#' => 'bar%=#'})
+ query_string = response.body[7..-1] # query string sent
+
+ tests("query string sent").returns('foo%25%3D%23=bar%25%3D%23') do
+ query_string
+ end
+ end
+
+ tests(":query => {'foo%=#' => nil}") do
+ response = connection.request(:method => :get, :path => '/query', :query => {'foo%=#' => nil})
+ query_string = response.body[7..-1] # query string sent
+
+ tests("query string sent").returns('foo%25%3D%23') do
+ query_string
+ end
+ end
+
+ end
+end
diff --git a/lib/vendor/excon/tests/rackups/basic.rb b/lib/vendor/excon/tests/rackups/basic.rb
new file mode 100644
index 0000000..0bddd9a
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/basic.rb
@@ -0,0 +1,41 @@
+require 'sinatra'
+require 'json'
+require File.join(File.dirname(__FILE__), 'webrick_patch')
+
+class Basic < Sinatra::Base
+ set :environment, :production
+ enable :dump_errors
+
+ get('/content-length/:value') do |value|
+ headers("Custom" => "Foo: bar")
+ 'x' * value.to_i
+ end
+
+ get('/headers') do
+ content_type :json
+ request.env.select{|key, _| key.start_with? 'HTTP_'}.to_json
+ end
+
+ post('/body-sink') do
+ request.body.read.size.to_s
+ end
+
+ post('/echo') do
+ echo
+ end
+
+ put('/echo') do
+ echo
+ end
+
+ get('/echo dirty') do
+ echo
+ end
+
+ private
+
+ def echo
+ request.body.read
+ end
+
+end
diff --git a/lib/vendor/excon/tests/rackups/basic.ru b/lib/vendor/excon/tests/rackups/basic.ru
new file mode 100644
index 0000000..90704a2
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/basic.ru
@@ -0,0 +1,3 @@
+require File.join(File.dirname(__FILE__), 'basic')
+
+run Basic
diff --git a/lib/vendor/excon/tests/rackups/basic_auth.ru b/lib/vendor/excon/tests/rackups/basic_auth.ru
new file mode 100644
index 0000000..d4565fb
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/basic_auth.ru
@@ -0,0 +1,14 @@
+require File.join(File.dirname(__FILE__), 'basic')
+
+class BasicAuth < Basic
+ before do
+ auth ||= Rack::Auth::Basic::Request.new(request.env)
+ user, pass = auth.provided? && auth.basic? && auth.credentials
+ unless [user, pass] == ["test_user", "test_password"]
+ response['WWW-Authenticate'] = %(Basic realm="Restricted Area")
+ throw(:halt, [401, "Not authorized\n"])
+ end
+ end
+end
+
+run BasicAuth
diff --git a/lib/vendor/excon/tests/rackups/deflater.ru b/lib/vendor/excon/tests/rackups/deflater.ru
new file mode 100644
index 0000000..1c881f1
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/deflater.ru
@@ -0,0 +1,4 @@
+require File.join(File.dirname(__FILE__), 'basic')
+
+use Rack::Deflater
+run Basic
diff --git a/lib/vendor/excon/tests/rackups/proxy.ru b/lib/vendor/excon/tests/rackups/proxy.ru
new file mode 100644
index 0000000..e6d7b65
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/proxy.ru
@@ -0,0 +1,18 @@
+require 'sinatra'
+require File.join(File.dirname(__FILE__), 'webrick_patch')
+
+class App < Sinatra::Base
+ set :environment, :production
+ enable :dump_errors
+
+ get('*') do
+ headers(
+ "Sent-Request-Uri" => request.env['REQUEST_URI'].to_s,
+ "Sent-Host" => request.env['HTTP_HOST'].to_s,
+ "Sent-Proxy-Connection" => request.env['HTTP_PROXY_CONNECTION'].to_s
+ )
+ 'proxied content'
+ end
+end
+
+run App
diff --git a/lib/vendor/excon/tests/rackups/query_string.ru b/lib/vendor/excon/tests/rackups/query_string.ru
new file mode 100644
index 0000000..b5bca66
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/query_string.ru
@@ -0,0 +1,13 @@
+require 'sinatra'
+require File.join(File.dirname(__FILE__), 'webrick_patch')
+
+class App < Sinatra::Base
+ set :environment, :production
+ enable :dump_errors
+
+ get('/query') do
+ "query: " << request.query_string
+ end
+end
+
+run App
diff --git a/lib/vendor/excon/tests/rackups/redirecting.ru b/lib/vendor/excon/tests/rackups/redirecting.ru
new file mode 100644
index 0000000..fff61e4
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/redirecting.ru
@@ -0,0 +1,23 @@
+require 'sinatra'
+require 'json'
+require File.join(File.dirname(__FILE__), 'webrick_patch')
+
+class App < Sinatra::Base
+ set :environment, :production
+ enable :dump_errors
+
+ post('/first') do
+ redirect "/second"
+ end
+
+ get('/second') do
+ post_body = request.body.read
+ if post_body == "" && request["CONTENT_LENGTH"].nil?
+ "ok"
+ else
+ JSON.pretty_generate(request.env)
+ end
+ end
+end
+
+run App
diff --git a/lib/vendor/excon/tests/rackups/redirecting_with_cookie.ru b/lib/vendor/excon/tests/rackups/redirecting_with_cookie.ru
new file mode 100644
index 0000000..f0401f8
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/redirecting_with_cookie.ru
@@ -0,0 +1,40 @@
+require 'sinatra'
+require 'sinatra/cookies'
+require 'json'
+require File.join(File.dirname(__FILE__), 'webrick_patch')
+
+class App < Sinatra::Base
+ helpers Sinatra::Cookies
+ set :environment, :production
+ enable :dump_errors
+
+ get('/sets_cookie') do
+ cookies[:chocolatechip] = "chunky"
+ redirect "/requires_cookie"
+ end
+
+ get('/requires_cookie') do
+ cookie = cookies[:chocolatechip]
+ unless cookie.nil? || cookie != "chunky"
+ "ok"
+ else
+ JSON.pretty_generate(headers)
+ end
+ end
+
+ get('/sets_multi_cookie') do
+ cookies[:chocolatechip] = "chunky"
+ cookies[:thinmints] = "minty"
+ redirect "/requires_cookie"
+ end
+
+ get('/requires_cookie') do
+ if cookies[:chocolatechip] == "chunky" && cookies[:thinmints] == "minty"
+ "ok"
+ else
+ JSON.pretty_generate(headers)
+ end
+ end
+end
+
+run App
diff --git a/lib/vendor/excon/tests/rackups/request_headers.ru b/lib/vendor/excon/tests/rackups/request_headers.ru
new file mode 100644
index 0000000..e1cc0f8
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/request_headers.ru
@@ -0,0 +1,15 @@
+require 'sinatra'
+require File.join(File.dirname(__FILE__), 'webrick_patch')
+
+class App < Sinatra::Base
+ set :environment, :production
+ enable :dump_errors
+
+ post '/' do
+ h = ""
+ env.each { |k,v| h << "#{$1.downcase}: #{v}\n" if k =~ /http_(.*)/i }
+ h
+ end
+end
+
+run App
diff --git a/lib/vendor/excon/tests/rackups/request_methods.ru b/lib/vendor/excon/tests/rackups/request_methods.ru
new file mode 100644
index 0000000..1fc08f4
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/request_methods.ru
@@ -0,0 +1,21 @@
+require 'sinatra'
+require File.join(File.dirname(__FILE__), 'webrick_patch')
+
+class App < Sinatra::Base
+ set :environment, :production
+ enable :dump_errors
+
+ get '/' do
+ 'GET'
+ end
+
+ post '/' do
+ 'POST'
+ end
+
+ delete '/' do
+ 'DELETE'
+ end
+end
+
+run App
diff --git a/lib/vendor/excon/tests/rackups/response_header.ru b/lib/vendor/excon/tests/rackups/response_header.ru
new file mode 100644
index 0000000..be0088f
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/response_header.ru
@@ -0,0 +1,18 @@
+require 'sinatra'
+require File.join(File.dirname(__FILE__), 'webrick_patch')
+
+class App < Sinatra::Base
+ set :environment, :production
+ enable :dump_errors
+
+ get('/foo') do
+ headers(
+ "MixedCase-Header" => 'MixedCase',
+ "UPPERCASE-HEADER" => 'UPPERCASE',
+ "lowercase-header" => 'lowercase'
+ )
+ 'primary content'
+ end
+end
+
+run App
diff --git a/lib/vendor/excon/tests/rackups/ssl.ru b/lib/vendor/excon/tests/rackups/ssl.ru
new file mode 100644
index 0000000..fc17065
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/ssl.ru
@@ -0,0 +1,16 @@
+require 'openssl'
+require 'webrick'
+require 'webrick/https'
+
+require File.join(File.dirname(__FILE__), 'basic')
+
+key_file = File.join(File.dirname(__FILE__), '..', 'data', '127.0.0.1.cert.key')
+cert_file = File.join(File.dirname(__FILE__), '..', 'data', '127.0.0.1.cert.crt')
+Rack::Handler::WEBrick.run(Basic, {
+ :Port => 9443,
+ :SSLEnable => true,
+ :SSLPrivateKey => OpenSSL::PKey::RSA.new(File.open(key_file).read),
+ :SSLCertificate => OpenSSL::X509::Certificate.new(File.open(cert_file).read),
+ :SSLCACertificateFile => cert_file,
+ :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
+})
diff --git a/lib/vendor/excon/tests/rackups/ssl_mismatched_cn.ru b/lib/vendor/excon/tests/rackups/ssl_mismatched_cn.ru
new file mode 100644
index 0000000..d9c5edf
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/ssl_mismatched_cn.ru
@@ -0,0 +1,15 @@
+require 'openssl'
+require 'webrick'
+require 'webrick/https'
+
+require File.join(File.dirname(__FILE__), 'basic')
+key_file = File.join(File.dirname(__FILE__), '..', 'data', 'excon.cert.key')
+cert_file = File.join(File.dirname(__FILE__), '..', 'data', 'excon.cert.crt')
+Rack::Handler::WEBrick.run(Basic, {
+ :Port => 9443,
+ :SSLEnable => true,
+ :SSLPrivateKey => OpenSSL::PKey::RSA.new(File.open(key_file).read),
+ :SSLCertificate => OpenSSL::X509::Certificate.new(File.open(cert_file).read),
+ :SSLCACertificateFile => cert_file,
+ :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
+})
diff --git a/lib/vendor/excon/tests/rackups/ssl_verify_peer.ru b/lib/vendor/excon/tests/rackups/ssl_verify_peer.ru
new file mode 100644
index 0000000..44d64c7
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/ssl_verify_peer.ru
@@ -0,0 +1,16 @@
+require 'openssl'
+require 'webrick'
+require 'webrick/https'
+
+require File.join(File.dirname(__FILE__), 'basic')
+key_file = File.join(File.dirname(__FILE__), '..', 'data', 'excon.cert.key')
+cert_file = File.join(File.dirname(__FILE__), '..', 'data', 'excon.cert.crt')
+Rack::Handler::WEBrick.run(Basic, {
+ :Port => 8443,
+ :SSLCertName => [["CN", WEBrick::Utils::getservername]],
+ :SSLEnable => true,
+ :SSLPrivateKey => OpenSSL::PKey::RSA.new(File.open(key_file).read),
+ :SSLCertificate => OpenSSL::X509::Certificate.new(File.open(cert_file).read),
+ :SSLCACertificateFile => cert_file,
+ :SSLVerifyClient => OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT,
+})
diff --git a/lib/vendor/excon/tests/rackups/streaming.ru b/lib/vendor/excon/tests/rackups/streaming.ru
new file mode 100644
index 0000000..101c064
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/streaming.ru
@@ -0,0 +1,30 @@
+use Rack::ContentType, "text/plain"
+
+app = lambda do |env|
+ # streamed pieces to be sent
+ pieces = %w{Hello streamy world}
+
+ response_headers = {}
+
+ # set a fixed content length in the header if requested
+ if env['REQUEST_PATH'] == '/streamed/fixed_length'
+ response_headers['Content-Length'] = pieces.join.length.to_s
+ end
+
+ response_headers["rack.hijack"] = lambda do |io|
+ # Write directly to IO of the response
+ begin
+ # return the response in pieces
+ pieces.each do |x|
+ sleep(0.1)
+ io.write(x)
+ io.flush
+ end
+ ensure
+ io.close
+ end
+ end
+ [200, response_headers, nil]
+end
+
+run app
diff --git a/lib/vendor/excon/tests/rackups/thread_safety.ru b/lib/vendor/excon/tests/rackups/thread_safety.ru
new file mode 100644
index 0000000..436c596
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/thread_safety.ru
@@ -0,0 +1,17 @@
+require 'sinatra'
+require File.join(File.dirname(__FILE__), 'webrick_patch')
+
+class App < Sinatra::Base
+ set :environment, :production
+ enable :dump_errors
+
+ get('/id/:id/wait/:wait') do |id, wait|
+ sleep(wait.to_i)
+ id.to_s
+ end
+end
+
+# get everything autoloaded, mainly for rbx
+App.new
+
+run App
diff --git a/lib/vendor/excon/tests/rackups/timeout.ru b/lib/vendor/excon/tests/rackups/timeout.ru
new file mode 100644
index 0000000..060436f
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/timeout.ru
@@ -0,0 +1,14 @@
+require 'sinatra'
+require File.join(File.dirname(__FILE__), 'webrick_patch')
+
+class App < Sinatra::Base
+ set :environment, :production
+ enable :dump_errors
+
+ get('/timeout') do
+ sleep(2)
+ ''
+ end
+end
+
+run App
diff --git a/lib/vendor/excon/tests/rackups/webrick_patch.rb b/lib/vendor/excon/tests/rackups/webrick_patch.rb
new file mode 100644
index 0000000..d65cf58
--- /dev/null
+++ b/lib/vendor/excon/tests/rackups/webrick_patch.rb
@@ -0,0 +1,34 @@
+# The ruby 2.0 stdlib includes the following changes
+# to avoid "can't add a new key into hash during iteration" errors.
+# https://github.com/ruby/ruby/commit/3c491a92f6fbfecc065f7687c51c7d6d52a38883
+# https://github.com/ruby/ruby/commit/7b18633804c606e8bcccfbb44e7d7b795e777ea6
+# However, these changes were not backported to the 1.9.x stdlib.
+# These errors are causing intermittent errors in the tests (frequently in jruby),
+# so we're applying those changes here. This is loaded by all rackups using WEBrick.
+if RUBY_VERSION =~ /^1\.9/
+ require 'webrick/utils'
+ module WEBrick
+ module Utils
+ class TimeoutHandler
+ def initialize
+ @timeout_info = Hash.new
+ Thread.start{
+ while true
+ now = Time.now
+ @timeout_info.keys.each{|thread|
+ ary = @timeout_info[thread]
+ next unless ary
+ ary.dup.each{|info|
+ time, exception = *info
+ interrupt(thread, info.object_id, exception) if time < now
+ }
+ }
+ sleep 0.5
+ end
+ }
+ end
+ end
+ end
+ end
+end
+
diff --git a/lib/vendor/excon/tests/request_headers_tests.rb b/lib/vendor/excon/tests/request_headers_tests.rb
new file mode 100644
index 0000000..12ebbc7
--- /dev/null
+++ b/lib/vendor/excon/tests/request_headers_tests.rb
@@ -0,0 +1,21 @@
+Shindo.tests('Excon request methods') do
+
+ with_rackup('request_headers.ru') do
+
+ tests 'empty headers sent' do
+
+ test('Excon.post') do
+ headers = {
+ :one => 1,
+ :two => nil,
+ :three => 3,
+ }
+ r = Excon.post('http://localhost:9292', :headers => headers).body
+ !r.match(/two:/).nil?
+ end
+
+ end
+
+ end
+
+end
diff --git a/lib/vendor/excon/tests/request_method_tests.rb b/lib/vendor/excon/tests/request_method_tests.rb
new file mode 100644
index 0000000..3cc9855
--- /dev/null
+++ b/lib/vendor/excon/tests/request_method_tests.rb
@@ -0,0 +1,47 @@
+Shindo.tests('Excon request methods') do
+
+ with_rackup('request_methods.ru') do
+
+ tests 'one-offs' do
+
+ tests('Excon.get').returns('GET') do
+ Excon.get('http://localhost:9292').body
+ end
+
+ tests('Excon.post').returns('POST') do
+ Excon.post('http://localhost:9292').body
+ end
+
+ tests('Excon.delete').returns('DELETE') do
+ Excon.delete('http://localhost:9292').body
+ end
+
+ end
+
+ tests 'with a connection object' do
+ connection = nil
+
+ tests('connection.get').returns('GET') do
+ connection = Excon.new('http://localhost:9292')
+ connection.get.body
+ end
+
+ tests('connection.post').returns('POST') do
+ connection.post.body
+ end
+
+ tests('connection.delete').returns('DELETE') do
+ connection.delete.body
+ end
+
+ tests('not modifies path argument').returns('path') do
+ path = 'path'
+ connection.get(:path => path)
+ path
+ end
+
+ end
+
+ end
+
+end
diff --git a/lib/vendor/excon/tests/request_tests.rb b/lib/vendor/excon/tests/request_tests.rb
new file mode 100644
index 0000000..ad2662c
--- /dev/null
+++ b/lib/vendor/excon/tests/request_tests.rb
@@ -0,0 +1,59 @@
+Shindo.tests('Request Tests') do
+ with_server('good') do
+
+ tests('persistent connections') do
+ ip_ports = %w(127.0.0.1:9292)
+ ip_ports << "[::1]:9293" unless RUBY_PLATFORM == 'java'
+ ip_ports.each do |ip_port|
+
+ tests("with default :persistent => true, #{ip_port}") do
+ connection = nil
+
+ returns(['1', '2'], 'uses a persistent connection') do
+ connection = Excon.new("http://#{ip_port}", :persistent => true)
+ 2.times.map do
+ connection.request(:method => :get, :path => '/echo/request_count').body
+ end
+ end
+
+ returns(['3', '1', '2'], ':persistent => false resets connection') do
+ ret = []
+ ret << connection.request(:method => :get,
+ :path => '/echo/request_count',
+ :persistent => false).body
+ ret << connection.request(:method => :get,
+ :path => '/echo/request_count').body
+ ret << connection.request(:method => :get,
+ :path => '/echo/request_count').body
+ end
+ end
+
+ tests("with default :persistent => false, #{ip_port}") do
+ connection = nil
+
+ returns(['1', '1'], 'does not use a persistent connection') do
+ connection = Excon.new("http://#{ip_port}", :persistent => false)
+ 2.times.map do
+ connection.request(:method => :get, :path => '/echo/request_count').body
+ end
+ end
+
+ returns(['1', '2', '3', '1'], ':persistent => true enables persistence') do
+ ret = []
+ ret << connection.request(:method => :get,
+ :path => '/echo/request_count',
+ :persistent => true).body
+ ret << connection.request(:method => :get,
+ :path => '/echo/request_count',
+ :persistent => true).body
+ ret << connection.request(:method => :get,
+ :path => '/echo/request_count').body
+ ret << connection.request(:method => :get,
+ :path => '/echo/request_count').body
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/vendor/excon/tests/response_tests.rb b/lib/vendor/excon/tests/response_tests.rb
new file mode 100644
index 0000000..2a989dd
--- /dev/null
+++ b/lib/vendor/excon/tests/response_tests.rb
@@ -0,0 +1,197 @@
+Shindo.tests('Excon Response Parsing') do
+ env_init
+
+ with_server('good') do
+
+ tests('responses with chunked transfer-encoding') do
+
+ tests('simple response').returns('hello world') do
+ Excon.get('http://127.0.0.1:9292/chunked/simple').body
+ end
+
+ tests('with :response_block') do
+
+ tests('simple response').
+ returns([['hello ', nil, nil], ['world', nil, nil]]) do
+ capture_response_block do |block|
+ Excon.get('http://127.0.0.1:9292/chunked/simple',
+ :response_block => block,
+ :chunk_size => 5) # not used
+ end
+ end
+
+ tests('simple response has empty body').returns('') do
+ response_block = lambda { |_, _, _| }
+ Excon.get('http://127.0.0.1:9292/chunked/simple', :response_block => response_block).body
+ end
+
+ tests('with expected response status').
+ returns([['hello ', nil, nil], ['world', nil, nil]]) do
+ capture_response_block do |block|
+ Excon.get('http://127.0.0.1:9292/chunked/simple',
+ :response_block => block,
+ :expects => 200)
+ end
+ end
+
+ tests('with unexpected response status').returns('hello world') do
+ begin
+ Excon.get('http://127.0.0.1:9292/chunked/simple',
+ :response_block => Proc.new { raise 'test failed' },
+ :expects => 500)
+ rescue Excon::Errors::HTTPStatusError => err
+ err.response[:body]
+ end
+ end
+
+ end
+
+ tests('merges trailers into headers').
+ returns('one, two, three, four, five, six') do
+ Excon.get('http://127.0.0.1:9292/chunked/trailers').headers['Test-Header']
+ end
+
+ tests("removes 'chunked' from Transfer-Encoding").returns(nil) do
+ Excon.get('http://127.0.0.1:9292/chunked/simple').headers['Transfer-Encoding']
+ end
+
+ end
+
+ tests('responses with content-length') do
+
+ tests('simple response').returns('hello world') do
+ Excon.get('http://127.0.0.1:9292/content-length/simple').body
+ end
+
+ tests('with :response_block') do
+
+ tests('simple response').
+ returns([['hello', 6, 11], [' worl', 1, 11], ['d', 0, 11]]) do
+ capture_response_block do |block|
+ Excon.get('http://127.0.0.1:9292/content-length/simple',
+ :response_block => block,
+ :chunk_size => 5)
+ end
+ end
+
+ tests('simple response has empty body').returns('') do
+ response_block = lambda { |_, _, _| }
+ Excon.get('http://127.0.0.1:9292/content-length/simple', :response_block => response_block).body
+ end
+
+ tests('with expected response status').
+ returns([['hello', 6, 11], [' worl', 1, 11], ['d', 0, 11]]) do
+ capture_response_block do |block|
+ Excon.get('http://127.0.0.1:9292/content-length/simple',
+ :response_block => block,
+ :chunk_size => 5,
+ :expects => 200)
+ end
+ end
+
+ tests('with unexpected response status').returns('hello world') do
+ begin
+ Excon.get('http://127.0.0.1:9292/content-length/simple',
+ :response_block => Proc.new { raise 'test failed' },
+ :chunk_size => 5,
+ :expects => 500)
+ rescue Excon::Errors::HTTPStatusError => err
+ err.response[:body]
+ end
+ end
+
+ end
+
+ end
+
+ tests('responses with unknown length') do
+
+ tests('simple response').returns('hello world') do
+ Excon.get('http://127.0.0.1:9292/unknown/simple').body
+ end
+
+ tests('with :response_block') do
+
+ tests('simple response').
+ returns([['hello', nil, nil], [' worl', nil, nil], ['d', nil, nil]]) do
+ capture_response_block do |block|
+ Excon.get('http://127.0.0.1:9292/unknown/simple',
+ :response_block => block,
+ :chunk_size => 5)
+ end
+ end
+
+ tests('simple response has empty body').returns('') do
+ response_block = lambda { |_, _, _| }
+ Excon.get('http://127.0.0.1:9292/unknown/simple', :response_block => response_block).body
+ end
+
+ tests('with expected response status').
+ returns([['hello', nil, nil], [' worl', nil, nil], ['d', nil, nil]]) do
+ capture_response_block do |block|
+ Excon.get('http://127.0.0.1:9292/unknown/simple',
+ :response_block => block,
+ :chunk_size => 5,
+ :expects => 200)
+ end
+ end
+
+ tests('with unexpected response status').returns('hello world') do
+ begin
+ Excon.get('http://127.0.0.1:9292/unknown/simple',
+ :response_block => Proc.new { raise 'test failed' },
+ :chunk_size => 5,
+ :expects => 500)
+ rescue Excon::Errors::HTTPStatusError => err
+ err.response[:body]
+ end
+ end
+
+ end
+
+ end
+
+ tests('cookies') do
+
+ tests('parses cookies into array').returns(['one, two', 'three, four']) do
+ resp = Excon.get('http://127.0.0.1:9292/unknown/cookies')
+ resp[:cookies]
+ end
+
+ end
+
+ tests('header continuation') do
+
+ tests('proper continuation').returns('one, two, three, four, five, six') do
+ resp = Excon.get('http://127.0.0.1:9292/unknown/header_continuation')
+ resp.headers['Test-Header']
+ end
+
+ tests('malformed header').raises(Excon::Errors::SocketError) do
+ Excon.get('http://127.0.0.1:9292/bad/malformed_header')
+ end
+
+ tests('malformed header continuation').raises(Excon::Errors::SocketError) do
+ Excon.get('http://127.0.0.1:9292/bad/malformed_header_continuation')
+ end
+
+ end
+
+ tests('status line parsing') do
+
+ tests('proper status code').returns(404) do
+ resp = Excon.get('http://127.0.0.1:9292/not-found')
+ resp.status
+ end
+
+ tests('proper reason phrase').returns("Not Found") do
+ resp = Excon.get('http://127.0.0.1:9292/not-found')
+ resp.reason_phrase
+ end
+
+ end
+
+ end
+
+ env_restore
+end
diff --git a/lib/vendor/excon/tests/servers/bad.rb b/lib/vendor/excon/tests/servers/bad.rb
new file mode 100755
index 0000000..e502d83
--- /dev/null
+++ b/lib/vendor/excon/tests/servers/bad.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+
+require "eventmachine"
+
+module BadServer
+ def receive_data(data)
+ case data
+ when %r{^GET /eof/no_content_length_and_no_chunking\s}
+ send_data "HTTP/1.1 200 OK\r\n"
+ send_data "\r\n"
+ send_data "hello"
+ close_connection(true)
+ end
+ end
+end
+
+EM.run do
+ EM.start_server("127.0.0.1", 9292, BadServer)
+ $stderr.puts "ready"
+end
diff --git a/lib/vendor/excon/tests/servers/eof.rb b/lib/vendor/excon/tests/servers/eof.rb
new file mode 100755
index 0000000..a82c729
--- /dev/null
+++ b/lib/vendor/excon/tests/servers/eof.rb
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+
+require "eventmachine"
+
+module EOFServer
+ def receive_data(data)
+ case data
+ when %r{^GET /eof\s}
+ close_connection(true)
+ end
+ end
+end
+
+EM.run do
+ EM.start_server("127.0.0.1", 9292, EOFServer)
+ $stderr.puts "ready"
+end
diff --git a/lib/vendor/excon/tests/servers/error.rb b/lib/vendor/excon/tests/servers/error.rb
new file mode 100755
index 0000000..ab3cd1f
--- /dev/null
+++ b/lib/vendor/excon/tests/servers/error.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+
+require "eventmachine"
+
+module ErrorServer
+ def receive_data(data)
+ case data
+ when %r{^GET /error/not_found\s}
+ send_data "HTTP/1.1 404 Not Found\r\n"
+ send_data "\r\n"
+ send_data "server says not found"
+ close_connection(true)
+ end
+ end
+end
+
+EM.run do
+ EM.start_server("127.0.0.1", 9292, ErrorServer)
+ $stderr.puts "ready"
+end
diff --git a/lib/vendor/excon/tests/servers/good.rb b/lib/vendor/excon/tests/servers/good.rb
new file mode 100755
index 0000000..1cb6d7f
--- /dev/null
+++ b/lib/vendor/excon/tests/servers/good.rb
@@ -0,0 +1,350 @@
+#!/usr/bin/env ruby
+
+require 'eventmachine'
+require 'stringio'
+require 'uri'
+require 'zlib'
+
+module GoodServer
+ # This method will be called with each request received.
+ #
+ # request = {
+ # :method => method,
+ # :uri => URI.parse(uri),
+ # :headers => {},
+ # :body => ''
+ # }
+ #
+ # Each connection to this server is persistent unless the client sends
+ # "Connection: close" in the request. If a response requires the connection
+ # to be closed, use `start_response(:persistent => false)`.
+ def send_response(request)
+ type, path = request[:uri].path.split('/', 3)[1, 2]
+ case type
+ when 'echo'
+ case path
+ when 'request'
+ data = Marshal.dump(request)
+ start_response
+ send_data "Content-Length: #{ data.size }\r\n"
+ send_data "\r\n"
+ send_data data
+
+ when 'request_count'
+ (@request_count ||= '0').next!
+ start_response
+ send_data "Content-Length: #{ @request_count.size }\r\n"
+ send_data "Connection: Keep-Alive\r\n"
+ send_data "\r\n"
+ send_data @request_count
+
+ when /(content|transfer)-encoded\/?(.*)/
+ if (encoding_type = $1) == 'content'
+ accept_header = 'Accept-Encoding'
+ encoding_header = 'Content-Encoding'
+ else
+ accept_header = 'TE'
+ encoding_header = 'Transfer-Encoding'
+ end
+ chunked = $2 == 'chunked'
+
+ encodings = parse_encodings(request[:headers][accept_header])
+ while encoding = encodings.pop
+ break if ['gzip', 'deflate'].include?(encoding)
+ end
+
+ case encoding
+ when 'gzip'
+ body = request[:body]
+ if(body.nil? || body.empty?)
+ body = ''
+ else
+ io = (Zlib::GzipWriter.new(StringIO.new) << request[:body]).finish
+ io.rewind
+ body = io.read
+ end
+ when 'deflate'
+ # drops the zlib header
+ deflator = Zlib::Deflate.new(nil, -Zlib::MAX_WBITS)
+ body = deflator.deflate(request[:body], Zlib::FINISH)
+ deflator.close
+ else
+ body = request[:body]
+ end
+
+ # simulate server pre/post content encoding
+ encodings = [
+ request[:headers]["#{ encoding_header }-Pre"],
+ encoding,
+ request[:headers]["#{ encoding_header }-Post"],
+ ]
+ if chunked && encoding_type == 'transfer'
+ encodings << 'chunked'
+ end
+ encodings = encodings.compact.join(', ')
+
+ start_response
+ # let the test know what the server sent
+ send_data "#{ encoding_header }-Sent: #{ encodings }\r\n"
+ send_data "#{ encoding_header }: #{ encodings }\r\n" unless encodings.empty?
+ if chunked
+ if encoding_type == 'content'
+ send_data "Transfer-Encoding: chunked\r\n"
+ end
+ send_data "\r\n"
+ send_data chunks_for(body)
+ send_data "\r\n"
+ else
+ send_data "Content-Length: #{ body.size }\r\n"
+ send_data "\r\n"
+ send_data body
+ end
+ end
+
+ when 'chunked'
+ case path
+ when 'simple'
+ start_response
+ send_data "Transfer-Encoding: chunked\r\n"
+ send_data "\r\n"
+ # chunk-extension is currently ignored.
+ # this works because "6; chunk-extension".to_i => "6"
+ send_data "6; chunk-extension\r\n"
+ send_data "hello \r\n"
+ send_data "5; chunk-extension\r\n"
+ send_data "world\r\n"
+ send_data "0; chunk-extension\r\n" # last-chunk
+ send_data "\r\n"
+
+ # merged trailers also support continuations
+ when 'trailers'
+ start_response
+ send_data "Transfer-Encoding: chunked\r\n"
+ send_data "Test-Header: one, two\r\n"
+ send_data "\r\n"
+ send_data chunks_for('hello world')
+ send_data "Test-Header: three, four,\r\n"
+ send_data "\tfive, six\r\n"
+ send_data "\r\n"
+ end
+
+ when 'content-length'
+ case path
+ when 'simple'
+ start_response
+ send_data "Content-Length: 11\r\n"
+ send_data "\r\n"
+ send_data "hello world"
+ end
+
+ when 'unknown'
+ case path
+ when 'cookies'
+ start_response(:persistent => false)
+ send_data "Set-Cookie: one, two\r\n"
+ send_data "Set-Cookie: three, four\r\n"
+ send_data "\r\n"
+ send_data "hello world"
+
+ when 'simple'
+ start_response(:persistent => false)
+ send_data "\r\n"
+ send_data "hello world"
+
+ when 'header_continuation'
+ start_response(:persistent => false)
+ send_data "Test-Header: one, two\r\n"
+ send_data "Test-Header: three, four,\r\n"
+ send_data " five, six\r\n"
+ send_data "\r\n"
+ send_data "hello world"
+ end
+
+ when 'bad'
+ # Excon will close these connections due to the errors.
+ case path
+ when 'malformed_header'
+ start_response
+ send_data "Bad-Header\r\n" # no ':'
+ send_data "\r\n"
+ send_data "hello world"
+
+ when 'malformed_header_continuation'
+ send_data "HTTP/1.1 200 OK\r\n"
+ send_data " Bad-Header: one, two\r\n" # no previous header
+ send_data "\r\n"
+ send_data "hello world"
+ end
+
+ when 'not-found'
+ start_response(:status => "404 Not Found")
+ send_data "Content-Length: 11\r\n"
+ send_data "\r\n"
+ send_data "hello world"
+ end
+ end
+
+ # Sends response status-line, plus headers common to all responses.
+ def start_response(opts = {})
+ opts = {
+ :status => '200 OK',
+ :persistent => @persistent # true unless client sent Connection: close
+ }.merge!(opts)
+
+ @persistent = opts[:persistent]
+ send_data "HTTP/1.1 #{ opts[:status] }\r\n"
+ send_data "Connection: close\r\n" unless @persistent
+ end
+
+ def post_init
+ @buffer = StringIO.new
+ @buffer.set_encoding('BINARY') if @buffer.respond_to?(:set_encoding)
+ end
+
+ # Receives a String of +data+ sent from the client.
+ # +data+ may only be a portion of what the client sent.
+ # The data is buffered, then processed and removed from the buffer
+ # as data becomes available until the @request is complete.
+ def receive_data(data)
+ @buffer.seek(0, IO::SEEK_END)
+ @buffer.write(data)
+
+ parse_headers unless @request
+ parse_body if @request
+
+ if @request_complete
+ send_response(@request)
+ if @persistent
+ @request = nil
+ @request_complete = false
+ # process remaining buffer for next request
+ receive_data('') unless @buffer.eof?
+ else
+ close_connection(true)
+ end
+ end
+ end
+
+ # Removes the processed portion of the buffer
+ # by replacing the buffer with it's contents from the current pos.
+ def sync_buffer
+ @buffer.string = @buffer.read
+ end
+
+ def parse_headers
+ @buffer.rewind
+ # wait until buffer contains the end of the headers
+ if /\sHTTP\/\d+\.\d+\r\n.*?\r\n\r\n/m =~ @buffer.read
+ @buffer.rewind
+ # For persistent connections, the buffer could start with the
+ # \r\n chunked-message terminator from the previous request.
+ # This will discard anything up to the request-line.
+ until m = /^(\w+)\s(.*)\sHTTP\/\d+\.\d+$/.match(@buffer.readline.chop!); end
+ method, uri = m[1, 2]
+
+ headers = {}
+ last_key = nil
+ until (line = @buffer.readline.chop!).empty?
+ if !line.lstrip!.nil?
+ headers[last_key] << ' ' << line.rstrip
+ else
+ key, value = line.split(':', 2)
+ headers[key] = ([headers[key]] << value.strip).compact.join(', ')
+ last_key = key
+ end
+ end
+
+ sync_buffer
+
+ @chunked = headers['Transfer-Encoding'] =~ /chunked/i
+ @content_length = headers['Content-Length'].to_i
+ @persistent = headers['Connection'] !~ /close/i
+ @request = {
+ :method => method,
+ :uri => URI.parse(uri),
+ :headers => headers,
+ :body => ''
+ }
+ end
+ end
+
+ def parse_body
+ if @chunked
+ @buffer.rewind
+ until @request_complete || @buffer.eof?
+ unless @chunk_size
+ # in case buffer only contains a portion of the chunk-size line
+ if (line = @buffer.readline) =~ /\r\n\z/
+ @chunk_size = line.to_i(16)
+ if @chunk_size > 0
+ sync_buffer
+ else # last-chunk
+ @buffer.read(2) # the final \r\n may or may not be in the buffer
+ sync_buffer
+ @chunk_size = nil
+ @request_complete = true
+ end
+ end
+ end
+ if @chunk_size
+ if @buffer.size >= @chunk_size + 2
+ @request[:body] << @buffer.read(@chunk_size + 2).chop!
+ @chunk_size = nil
+ sync_buffer
+ else
+ break # wait for more data
+ end
+ end
+ end
+ elsif @content_length > 0
+ @buffer.rewind
+ unless @buffer.eof? # buffer only contained the headers
+ @request[:body] << @buffer.read(@content_length - @request[:body].size)
+ sync_buffer
+ if @request[:body].size == @content_length
+ @request_complete = true
+ end
+ end
+ else
+ # no body
+ @request_complete = true
+ end
+ end
+
+ def chunks_for(str)
+ chunks = ''
+ str.force_encoding('BINARY') if str.respond_to?(:force_encoding)
+ chunk_size = str.size / 2
+ until (chunk = str.slice!(0, chunk_size)).empty?
+ chunks << chunk.size.to_s(16) << "\r\n"
+ chunks << chunk << "\r\n"
+ end
+ chunks << "0\r\n" # last-chunk
+ end
+
+ # only supports a single quality parameter for tokens
+ def parse_encodings(encodings)
+ return [] if encodings.nil?
+ split_header_value(encodings).map do |value|
+ token, q_val = /^(.*?)(?:;q=(.*))?$/.match(value.strip)[1, 2]
+ if q_val && q_val.to_f == 0
+ nil
+ else
+ [token, (q_val || 1).to_f]
+ end
+ end.compact.sort_by {|_, q_val| q_val }.map {|token, _| token }
+ end
+
+ # Splits a header value +str+ according to HTTP specification.
+ def split_header_value(str)
+ return [] if str.nil?
+ str.strip.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]+)+)
+ (?:,\s*|\Z)'xn).flatten
+ end
+end
+
+EM.run do
+ EM.start_server("127.0.0.1", 9292, GoodServer)
+ EM.start_server("::1", 9293, GoodServer) unless RUBY_PLATFORM == 'java'
+ $stderr.puts "ready"
+end
diff --git a/lib/vendor/excon/tests/test_helper.rb b/lib/vendor/excon/tests/test_helper.rb
new file mode 100644
index 0000000..a3c6d63
--- /dev/null
+++ b/lib/vendor/excon/tests/test_helper.rb
@@ -0,0 +1,306 @@
+require 'rubygems' if RUBY_VERSION < '1.9'
+require 'bundler/setup'
+require 'excon'
+require 'delorean'
+require 'open4'
+
+Excon.defaults.merge!(
+ :connect_timeout => 5,
+ :read_timeout => 5,
+ :write_timeout => 5
+)
+
+def basic_tests(url = 'http://127.0.0.1:9292', options = {})
+ ([true, false] * 2).combination(2).to_a.uniq.each do |nonblock, persistent|
+ connection = nil
+ test do
+ options = options.merge({:ssl_verify_peer => false, :nonblock => nonblock, :persistent => persistent })
+ connection = Excon.new(url, options)
+ true
+ end
+
+ tests("nonblock => #{nonblock}, persistent => #{persistent}") do
+
+ tests('GET /content-length/100') do
+ response = nil
+
+ tests('response.status').returns(200) do
+ response = connection.request(:method => :get, :path => '/content-length/100')
+
+ response.status
+ end
+
+ tests('response[:status]').returns(200) do
+ response[:status]
+ end
+
+ tests("response.headers['Content-Length']").returns('100') do
+ response.headers['Content-Length']
+ end
+
+ tests("response.headers['Content-Type']").returns('text/html;charset=utf-8') do
+ response.headers['Content-Type']
+ end
+
+ test("Time.parse(response.headers['Date']).is_a?(Time)") do
+ pending if connection.data[:scheme] == Excon::UNIX
+ Time.parse(response.headers['Date']).is_a?(Time)
+ end
+
+ test("!!(response.headers['Server'] =~ /^WEBrick/)") do
+ pending if connection.data[:scheme] == Excon::UNIX
+ !!(response.headers['Server'] =~ /^WEBrick/)
+ end
+
+ tests("response.headers['Custom']").returns("Foo: bar") do
+ response.headers['Custom']
+ end
+
+ tests("response.remote_ip").returns("127.0.0.1") do
+ pending if connection.data[:scheme] == Excon::UNIX
+ response.remote_ip
+ end
+
+ tests("response.body").returns('x' * 100) do
+ response.body
+ end
+
+ tests("deprecated block usage").returns(['x' * 100, 0, 100]) do
+ data = []
+ silence_warnings do
+ connection.request(:method => :get, :path => '/content-length/100') do |chunk, remaining_length, total_length|
+ data = [chunk, remaining_length, total_length]
+ end
+ end
+ data
+ end
+
+ tests("response_block usage").returns(['x' * 100, 0, 100]) do
+ data = []
+ response_block = lambda do |chunk, remaining_length, total_length|
+ data = [chunk, remaining_length, total_length]
+ end
+ connection.request(:method => :get, :path => '/content-length/100', :response_block => response_block)
+ data
+ end
+
+ end
+
+ tests('POST /body-sink') do
+
+ tests('response.body').returns("5000000") do
+ response = connection.request(:method => :post, :path => '/body-sink', :headers => { 'Content-Type' => 'text/plain' }, :body => 'x' * 5_000_000)
+ response.body
+ end
+
+ tests('empty body').returns('0') do
+ response = connection.request(:method => :post, :path => '/body-sink', :headers => { 'Content-Type' => 'text/plain' }, :body => '')
+ response.body
+ end
+
+ end
+
+ tests('POST /echo') do
+
+ tests('with file').returns('x' * 100 + "\n") do
+ file_path = File.join(File.dirname(__FILE__), "data", "xs")
+ response = connection.request(:method => :post, :path => '/echo', :body => File.open(file_path))
+ response.body
+ end
+
+ tests('without request_block').returns('x' * 100) do
+ response = connection.request(:method => :post, :path => '/echo', :body => 'x' * 100)
+ response.body
+ end
+
+ tests('with request_block').returns('x' * 100) do
+ data = ['x'] * 100
+ request_block = lambda do
+ data.shift.to_s
+ end
+ response = connection.request(:method => :post, :path => '/echo', :request_block => request_block)
+ response.body
+ end
+
+ tests('with multi-byte strings') do
+ body = "\xC3\xBC" * 100
+ headers = { 'Custom' => body.dup }
+ if RUBY_VERSION >= '1.9'
+ body.force_encoding('BINARY')
+ headers['Custom'].force_encoding('UTF-8')
+ end
+
+ returns(body, 'properly concatenates request+headers and body') do
+ response = connection.request(:method => :post, :path => '/echo', :headers => headers, :body => body)
+ response.body
+ end
+ end
+
+ end
+
+ tests('PUT /echo') do
+
+ tests('with file').returns('x' * 100 + "\n") do
+ file_path = File.join(File.dirname(__FILE__), "data", "xs")
+ response = connection.request(:method => :put, :path => '/echo', :body => File.open(file_path))
+ response.body
+ end
+
+ tests('without request_block').returns('x' * 100) do
+ response = connection.request(:method => :put, :path => '/echo', :body => 'x' * 100)
+ response.body
+ end
+
+ tests('request_block usage').returns('x' * 100) do
+ data = ['x'] * 100
+ request_block = lambda do
+ data.shift.to_s
+ end
+ response = connection.request(:method => :put, :path => '/echo', :request_block => request_block)
+ response.body
+ end
+
+ tests('with multi-byte strings') do
+ body = "\xC3\xBC" * 100
+ headers = { 'Custom' => body.dup }
+ if RUBY_VERSION >= '1.9'
+ body.force_encoding('BINARY')
+ headers['Custom'].force_encoding('UTF-8')
+ end
+
+ returns(body, 'properly concatenates request+headers and body') do
+ response = connection.request(:method => :put, :path => '/echo', :headers => headers, :body => body)
+ response.body
+ end
+ end
+
+ end
+
+ tests('should succeed with tcp_nodelay').returns(200) do
+ options = options.merge(:ssl_verify_peer => false, :nonblock => nonblock, :tcp_nodelay => true)
+ connection = Excon.new(url, options)
+ response = connection.request(:method => :get, :path => '/content-length/100')
+ response.status
+ end
+
+ end
+ end
+end
+
+
+PROXY_ENV_VARIABLES = %w{http_proxy https_proxy no_proxy} # All lower-case
+
+def env_init(env={})
+ current = {}
+ PROXY_ENV_VARIABLES.each do |key|
+ current[key] = ENV.delete(key)
+ current[key.upcase] = ENV.delete(key.upcase)
+ end
+ env_stack << current
+
+ env.each do |key, value|
+ ENV[key] = value
+ end
+end
+
+def env_restore
+ ENV.update(env_stack.pop)
+end
+
+def env_stack
+ @env_stack ||= []
+end
+
+def silence_warnings
+ orig_verbose = $VERBOSE
+ $VERBOSE = nil
+ yield
+ensure
+ $VERBOSE = orig_verbose
+end
+
+def capture_response_block
+ captures = []
+ yield lambda {|chunk, remaining_bytes, total_bytes|
+ captures << [chunk, remaining_bytes, total_bytes]
+ }
+ captures
+end
+
+def rackup_path(*parts)
+ File.expand_path(File.join(File.dirname(__FILE__), 'rackups', *parts))
+end
+
+def with_rackup(name, host="127.0.0.1")
+ unless RUBY_PLATFORM == 'java'
+ GC.disable if RUBY_VERSION < '1.9'
+ pid, w, r, e = Open4.popen4("rackup", "-s", "webrick", "--host", host, rackup_path(name))
+ else
+ pid, w, r, e = IO.popen4("rackup", "-s", "webrick", "--host", host, rackup_path(name))
+ end
+ until e.gets =~ /HTTPServer#start:/; end
+ yield
+ensure
+ Process.kill(9, pid)
+ unless RUBY_PLATFORM == 'java'
+ GC.enable if RUBY_VERSION < '1.9'
+ Process.wait(pid)
+ end
+
+ # dump server errors
+ lines = e.read.split($/)
+ while line = lines.shift
+ case line
+ when /(ERROR|Error)/
+ unless line =~ /(null cert chain|did not return a certificate|SSL_read:: internal error)/
+ in_err = true
+ puts
+ end
+ when /^(127|localhost)/
+ in_err = false
+ end
+ puts line if in_err
+ end
+end
+
+def with_unicorn(name, listen='127.0.0.1:9292')
+ unless RUBY_PLATFORM == 'java'
+ GC.disable if RUBY_VERSION < '1.9'
+ unix_socket = listen.sub('unix://', '') if listen.start_with? 'unix://'
+ pid, w, r, e = Open4.popen4("unicorn", "--no-default-middleware","-l", listen, rackup_path(name))
+ until e.gets =~ /worker=0 ready/; end
+ else
+ # need to find suitable server for jruby
+ end
+ yield
+ensure
+ unless RUBY_PLATFORM == 'java'
+ Process.kill(9, pid)
+ GC.enable if RUBY_VERSION < '1.9'
+ Process.wait(pid)
+ end
+ if not unix_socket.nil? and File.exist?(unix_socket)
+ File.delete(unix_socket)
+ end
+end
+
+def server_path(*parts)
+ File.expand_path(File.join(File.dirname(__FILE__), 'servers', *parts))
+end
+
+def with_server(name)
+ unless RUBY_PLATFORM == 'java'
+ GC.disable if RUBY_VERSION < '1.9'
+ pid, w, r, e = Open4.popen4(server_path("#{name}.rb"))
+ else
+ pid, w, r, e = IO.popen4(server_path("#{name}.rb"))
+ end
+ until e.gets =~ /ready/; end
+ yield
+ensure
+ Process.kill(9, pid)
+ unless RUBY_PLATFORM == 'java'
+ GC.enable if RUBY_VERSION < '1.9'
+ Process.wait(pid)
+ end
+end
diff --git a/lib/vendor/excon/tests/thread_safety_tests.rb b/lib/vendor/excon/tests/thread_safety_tests.rb
new file mode 100644
index 0000000..32a76e0
--- /dev/null
+++ b/lib/vendor/excon/tests/thread_safety_tests.rb
@@ -0,0 +1,39 @@
+Shindo.tests('Excon thread safety') do
+
+ tests('thread_safe_sockets configuration') do
+ tests('thread_safe_sockets default').returns(true) do
+ connection = Excon.new('http://foo.com')
+ connection.data[:thread_safe_sockets]
+ end
+
+ tests('with thread_safe_sockets set false').returns(false) do
+ connection = Excon.new('http://foo.com', :thread_safe_sockets => false)
+ connection.data[:thread_safe_sockets]
+ end
+ end
+
+ with_rackup('thread_safety.ru') do
+ connection = Excon.new('http://127.0.0.1:9292')
+
+ long_thread = Thread.new {
+ response = connection.request(:method => 'GET', :path => '/id/1/wait/2')
+ Thread.current[:success] = response.body == '1'
+ }
+
+ short_thread = Thread.new {
+ response = connection.request(:method => 'GET', :path => '/id/2/wait/1')
+ Thread.current[:success] = response.body == '2'
+ }
+
+ test('long_thread') do
+ long_thread.join
+ short_thread.join
+
+ long_thread[:success]
+ end
+
+ test('short_thread') do
+ short_thread[:success]
+ end
+ end
+end
diff --git a/lib/vendor/excon/tests/timeout_tests.rb b/lib/vendor/excon/tests/timeout_tests.rb
new file mode 100644
index 0000000..88a5706
--- /dev/null
+++ b/lib/vendor/excon/tests/timeout_tests.rb
@@ -0,0 +1,12 @@
+Shindo.tests('read should timeout') do
+ with_rackup('timeout.ru') do
+
+ [false, true].each do |nonblock|
+ tests("nonblock => #{nonblock} hits read_timeout").raises(Excon::Errors::Timeout) do
+ connection = Excon.new('http://127.0.0.1:9292', :nonblock => nonblock)
+ connection.request(:method => :get, :path => '/timeout', :read_timeout => 1)
+ end
+ end
+
+ end
+end
diff --git a/lib/vendor/excon/tests/utils_tests.rb b/lib/vendor/excon/tests/utils_tests.rb
new file mode 100644
index 0000000..65f0382
--- /dev/null
+++ b/lib/vendor/excon/tests/utils_tests.rb
@@ -0,0 +1,81 @@
+Shindo.tests('Excon::Utils') do
+
+ tests('#connection_uri') do
+
+ expected_uri = 'unix:///tmp/some.sock'
+ tests('using UNIX scheme').returns(expected_uri) do
+ connection = Excon.new('unix:///some/path', :socket => '/tmp/some.sock')
+ Excon::Utils.connection_uri(connection.data)
+ end
+
+ tests('using HTTP scheme') do
+
+ expected_uri = 'http://foo.com:80'
+ tests('with default port').returns(expected_uri) do
+ connection = Excon.new('http://foo.com/some/path')
+ Excon::Utils.connection_uri(connection.data)
+ end
+
+ expected_uri = 'http://foo.com'
+ tests('without default port').returns(expected_uri) do
+ connection = Excon.new('http://foo.com/some/path', :omit_default_port => true)
+ Excon::Utils.connection_uri(connection.data)
+ end
+
+ end
+
+ end
+
+ tests('#request_uri') do
+
+ tests('using UNIX scheme') do
+
+ expected_uri = 'unix:///tmp/some.sock/some/path'
+ tests('without query').returns(expected_uri) do
+ connection = Excon.new('unix:/', :socket => '/tmp/some.sock')
+ params = { :path => '/some/path' }
+ Excon::Utils.request_uri(connection.data.merge(params))
+ end
+
+ expected_uri = 'unix:///tmp/some.sock/some/path?bar=that&foo=this'
+ tests('with query').returns(expected_uri) do
+ connection = Excon.new('unix:/', :socket => '/tmp/some.sock')
+ params = { :path => '/some/path', :query => { :foo => 'this', :bar => 'that' } }
+ Excon::Utils.request_uri(connection.data.merge(params))
+ end
+
+ end
+
+ tests('using HTTP scheme') do
+
+ expected_uri = 'http://foo.com:80/some/path'
+ tests('without query').returns(expected_uri) do
+ connection = Excon.new('http://foo.com')
+ params = { :path => '/some/path' }
+ Excon::Utils.request_uri(connection.data.merge(params))
+ end
+
+ expected_uri = 'http://foo.com:80/some/path?bar=that&foo=this'
+ tests('with query').returns(expected_uri) do
+ connection = Excon.new('http://foo.com')
+ params = { :path => '/some/path', :query => { :foo => 'this', :bar => 'that' } }
+ Excon::Utils.request_uri(connection.data.merge(params))
+ end
+
+ end
+
+ end
+
+ tests('#escape_uri').returns('/hello%20excon') do
+ Excon::Utils.escape_uri('/hello excon')
+ end
+
+ tests('#unescape_uri').returns('/hello excon') do
+ Excon::Utils.unescape_uri('/hello%20excon')
+ end
+
+ tests('#unescape_form').returns('message=We love excon!') do
+ Excon::Utils.unescape_form('message=We+love+excon!')
+ end
+
+end