excon 0.31.0 → 0.32.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of excon might be problematic. Click here for more details.

@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'excon'
16
- s.version = '0.31.0'
17
- s.date = '2013-12-16'
16
+ s.version = '0.32.0'
17
+ s.date = '2014-02-27'
18
18
  s.rubyforge_project = 'excon'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -68,8 +68,11 @@ Gem::Specification.new do |s|
68
68
  ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
69
69
  # = MANIFEST =
70
70
  s.files = %w[
71
+ CONTRIBUTING.md
72
+ CONTRIBUTORS.md
71
73
  Gemfile
72
74
  Gemfile.lock
75
+ LICENSE.md
73
76
  README.md
74
77
  Rakefile
75
78
  benchmarks/class_vs_lambda.rb
@@ -99,6 +102,7 @@ Gem::Specification.new do |s|
99
102
  lib/excon/errors.rb
100
103
  lib/excon/middlewares/base.rb
101
104
  lib/excon/middlewares/decompress.rb
105
+ lib/excon/middlewares/escape_path.rb
102
106
  lib/excon/middlewares/expects.rb
103
107
  lib/excon/middlewares/idempotent.rb
104
108
  lib/excon/middlewares/instrumentor.rb
@@ -121,6 +125,7 @@ Gem::Specification.new do |s|
121
125
  tests/header_tests.rb
122
126
  tests/middlewares/canned_response_tests.rb
123
127
  tests/middlewares/decompress_tests.rb
128
+ tests/middlewares/escape_path_tests.rb
124
129
  tests/middlewares/idempotent_tests.rb
125
130
  tests/middlewares/instrumentation_tests.rb
126
131
  tests/middlewares/mock_tests.rb
@@ -11,8 +11,6 @@ require 'uri'
11
11
  require 'zlib'
12
12
  require 'stringio'
13
13
 
14
- BasicSocket.do_not_reverse_lookup = true
15
-
16
14
  # Define defaults first so they will be available to other files
17
15
  module Excon
18
16
  class << self
@@ -65,6 +63,7 @@ require 'excon/connection'
65
63
  require 'excon/errors'
66
64
  require 'excon/middlewares/base'
67
65
  require 'excon/middlewares/decompress'
66
+ require 'excon/middlewares/escape_path'
68
67
  require 'excon/middlewares/expects'
69
68
  require 'excon/middlewares/idempotent'
70
69
  require 'excon/middlewares/instrumentor'
@@ -269,7 +269,7 @@ module Excon
269
269
 
270
270
  if datum[:persistent]
271
271
  if key = datum[:response][:headers].keys.detect {|k| k.casecmp('Connection') == 0 }
272
- if split_header_value(datum[:response][:headers][key]).any? {|t| t.casecmp('close') }
272
+ if split_header_value(datum[:response][:headers][key]).any? {|t| t.casecmp('close') == 0 }
273
273
  reset
274
274
  end
275
275
  end
@@ -305,7 +305,7 @@ module Excon
305
305
 
306
306
  if @data[:persistent]
307
307
  if key = responses.last[:headers].keys.detect {|k| k.casecmp('Connection') == 0 }
308
- if split_header_value(responses.last[:headers][key]).any? {|t| t.casecmp('close') }
308
+ if split_header_value(responses.last[:headers][key]).any? {|t| t.casecmp('close') == 0 }
309
309
  reset
310
310
  end
311
311
  end
@@ -1,6 +1,6 @@
1
1
  module Excon
2
2
 
3
- VERSION = '0.31.0'
3
+ VERSION = '0.32.0'
4
4
 
5
5
  CR_NL = "\r\n"
6
6
 
@@ -70,6 +70,7 @@ module Excon
70
70
  :host,
71
71
  :omit_default_port,
72
72
  :nonblock,
73
+ :reuseaddr,
73
74
  :password,
74
75
  :port,
75
76
  :proxy,
@@ -0,0 +1,11 @@
1
+ module Excon
2
+ module Middleware
3
+ class EscapePath < Excon::Middleware::Base
4
+ def request_call(datum)
5
+ # make sure path is encoded, prevent double encoding
6
+ datum[:path] = Excon::Utils.escape_uri(Excon::Utils.unescape_uri(datum[:path]))
7
+ @stack.request_call(datum)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -28,6 +28,12 @@ module Excon
28
28
  def remote_ip
29
29
  @data[:remote_ip]
30
30
  end
31
+ def local_port
32
+ @data[:local_port]
33
+ end
34
+ def local_address
35
+ @data[:local_address]
36
+ end
31
37
 
32
38
  def self.parse(socket, datum)
33
39
  # this will discard any trailing lines from the previous response if any.
@@ -35,10 +41,12 @@ module Excon
35
41
  status = match[1].to_i
36
42
 
37
43
  datum[:response] = {
38
- :body => '',
39
- :headers => {},
40
- :status => status,
41
- :remote_ip => socket.respond_to?(:remote_ip) && socket.remote_ip
44
+ :body => '',
45
+ :headers => {},
46
+ :status => status,
47
+ :remote_ip => socket.respond_to?(:remote_ip) && socket.remote_ip,
48
+ :local_port => socket.respond_to?(:local_port) && socket.local_port,
49
+ :local_address => socket.respond_to?(:local_address) && socket.local_address
42
50
  }
43
51
 
44
52
  parse_headers(socket, datum)
@@ -126,10 +134,12 @@ module Excon
126
134
  :body => '',
127
135
  :headers => {}
128
136
  }.merge(params)
129
- @body = @data[:body]
130
- @headers = @data[:headers]
131
- @status = @data[:status]
132
- @remote_ip = @data[:remote_ip]
137
+ @body = @data[:body]
138
+ @headers = @data[:headers]
139
+ @status = @data[:status]
140
+ @remote_ip = @data[:remote_ip]
141
+ @local_port = @data[:local_port]
142
+ @local_address = @data[:local_address]
133
143
  end
134
144
 
135
145
  def [](key)
@@ -145,24 +145,40 @@ module Excon
145
145
  @socket.write(data)
146
146
  end
147
147
  rescue Timeout::Error
148
- Excon::Errors::Timeout.new('write timeout reached')
148
+ raise(Excon::Errors::Timeout.new('write timeout reached'))
149
149
  end
150
150
  end
151
151
  end
152
152
 
153
+ def local_port
154
+ ::Socket.unpack_sockaddr_in(@socket.to_io.getsockname)[0]
155
+ rescue ArgumentError => e
156
+ raise unless e.message == 'not an AF_INET/AF_INET6 sockaddr'
157
+ end
158
+
159
+ def local_address
160
+ ::Socket.unpack_sockaddr_in(@socket.to_io.getsockname)[1]
161
+ rescue ArgumentError => e
162
+ raise unless e.message == 'not an AF_INET/AF_INET6 sockaddr'
163
+ end
164
+
153
165
  private
154
166
 
155
167
  def connect
156
168
  @socket = nil
157
169
  exception = nil
158
170
 
159
- addrinfo = if @data[:proxy]
171
+ if @data[:proxy]
160
172
  family = @data[:proxy][:family] || ::Socket::Constants::AF_UNSPEC
161
- ::Socket.getaddrinfo(@data[:proxy][:host], @data[:proxy][:port], family, ::Socket::Constants::SOCK_STREAM)
173
+ args = [@data[:proxy][:host], @data[:proxy][:port], family, ::Socket::Constants::SOCK_STREAM]
162
174
  else
163
175
  family = @data[:family] || ::Socket::Constants::AF_UNSPEC
164
- ::Socket.getaddrinfo(@data[:host], @data[:port], family, ::Socket::Constants::SOCK_STREAM)
176
+ args = [@data[:host], @data[:port], family, ::Socket::Constants::SOCK_STREAM]
165
177
  end
178
+ if RUBY_VERSION >= '1.9.2' && defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby'
179
+ args << nil << nil << false # no reverse lookup
180
+ end
181
+ addrinfo = ::Socket.getaddrinfo(*args)
166
182
 
167
183
  addrinfo.each do |_, port, _, ip, a_family, s_type|
168
184
  @remote_ip = ip
@@ -173,16 +189,23 @@ module Excon
173
189
 
174
190
  socket = ::Socket.new(a_family, s_type, 0)
175
191
 
176
- if @nonblock
177
- socket.connect_nonblock(sockaddr)
178
- else
179
- begin
180
- Timeout.timeout(@data[:connect_timeout]) do
192
+ if @data[:reuseaddr]
193
+ socket.setsockopt(::Socket::Constants::SOL_SOCKET, ::Socket::Constants::SO_REUSEADDR, true)
194
+ if defined?(::Socket::Constants::SO_REUSEPORT)
195
+ socket.setsockopt(::Socket::Constants::SOL_SOCKET, ::Socket::Constants::SO_REUSEPORT, true)
196
+ end
197
+ end
198
+
199
+ begin
200
+ Timeout.timeout(@data[:connect_timeout]) do
201
+ if @nonblock
202
+ socket.connect_nonblock(sockaddr)
203
+ else
181
204
  socket.connect(sockaddr)
182
205
  end
183
- rescue Timeout::Error
184
- raise Excon::Errors::Timeout.new('connect timeout reached')
185
206
  end
207
+ rescue Timeout::Error
208
+ raise Excon::Errors::Timeout.new('connect timeout reached')
186
209
  end
187
210
 
188
211
  @socket = socket
@@ -10,8 +10,21 @@ module Excon
10
10
 
11
11
  # create ssl context
12
12
  ssl_context = OpenSSL::SSL::SSLContext.new
13
+
14
+ # disable less secure options, when supported
15
+ ssl_context_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
16
+ if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
17
+ ssl_context_options &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS
18
+ end
19
+ if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
20
+ ssl_context_options |= OpenSSL::SSL::OP_NO_COMPRESSION
21
+ end
22
+ ssl_context.options = ssl_context_options
23
+
13
24
  ssl_context.ciphers = @data[:ciphers]
14
- ssl_context.ssl_version = @data[:ssl_version] if @data[:ssl_version]
25
+ if @data[:ssl_version]
26
+ ssl_context.ssl_version = @data[:ssl_version]
27
+ end
15
28
  if @data[:ssl_verify_peer]
16
29
  # turn verification on
17
30
  ssl_context.verify_mode = OpenSSL::SSL::VERIFY_PEER
@@ -74,7 +87,27 @@ module Excon
74
87
  # convert Socket to OpenSSL::SSL::SSLSocket
75
88
  @socket = OpenSSL::SSL::SSLSocket.new(@socket, ssl_context)
76
89
  @socket.sync_close = true
77
- @socket.connect
90
+ begin
91
+ Timeout.timeout(@data[:connect_timeout]) do
92
+ if @nonblock
93
+ while true
94
+ begin
95
+ @socket.connect_nonblock
96
+ break # connect succeeded
97
+ rescue OpenSSL::SSL::SSLError => error
98
+ # would block, rescue and retry as select is non-helpful
99
+ unless error.message == 'read would block'
100
+ raise error
101
+ end
102
+ end
103
+ end
104
+ else
105
+ @socket.connect
106
+ end
107
+ end
108
+ rescue Timeout::Error
109
+ raise Excon::Errors::Timeout.new('connect timeout reached')
110
+ end
78
111
 
79
112
  # Server Name Indication (SNI) RFC 3546
80
113
  if @socket.respond_to?(:hostname=)
@@ -2,7 +2,12 @@ module Excon
2
2
  module Utils
3
3
  extend self
4
4
 
5
- ESCAPED = /%([0-9a-fA-F]{2})/
5
+ control = (0x0..0x1f).map {|c| c.chr }.join + "\x7f"
6
+ delims = '<>#%"'
7
+ unwise = '{}|\\^[]`'
8
+ nonascii = (0x80..0xff).map {|c| c.chr }.join
9
+ UNESCAPED = /([#{ Regexp.escape(control + ' ' + delims + unwise + nonascii) }])/
10
+ ESCAPED = /%([0-9a-fA-F]{2})/
6
11
 
7
12
  def valid_connection_keys(params = {})
8
13
  Excon::VALID_CONNECTION_KEYS
@@ -65,6 +70,14 @@ module Excon
65
70
  (?:,\s*|\Z)'xn).flatten
66
71
  end
67
72
 
73
+ # Escapes HTTP reserved and unwise characters in +str+
74
+ def escape_uri(str)
75
+ str = str.dup
76
+ str.force_encoding('BINARY') if FORCE_ENC
77
+ str.gsub!(UNESCAPED) { "%%%02X" % $1[0].ord }
78
+ str
79
+ end
80
+
68
81
  # Unescapes HTTP reserved and unwise characters in +str+
69
82
  def unescape_uri(str)
70
83
  str = str.dup
@@ -119,3 +119,72 @@ Shindo.tests('Excon basics (Unix socket)') do
119
119
  end
120
120
  end
121
121
  end
122
+
123
+ Shindo.tests('Excon basics (reusable local port)') do
124
+ class CustomSocket < Socket
125
+ def initialize
126
+ super(AF_INET, SOCK_STREAM, 0)
127
+ setsockopt(SOL_SOCKET, SO_REUSEADDR, true)
128
+ if defined?(SO_REUSEPORT)
129
+ setsockopt(SOL_SOCKET, SO_REUSEPORT, true)
130
+ end
131
+ end
132
+
133
+ def bind(address, port)
134
+ super(Socket.pack_sockaddr_in(port, address))
135
+ end
136
+
137
+ def connect(address, port)
138
+ super(Socket.pack_sockaddr_in(port, address))
139
+ end
140
+
141
+ def http_get(path)
142
+ print "GET /content-length/10 HTTP/1.0\r\n\r\n"
143
+ read.split("\r\n\r\n", 2)[1]
144
+ end
145
+
146
+ def self.ip_address_list
147
+ if Socket.respond_to?(:ip_address_list)
148
+ Socket.ip_address_list.select(&:ipv4?).map(&:ip_address)
149
+ else
150
+ `ifconfig`.scan(/inet.*?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/).flatten
151
+ end
152
+ end
153
+
154
+ def self.find_alternate_ip(ip)
155
+ ip_address_list.detect {|a| a != ip } || '127.0.0.1'
156
+ end
157
+ end
158
+
159
+ with_rackup('basic.ru') do
160
+ connection = Excon.new("http://127.0.0.1:9292/echo",
161
+ :reuseaddr => true, # enable address and port reuse
162
+ :persistent => true # keep the socket open
163
+ )
164
+ response = connection.get
165
+
166
+ tests('has a local port').returns(true) do
167
+ response.local_port.to_s =~ /\d{4,5}/ ? true : false
168
+ end
169
+
170
+ tests('local port can be re-bound').returns('x' * 10) do
171
+ # create a socket with address/port reuse enabled
172
+ s = CustomSocket.new
173
+
174
+ # bind to the same local port and address used in the get above (won't work without reuse options on both sockets)
175
+ s.bind(response.local_address, response.local_port)
176
+
177
+ # 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}
178
+ s.connect(CustomSocket.find_alternate_ip(response.local_address), 9292)
179
+
180
+ # send the request
181
+ body = s.http_get("/content-length/10")
182
+
183
+ # close both the sockets
184
+ s.close
185
+ connection.reset
186
+
187
+ body
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,34 @@
1
+ Shindo.tests('Excon Decompress Middleware') do
2
+ env_init
3
+ with_rackup('basic.ru') do
4
+ tests('encoded uri passed to connection') do
5
+ tests('GET /echo%20dirty').returns(200) do
6
+ connection = Excon::Connection.new({
7
+ :host => '127.0.0.1',
8
+ :middlewares => Excon.defaults[:middlewares] + [Excon::Middleware::EscapePath],
9
+ :nonblock => false,
10
+ :port => 9292,
11
+ :scheme => 'http',
12
+ :ssl_verify_peer => false
13
+ })
14
+ response = connection.request(:method => :get, :path => '/echo%20dirty')
15
+ response[:status]
16
+ end
17
+ end
18
+
19
+ tests('unencoded uri passed to connection') do
20
+ tests('GET /echo dirty').returns(200) do
21
+ connection = Excon::Connection.new({
22
+ :host => '127.0.0.1',
23
+ :middlewares => Excon.defaults[:middlewares] + [Excon::Middleware::EscapePath],
24
+ :nonblock => false,
25
+ :port => 9292,
26
+ :scheme => 'http',
27
+ :ssl_verify_peer => false
28
+ })
29
+ response = connection.request(:method => :get, :path => '/echo dirty')
30
+ response[:status]
31
+ end
32
+ end
33
+ end
34
+ end
@@ -22,6 +22,10 @@ class Basic < Sinatra::Base
22
22
  echo
23
23
  end
24
24
 
25
+ get('/echo dirty') do
26
+ echo
27
+ end
28
+
25
29
  private
26
30
 
27
31
  def echo
@@ -34,6 +34,7 @@ module GoodServer
34
34
  (@request_count ||= '0').next!
35
35
  start_response
36
36
  send_data "Content-Length: #{ @request_count.size }\r\n"
37
+ send_data "Connection: Keep-Alive\r\n"
37
38
  send_data "\r\n"
38
39
  send_data @request_count
39
40
 
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: excon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.31.0
5
- prerelease:
4
+ version: 0.32.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - dpiddy (Dan Peterson)
@@ -11,12 +10,11 @@ authors:
11
10
  autorequire:
12
11
  bindir: bin
13
12
  cert_chain: []
14
- date: 2013-12-16 00:00:00.000000000 Z
13
+ date: 2014-02-27 00:00:00.000000000 Z
15
14
  dependencies:
16
15
  - !ruby/object:Gem::Dependency
17
16
  name: activesupport
18
17
  requirement: !ruby/object:Gem::Requirement
19
- none: false
20
18
  requirements:
21
19
  - - ! '>='
22
20
  - !ruby/object:Gem::Version
@@ -24,7 +22,6 @@ dependencies:
24
22
  type: :development
25
23
  prerelease: false
26
24
  version_requirements: !ruby/object:Gem::Requirement
27
- none: false
28
25
  requirements:
29
26
  - - ! '>='
30
27
  - !ruby/object:Gem::Version
@@ -32,7 +29,6 @@ dependencies:
32
29
  - !ruby/object:Gem::Dependency
33
30
  name: delorean
34
31
  requirement: !ruby/object:Gem::Requirement
35
- none: false
36
32
  requirements:
37
33
  - - ! '>='
38
34
  - !ruby/object:Gem::Version
@@ -40,7 +36,6 @@ dependencies:
40
36
  type: :development
41
37
  prerelease: false
42
38
  version_requirements: !ruby/object:Gem::Requirement
43
- none: false
44
39
  requirements:
45
40
  - - ! '>='
46
41
  - !ruby/object:Gem::Version
@@ -48,7 +43,6 @@ dependencies:
48
43
  - !ruby/object:Gem::Dependency
49
44
  name: eventmachine
50
45
  requirement: !ruby/object:Gem::Requirement
51
- none: false
52
46
  requirements:
53
47
  - - ! '>='
54
48
  - !ruby/object:Gem::Version
@@ -56,7 +50,6 @@ dependencies:
56
50
  type: :development
57
51
  prerelease: false
58
52
  version_requirements: !ruby/object:Gem::Requirement
59
- none: false
60
53
  requirements:
61
54
  - - ! '>='
62
55
  - !ruby/object:Gem::Version
@@ -64,7 +57,6 @@ dependencies:
64
57
  - !ruby/object:Gem::Dependency
65
58
  name: open4
66
59
  requirement: !ruby/object:Gem::Requirement
67
- none: false
68
60
  requirements:
69
61
  - - ! '>='
70
62
  - !ruby/object:Gem::Version
@@ -72,7 +64,6 @@ dependencies:
72
64
  type: :development
73
65
  prerelease: false
74
66
  version_requirements: !ruby/object:Gem::Requirement
75
- none: false
76
67
  requirements:
77
68
  - - ! '>='
78
69
  - !ruby/object:Gem::Version
@@ -80,7 +71,6 @@ dependencies:
80
71
  - !ruby/object:Gem::Dependency
81
72
  name: rake
82
73
  requirement: !ruby/object:Gem::Requirement
83
- none: false
84
74
  requirements:
85
75
  - - ! '>='
86
76
  - !ruby/object:Gem::Version
@@ -88,7 +78,6 @@ dependencies:
88
78
  type: :development
89
79
  prerelease: false
90
80
  version_requirements: !ruby/object:Gem::Requirement
91
- none: false
92
81
  requirements:
93
82
  - - ! '>='
94
83
  - !ruby/object:Gem::Version
@@ -96,7 +85,6 @@ dependencies:
96
85
  - !ruby/object:Gem::Dependency
97
86
  name: rdoc
98
87
  requirement: !ruby/object:Gem::Requirement
99
- none: false
100
88
  requirements:
101
89
  - - ! '>='
102
90
  - !ruby/object:Gem::Version
@@ -104,7 +92,6 @@ dependencies:
104
92
  type: :development
105
93
  prerelease: false
106
94
  version_requirements: !ruby/object:Gem::Requirement
107
- none: false
108
95
  requirements:
109
96
  - - ! '>='
110
97
  - !ruby/object:Gem::Version
@@ -112,7 +99,6 @@ dependencies:
112
99
  - !ruby/object:Gem::Dependency
113
100
  name: shindo
114
101
  requirement: !ruby/object:Gem::Requirement
115
- none: false
116
102
  requirements:
117
103
  - - ! '>='
118
104
  - !ruby/object:Gem::Version
@@ -120,7 +106,6 @@ dependencies:
120
106
  type: :development
121
107
  prerelease: false
122
108
  version_requirements: !ruby/object:Gem::Requirement
123
- none: false
124
109
  requirements:
125
110
  - - ! '>='
126
111
  - !ruby/object:Gem::Version
@@ -128,7 +113,6 @@ dependencies:
128
113
  - !ruby/object:Gem::Dependency
129
114
  name: sinatra
130
115
  requirement: !ruby/object:Gem::Requirement
131
- none: false
132
116
  requirements:
133
117
  - - ! '>='
134
118
  - !ruby/object:Gem::Version
@@ -136,7 +120,6 @@ dependencies:
136
120
  type: :development
137
121
  prerelease: false
138
122
  version_requirements: !ruby/object:Gem::Requirement
139
- none: false
140
123
  requirements:
141
124
  - - ! '>='
142
125
  - !ruby/object:Gem::Version
@@ -148,8 +131,11 @@ extensions: []
148
131
  extra_rdoc_files:
149
132
  - README.md
150
133
  files:
134
+ - CONTRIBUTING.md
135
+ - CONTRIBUTORS.md
151
136
  - Gemfile
152
137
  - Gemfile.lock
138
+ - LICENSE.md
153
139
  - README.md
154
140
  - Rakefile
155
141
  - benchmarks/class_vs_lambda.rb
@@ -179,6 +165,7 @@ files:
179
165
  - lib/excon/errors.rb
180
166
  - lib/excon/middlewares/base.rb
181
167
  - lib/excon/middlewares/decompress.rb
168
+ - lib/excon/middlewares/escape_path.rb
182
169
  - lib/excon/middlewares/expects.rb
183
170
  - lib/excon/middlewares/idempotent.rb
184
171
  - lib/excon/middlewares/instrumentor.rb
@@ -201,6 +188,7 @@ files:
201
188
  - tests/header_tests.rb
202
189
  - tests/middlewares/canned_response_tests.rb
203
190
  - tests/middlewares/decompress_tests.rb
191
+ - tests/middlewares/escape_path_tests.rb
204
192
  - tests/middlewares/idempotent_tests.rb
205
193
  - tests/middlewares/instrumentation_tests.rb
206
194
  - tests/middlewares/mock_tests.rb
@@ -237,29 +225,25 @@ files:
237
225
  homepage: https://github.com/geemus/excon
238
226
  licenses:
239
227
  - MIT
228
+ metadata: {}
240
229
  post_install_message:
241
230
  rdoc_options:
242
231
  - --charset=UTF-8
243
232
  require_paths:
244
233
  - lib
245
234
  required_ruby_version: !ruby/object:Gem::Requirement
246
- none: false
247
235
  requirements:
248
236
  - - ! '>='
249
237
  - !ruby/object:Gem::Version
250
238
  version: '0'
251
- segments:
252
- - 0
253
- hash: -1399644688570873046
254
239
  required_rubygems_version: !ruby/object:Gem::Requirement
255
- none: false
256
240
  requirements:
257
241
  - - ! '>='
258
242
  - !ruby/object:Gem::Version
259
243
  version: '0'
260
244
  requirements: []
261
245
  rubyforge_project: excon
262
- rubygems_version: 1.8.23
246
+ rubygems_version: 2.2.2
263
247
  signing_key:
264
248
  specification_version: 2
265
249
  summary: speed, persistence, http(s)