excon 0.51.0 → 0.52.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.

Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -1
  3. data/Gemfile.lock +19 -2
  4. data/Rakefile +11 -1
  5. data/benchmarks/concat_vs_interpolate.rb +6 -5
  6. data/changelog.txt +9 -0
  7. data/excon.gemspec +11 -2
  8. data/lib/excon.rb +3 -2
  9. data/lib/excon/connection.rb +16 -17
  10. data/lib/excon/constants.rb +4 -3
  11. data/lib/excon/error.rb +6 -5
  12. data/lib/excon/extensions/uri.rb +1 -0
  13. data/lib/excon/headers.rb +1 -0
  14. data/lib/excon/middlewares/base.rb +1 -0
  15. data/lib/excon/middlewares/capture_cookies.rb +1 -0
  16. data/lib/excon/middlewares/decompress.rb +1 -0
  17. data/lib/excon/middlewares/escape_path.rb +1 -0
  18. data/lib/excon/middlewares/expects.rb +1 -0
  19. data/lib/excon/middlewares/idempotent.rb +1 -0
  20. data/lib/excon/middlewares/instrumentor.rb +1 -0
  21. data/lib/excon/middlewares/mock.rb +1 -0
  22. data/lib/excon/middlewares/redirect_follower.rb +1 -0
  23. data/lib/excon/middlewares/response_parser.rb +1 -0
  24. data/lib/excon/pretty_printer.rb +1 -0
  25. data/lib/excon/response.rb +2 -1
  26. data/lib/excon/socket.rb +3 -2
  27. data/lib/excon/ssl_socket.rb +8 -7
  28. data/lib/excon/standard_instrumentor.rb +1 -0
  29. data/lib/excon/test/plugin/server/exec.rb +23 -0
  30. data/lib/excon/test/plugin/server/puma.rb +21 -0
  31. data/lib/excon/test/plugin/server/unicorn.rb +35 -0
  32. data/lib/excon/test/plugin/server/webrick.rb +23 -0
  33. data/lib/excon/test/server.rb +107 -0
  34. data/lib/excon/unix_socket.rb +1 -0
  35. data/lib/excon/utils.rb +6 -5
  36. data/spec/excon_spec.rb +7 -0
  37. data/spec/excon_test_server_spec.rb +51 -0
  38. data/spec/spec_helper.rb +126 -0
  39. data/tests/authorization_header_tests.rb +0 -4
  40. data/tests/basic_tests.rb +16 -3
  41. data/tests/middlewares/instrumentation_tests.rb +5 -2
  42. data/tests/test_helper.rb +2 -2
  43. metadata +24 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a5c097ca48adbd9359207000df88072d4642eff7
4
- data.tar.gz: 5286fc8951d6efb9cb2395083532a155e57a0321
3
+ metadata.gz: a4fbd928d58bcca49ade92b992e6081c499c5953
4
+ data.tar.gz: ffd6ef0ea40f00bae7370651713d1838da818cbb
5
5
  SHA512:
6
- metadata.gz: 5669c2d1f478f3e42f2b9d2a00d66d40c800b415b9ed0b78807b10e2954656c56fc669f500612d582888ccfb3537a96367befef6c6e70c5f37a0bf67f27362e7
7
- data.tar.gz: 119b797537e7f9509534b4c4a5db74737b360589f4ccf2939f9bc32dbc208ed3d6cab48679bc3ca159fd0ae85af917dfd87628f9d29663e361baebcf3d0b87e4
6
+ metadata.gz: ec4376d34c259d5a1db8b9f5ec85484ce8a26e22e41a737feb2c4ca584441bfeed0e51d9528c1c0b4213406047398b1af25052f4a64203750aab7bfd346435c3
7
+ data.tar.gz: 049b675e456d193711f65a39c087d86d04e015dff34e0a9e30b8f04e089cf09f935f46aa21ad5f25cfa95123e5fd9ad6ca1525c3bd719aee1f6db8f11ef11632
data/Gemfile CHANGED
@@ -3,7 +3,8 @@ source "http://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  gem 'jruby-openssl', :platform => :jruby
6
- gem 'unicorn', :platforms => [:mri, :rbx]
6
+ gem 'puma', :groups => [:development, :test]
7
+ gem 'unicorn', :platforms => [:mri, :rbx], :groups => [:development, :test]
7
8
  gem 'rubysl', '~> 2.0', :platform => :rbx
8
9
  gem 'rack', '~> 1.6'
9
10
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- excon (0.51.0)
4
+ excon (0.52.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
@@ -14,6 +14,7 @@ GEM
14
14
  chronic (0.6.7)
15
15
  delorean (2.0.0)
16
16
  chronic
17
+ diff-lcs (1.2.5)
17
18
  eventmachine (1.0.4)
18
19
  eventmachine (1.0.4-java)
19
20
  ffi2-generators (0.1.1)
@@ -27,6 +28,7 @@ GEM
27
28
  minitest (4.7.5)
28
29
  multi_json (1.3.6)
29
30
  open4 (1.3.0)
31
+ puma (3.6.0)
30
32
  rack (1.6.0)
31
33
  rack-protection (1.2.0)
32
34
  rack
@@ -36,6 +38,19 @@ GEM
36
38
  rake (0.9.2.2)
37
39
  rdoc (3.12)
38
40
  json (~> 1.4)
41
+ rspec (3.5.0)
42
+ rspec-core (~> 3.5.0)
43
+ rspec-expectations (~> 3.5.0)
44
+ rspec-mocks (~> 3.5.0)
45
+ rspec-core (3.5.0)
46
+ rspec-support (~> 3.5.0)
47
+ rspec-expectations (3.5.0)
48
+ diff-lcs (>= 1.2.0, < 2.0)
49
+ rspec-support (~> 3.5.0)
50
+ rspec-mocks (3.5.0)
51
+ diff-lcs (>= 1.2.0, < 2.0)
52
+ rspec-support (~> 3.5.0)
53
+ rspec-support (3.5.0)
39
54
  rubysl (2.0.14)
40
55
  rubysl-abbrev (~> 2.0)
41
56
  rubysl-base64 (~> 2.0)
@@ -272,9 +287,11 @@ DEPENDENCIES
272
287
  jruby-openssl
273
288
  json (>= 1.8.2)
274
289
  open4
290
+ puma
275
291
  rack (~> 1.6)
276
292
  rake
277
293
  rdoc
294
+ rspec (>= 3.5.0)
278
295
  rubysl (~> 2.0)
279
296
  shindo
280
297
  sinatra
@@ -282,4 +299,4 @@ DEPENDENCIES
282
299
  unicorn
283
300
 
284
301
  BUNDLED WITH
285
- 1.11.2
302
+ 1.12.5
data/Rakefile CHANGED
@@ -44,9 +44,19 @@ end
44
44
  #############################################################################
45
45
 
46
46
  require 'shindo/rake'
47
+ require "rspec/core/rake_task"
48
+
49
+ RSpec::Core::RakeTask.new(:spec, :format) do |t, args|
50
+ format = args[:format] || 'doc'
51
+ t.rspec_opts = ["-c", "-f #{format}", "-r ./spec/spec_helper.rb"]
52
+ t.pattern = 'spec/**/*_spec.rb'
53
+ end
54
+
55
+
47
56
  Shindo::Rake.new
48
57
 
49
- task :default => :tests
58
+ task :default => [ :tests, :test]
59
+ task :test => :spec
50
60
 
51
61
  require 'rdoc/task'
52
62
  Rake::RDocTask.new do |rdoc|
@@ -5,17 +5,18 @@ key = 'Content-Length'
5
5
  value = '100'
6
6
  Tach.meter(1_000) do
7
7
  tach('concat') do
8
- key << ': ' << value << "\r\n"
8
+ temp = ''
9
+ temp << key << ': ' << value << "\r\n"
9
10
  end
10
11
  tach('interpolate') do
11
- "#{key}: value\r\n"
12
+ "#{key}: #{value}\r\n"
12
13
  end
13
14
  end
14
15
 
15
16
  # +-------------+----------+
16
17
  # | tach | total |
17
18
  # +-------------+----------+
18
- # | concat | 0.000902 |
19
+ # | interpolate | 0.000404 |
20
+ # +-------------+----------+
21
+ # | concat | 0.000564 |
19
22
  # +-------------+----------+
20
- # | interpolate | 0.019667 |
21
- # +-------------+----------+
@@ -1,4 +1,13 @@
1
+ 0.52.0 08/22/2016
2
+ =================
3
+
4
+ freeze string literals
5
+ move toward interpolation, over concatenation (frozen string related)
6
+ start conversion toward rspec
7
+ move user/pass authorization header setting to request level
8
+
1
9
  0.51.0 07/08/2016
10
+ =================
2
11
 
3
12
  tweak new errors to be an alias rather than inherit
4
13
 
@@ -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.51.0'
17
- s.date = '2016-07-08'
16
+ s.version = '0.52.0'
17
+ s.date = '2016-08-22'
18
18
  s.rubyforge_project = 'excon'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -54,6 +54,7 @@ Gem::Specification.new do |s|
54
54
  ## List your development dependencies here. Development dependencies are
55
55
  ## those that are only needed during development
56
56
  # s.add_development_dependency('DEVDEPNAME', [">= 1.1.0", "< 2.0.0"])
57
+ s.add_development_dependency('rspec', '>= 3.5.0')
57
58
  s.add_development_dependency('activesupport')
58
59
  s.add_development_dependency('delorean')
59
60
  s.add_development_dependency('eventmachine', '>= 1.0.4')
@@ -119,8 +120,16 @@ Gem::Specification.new do |s|
119
120
  lib/excon/socket.rb
120
121
  lib/excon/ssl_socket.rb
121
122
  lib/excon/standard_instrumentor.rb
123
+ lib/excon/test/plugin/server/exec.rb
124
+ lib/excon/test/plugin/server/puma.rb
125
+ lib/excon/test/plugin/server/unicorn.rb
126
+ lib/excon/test/plugin/server/webrick.rb
127
+ lib/excon/test/server.rb
122
128
  lib/excon/unix_socket.rb
123
129
  lib/excon/utils.rb
130
+ spec/excon_spec.rb
131
+ spec/excon_test_server_spec.rb
132
+ spec/spec_helper.rb
124
133
  tests/authorization_header_tests.rb
125
134
  tests/bad_tests.rb
126
135
  tests/basic_tests.rb
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  $:.unshift(File.dirname(__FILE__)) unless
2
3
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
4
 
@@ -55,7 +56,7 @@ module Excon
55
56
  def display_warning(warning)
56
57
  # Show warning if $VERBOSE or ENV['EXCON_DEBUG'] is set
57
58
  if $VERBOSE || ENV['EXCON_DEBUG']
58
- $stderr.puts '[excon][WARNING] ' << warning << "\n#{ caller.join("\n") }"
59
+ $stderr.puts "[excon][WARNING] #{warning}\n#{ caller.join("\n") }"
59
60
  end
60
61
  end
61
62
 
@@ -149,7 +150,7 @@ module Excon
149
150
  if uri.user || uri.password
150
151
  request_params[:headers] ||= {}
151
152
  user, pass = Utils.unescape_form(uri.user.to_s), Utils.unescape_form(uri.password.to_s)
152
- request_params[:headers]['Authorization'] ||= 'Basic ' << ['' << user << ':' << pass].pack('m').delete(Excon::CR_NL)
153
+ request_params[:headers]['Authorization'] ||= 'Basic ' + ["#{user}:#{pass}"].pack('m').delete(Excon::CR_NL)
153
154
  end
154
155
  end
155
156
  if request_params.has_key?(:headers)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  class Connection
3
4
  include Utils
@@ -69,13 +70,6 @@ module Excon
69
70
  @data[:instrumentor] = Excon::StandardInstrumentor
70
71
  end
71
72
 
72
- # Use Basic Auth if url contains a login
73
- if @data[:user] || @data[:password]
74
- user, pass = Utils.unescape_form(@data[:user].to_s), Utils.unescape_form(@data[:password].to_s)
75
- @data[:headers]['Authorization'] ||= 'Basic ' << ['' << user.to_s << ':' << pass.to_s].pack('m').delete(Excon::CR_NL)
76
- end
77
-
78
- @socket_key = '' << @data[:scheme]
79
73
  if @data[:scheme] == UNIX
80
74
  if @data[:host]
81
75
  raise ArgumentError, "The `:host` parameter should not be set for `unix://` connections.\n" +
@@ -83,10 +77,10 @@ module Excon
83
77
  elsif !@data[:socket]
84
78
  raise ArgumentError, 'You must provide a `:socket` for `unix://` connections'
85
79
  else
86
- @socket_key << '://' << @data[:socket]
80
+ @socket_key = "#{@data[:scheme]}://#{@data[:socket]}"
87
81
  end
88
82
  else
89
- @socket_key << '://' << @data[:host] << port_string(@data)
83
+ @socket_key = "#{@data[:scheme]}://#{@data[:host]}#{port_string(@data)}"
90
84
  end
91
85
  reset
92
86
  end
@@ -105,7 +99,7 @@ module Excon
105
99
  else
106
100
  socket.data = datum
107
101
  # start with "METHOD /path"
108
- request = datum[:method].to_s.upcase << ' '
102
+ request = datum[:method].to_s.upcase + ' '
109
103
  if datum[:proxy] && datum[:scheme] != HTTPS
110
104
  request << datum[:scheme] << '://' << datum[:host] << port_string(datum)
111
105
  end
@@ -151,7 +145,7 @@ module Excon
151
145
  if chunk.length > 0
152
146
  socket.write(chunk.length.to_s(16) << CR_NL << chunk << CR_NL)
153
147
  else
154
- socket.write('0' << CR_NL << CR_NL)
148
+ socket.write(String.new("0#{CR_NL}#{CR_NL}"))
155
149
  break
156
150
  end
157
151
  end
@@ -223,10 +217,15 @@ module Excon
223
217
  datum = @data.merge(params)
224
218
  datum[:headers] = @data[:headers].merge(datum[:headers] || {})
225
219
 
220
+ if datum[:user] || datum[:password]
221
+ user, pass = Utils.unescape_form(datum[:user].to_s), Utils.unescape_form(datum[:password].to_s)
222
+ datum[:headers]['Authorization'] ||= 'Basic ' + ["#{user}:#{pass}"].pack('m').delete(Excon::CR_NL)
223
+ end
224
+
226
225
  if datum[:scheme] == UNIX
227
226
  datum[:headers]['Host'] = ''
228
227
  else
229
- datum[:headers]['Host'] ||= '' << datum[:host] << port_string(datum)
228
+ datum[:headers]['Host'] ||= datum[:host] + port_string(datum)
230
229
  end
231
230
  datum[:retries_remaining] ||= datum[:retry_limit]
232
231
 
@@ -340,11 +339,11 @@ module Excon
340
339
  vars[:'@data'][:password] = REDACTED
341
340
  end
342
341
  inspection = '#<Excon::Connection:'
343
- inspection << (object_id << 1).to_s(16)
342
+ inspection += (object_id << 1).to_s(16)
344
343
  vars.each do |key, value|
345
- inspection << ' ' << key.to_s << '=' << value.inspect
344
+ inspection += " #{key}=#{value.inspect}"
346
345
  end
347
- inspection << '>'
346
+ inspection += '>'
348
347
  inspection
349
348
  end
350
349
 
@@ -486,8 +485,8 @@ module Excon
486
485
  # https credentials happen in handshake
487
486
  if @data[:proxy].has_key?(:user) || @data[:proxy].has_key?(:password)
488
487
  user, pass = Utils.unescape_form(@data[:proxy][:user].to_s), Utils.unescape_form(@data[:proxy][:password].to_s)
489
- auth = ['' << user << ':' << pass].pack('m').delete(Excon::CR_NL)
490
- @data[:headers]['Proxy-Authorization'] = 'Basic ' << auth
488
+ auth = ["#{user}:#{pass}"].pack('m').delete(Excon::CR_NL)
489
+ @data[:headers]['Proxy-Authorization'] = 'Basic ' + auth
491
490
  end
492
491
  end
493
492
  end
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
 
3
- VERSION = '0.51.0'
4
+ VERSION = '0.52.0'
4
5
 
5
6
  CR_NL = "\r\n"
6
7
 
@@ -29,9 +30,9 @@ module Excon
29
30
 
30
31
  UNIX = 'unix'
31
32
 
32
- USER_AGENT = 'excon/' << VERSION
33
+ USER_AGENT = "excon/#{VERSION}"
33
34
 
34
- VERSIONS = USER_AGENT + ' (' << RUBY_PLATFORM << ') ruby/' << RUBY_VERSION
35
+ VERSIONS = "#{USER_AGENT} (#{RUBY_PLATFORM}) ruby/#{RUBY_VERSION}"
35
36
 
36
37
  VALID_REQUEST_KEYS = [
37
38
  :body,
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  # Excon exception classes
3
4
  class Error < StandardError
@@ -36,8 +37,8 @@ Unable to verify certificate. This may be an issue with the remote host or with
36
37
  or:
37
38
  `Excon.defaults[:ssl_verify_peer] = false` (less secure).
38
39
  EOL
39
- full_message = "#{socket_error.message} (#{socket_error.class})"
40
- full_message << ' ' + msg
40
+ full_message = "#{socket_error.message} (#{socket_error.class})" +
41
+ ' ' + msg
41
42
  super(full_message)
42
43
  set_backtrace(socket_error.backtrace)
43
44
  @socket_error = socket_error
@@ -163,8 +164,8 @@ or:
163
164
  error_class, error_message = [default_class, 'Unknown']
164
165
  end
165
166
  message = StringIO.new
166
- str = "Expected(#{request[:expects].inspect}) <=>"
167
- str << " Actual(#{response[:status]} #{error_message})"
167
+ str = "Expected(#{request[:expects].inspect}) <=>" +
168
+ " Actual(#{response[:status]} #{error_message})"
168
169
  message.puts(str)
169
170
  if request[:debug_request]
170
171
  message.puts('excon.error.request')
@@ -201,7 +202,7 @@ or:
201
202
 
202
203
  klasses.each do |klass|
203
204
  class_name = klass.to_s
204
- unless class_name =~ /Error\Z/
205
+ unless class_name =~ /Error\Z/
205
206
  class_name = klass.to_s + 'Error' if class_name =~ legacy_re
206
207
  end
207
208
  Excon::Errors.const_set(class_name, Excon::Error.const_get(klass))
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # TODO: Remove this monkey patch once ruby 1.9.3+ is the minimum supported version.
2
3
  #
3
4
  # This patch backports URI#hostname to ruby 1.9.2 and older.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  class Headers < Hash
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  module Middleware
3
4
  class Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  module Middleware
3
4
  class CaptureCookies < Excon::Middleware::Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  module Middleware
3
4
  class Decompress < Excon::Middleware::Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  module Middleware
3
4
  class EscapePath < Excon::Middleware::Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  module Middleware
3
4
  class Expects < Excon::Middleware::Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  module Middleware
3
4
  class Idempotent < Excon::Middleware::Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  module Middleware
3
4
  class Instrumentor < Excon::Middleware::Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  module Middleware
3
4
  class Mock < Excon::Middleware::Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  module Middleware
3
4
  class RedirectFollower < Excon::Middleware::Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  module Middleware
3
4
  class ResponseParser < Excon::Middleware::Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  class PrettyPrinter
3
4
  def self.pp(io, datum, indent=0)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  class Response
3
4
 
@@ -65,7 +66,7 @@ module Excon
65
66
  reason_phrase = line[13..-3] # -3 strips the trailing "\r\n"
66
67
 
67
68
  datum[:response] = {
68
- :body => '',
69
+ :body => String.new,
69
70
  :cookies => [],
70
71
  :host => datum[:host],
71
72
  :headers => Excon::Headers.new,
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  class Socket
3
4
  include Utils
@@ -23,7 +24,7 @@ module Excon
23
24
  def initialize(data = {})
24
25
  @data = data
25
26
  @nonblock = data[:nonblock]
26
- @read_buffer = ''
27
+ @read_buffer = String.new
27
28
  @eof = false
28
29
  connect
29
30
  end
@@ -40,7 +41,7 @@ module Excon
40
41
 
41
42
  def readline
42
43
  return legacy_readline if RUBY_VERSION.to_f <= 1.8_7
43
- buffer = ''
44
+ buffer = String.new
44
45
  begin
45
46
  buffer << @socket.read_nonblock(1) while buffer[-1] != "\n"
46
47
  buffer
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  class SSLSocket < Socket
3
4
  HAVE_NONBLOCK = [:connect_nonblock, :read_nonblock, :write_nonblock].all? do |m|
@@ -47,7 +48,7 @@ module Excon
47
48
 
48
49
  # workaround issue #257 (JRUBY-6970)
49
50
  ca_file = DEFAULT_CA_FILE
50
- ca_file.gsub!(/^jar:/, '') if ca_file =~ /^jar:file:\//
51
+ ca_file = ca_file.gsub(/^jar:/, '') if ca_file =~ /^jar:file:\//
51
52
 
52
53
  begin
53
54
  ssl_context.cert_store.add_file(ca_file)
@@ -86,17 +87,17 @@ module Excon
86
87
  end
87
88
 
88
89
  if @data[:proxy]
89
- request = 'CONNECT ' << @data[:host] << port_string(@data.merge(:omit_default_port => false)) << Excon::HTTP_1_1
90
- request << 'Host: ' << @data[:host] << port_string(@data) << Excon::CR_NL
90
+ request = "CONNECT #{@data[:host]}#{port_string(@data.merge(:omit_default_port => false))}#{Excon::HTTP_1_1}" +
91
+ "Host: #{@data[:host]}#{port_string(@data)}#{Excon::CR_NL}"
91
92
 
92
93
  if @data[:proxy][:password] || @data[:proxy][:user]
93
- auth = ['' << @data[:proxy][:user].to_s << ':' << @data[:proxy][:password].to_s].pack('m').delete(Excon::CR_NL)
94
- request << 'Proxy-Authorization: Basic ' << auth << Excon::CR_NL
94
+ auth = ["#{@data[:proxy][:user]}:#{@data[:proxy][:password]}"].pack('m').delete(Excon::CR_NL)
95
+ request += "Proxy-Authorization: Basic #{auth}#{Excon::CR_NL}"
95
96
  end
96
97
 
97
- request << 'Proxy-Connection: Keep-Alive' << Excon::CR_NL
98
+ request += "Proxy-Connection: Keep-Alive#{Excon::CR_NL}"
98
99
 
99
- request << Excon::CR_NL
100
+ request += Excon::CR_NL
100
101
 
101
102
  # write out the proxy setup request
102
103
  @socket.write(request)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  class StandardInstrumentor
3
4
  def self.instrument(name, params = {}, &block)
@@ -0,0 +1,23 @@
1
+ module Excon
2
+ module Test
3
+ module Plugin
4
+ module Server
5
+ module Exec
6
+ def start(app_str = app)
7
+ line = ''
8
+ open_process(app)
9
+ until line =~ /\Aready\Z/
10
+ line = error.gets
11
+ fatal_time = elapsed_time > timeout
12
+ if fatal_time
13
+ msg = "executable #{app} has taken too long to start"
14
+ raise msg
15
+ end
16
+ end
17
+ true
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ module Excon
2
+ module Test
3
+ module Plugin
4
+ module Server
5
+ module Puma
6
+ def start(app_str = app, bind_uri = bind)
7
+ bind.host = bind_uri.host.gsub(/[\[\]]/, '')
8
+ open_process('puma', '-b', bind_uri.to_s, app_str)
9
+ line = ''
10
+ until line =~ /Use Ctrl-C to stop/
11
+ line = read.gets
12
+ fatal_time = elapsed_time > timeout
13
+ raise 'puma server has taken too long to start' if fatal_time
14
+ end
15
+ true
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,35 @@
1
+ module Excon
2
+ module Test
3
+ module Plugin
4
+ module Server
5
+ module Unicorn
6
+ def start(app_str = app, bind_uri = bind)
7
+ bind_uri = URI.parse(bind_uri) unless bind_uri.is_a? URI::Generic
8
+ is_unix_socket = (bind_uri.scheme == "unix")
9
+ if is_unix_socket
10
+ bind_str = bind_uri.to_s
11
+ else
12
+ host = bind_uri.host.gsub(/[\[\]]/, '')
13
+ bind_str = "#{host}:#{bind_uri.port}"
14
+ end
15
+ args = [
16
+ 'unicorn',
17
+ '--no-default-middleware',
18
+ '-l',
19
+ bind_str,
20
+ app_str
21
+ ]
22
+ open_process(*args)
23
+ line = ''
24
+ until line =~ /worker\=0 ready/
25
+ line = error.gets
26
+ fatal_time = elapsed_time > timeout
27
+ raise 'unicorn server has taken too long to start' if fatal_time
28
+ end
29
+ true
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ module Excon
2
+ module Test
3
+ module Plugin
4
+ module Server
5
+ module Webrick
6
+ def start(app_str = app, bind_uri = bind)
7
+ bind_uri = URI.parse(bind_uri) unless bind_uri.is_a? URI::Generic
8
+ host = bind_uri.host.gsub(/[\[\]]/, '')
9
+ port = bind_uri.port.to_s
10
+ open_process('rackup', '-s', 'webrick', '--host', host, '--port', port, app_str)
11
+ line = ''
12
+ until line =~ /HTTPServer#start/
13
+ line = error.gets
14
+ fatal_time = elapsed_time > timeout
15
+ raise 'webrick server has taken too long to start' if fatal_time
16
+ end
17
+ true
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,107 @@
1
+ require 'open4'
2
+ require 'excon'
3
+ require 'excon/test/plugin/server/webrick'
4
+ require 'excon/test/plugin/server/unicorn'
5
+ require 'excon/test/plugin/server/puma'
6
+ require 'excon/test/plugin/server/exec'
7
+
8
+
9
+ module Excon
10
+ module Test
11
+ class Server
12
+ attr_accessor :app, :server, :bind, :pid, :read, :write, :error, :started_at, :timeout
13
+
14
+ # Methods that must be implemented by a plugin
15
+ INSTANCE_REQUIRES = [:start]
16
+ Excon.defaults.merge!(
17
+ connect_timeout: 5,
18
+ read_timeout: 5,
19
+ write_timeout: 5
20
+ )
21
+
22
+ def initialize(args)
23
+ # TODO: Validate these args
24
+ @server = args.keys.first
25
+ @app = args[server]
26
+ args[:bind] ||= 'tcp://127.0.0.1:9292'
27
+ @bind = URI.parse(args[:bind])
28
+ @is_unix_socket = (@bind.scheme == 'unix')
29
+ @bind.host = @bind.host.gsub(/[\[\]]/, '') unless @is_unix_socket
30
+ if args[:timeout]
31
+ @timeout = args[:timeout]
32
+ else
33
+ # Double the default timeout if jruby because of the startup cost
34
+ @timeout = RUBY_PLATFORM == "java" ? 20 : 10
35
+ end
36
+ name = @server.to_s.split('_').collect(&:capitalize).join
37
+ plug = nested_const_get("Excon::Test::Plugin::Server::#{name}")
38
+ self.extend plug
39
+ check_implementation(plug)
40
+ end
41
+
42
+ def open_process(*args)
43
+ if RUBY_PLATFORM == 'java'
44
+ @pid, @write, @read, @error = IO.popen4(*args)
45
+ else
46
+ GC.disable if RUBY_VERSION < '1.9'
47
+ @pid, @write, @read, @error = Open4.popen4(*args)
48
+ end
49
+ @started_at = Time.now
50
+ end
51
+
52
+ def elapsed_time
53
+ Time.now - started_at
54
+ end
55
+
56
+ def stop
57
+ if RUBY_PLATFORM == 'java'
58
+ Process.kill('USR1', pid)
59
+ else
60
+ Process.kill(9, pid)
61
+ GC.enable if RUBY_VERSION < '1.9'
62
+ Process.wait(pid)
63
+ end
64
+
65
+ if @is_unix_socket
66
+ socket = @bind.path
67
+ File.delete(socket) if File.exist?(socket)
68
+ end
69
+
70
+ # TODO: Ensure process is really dead
71
+ dump_errors
72
+ true
73
+ end
74
+ def dump_errors
75
+ lines = error.read.split($INPUT_RECORD_SEPARATOR)
76
+ while line = lines.shift
77
+ case line
78
+ when /(ERROR|Error)/
79
+ unless line =~ /(null cert chain|did not return a certificate|SSL_read:: internal error)/
80
+ in_err = true
81
+ puts
82
+ end
83
+ when /^(127|localhost)/
84
+ in_err = false
85
+ end
86
+ puts line if in_err
87
+ end
88
+ end
89
+
90
+ private
91
+
92
+ def nested_const_get(namespace)
93
+ namespace.split('::').inject(Object) do |mod, klass|
94
+ mod.const_get(klass)
95
+ end
96
+ end
97
+
98
+ def check_implementation(plug)
99
+ INSTANCE_REQUIRES.each do |m|
100
+ unless self.respond_to? m
101
+ raise "FATAL: #{plug} does not implement ##{m}"
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  class UnixSocket < Excon::Socket
3
4
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Excon
2
3
  module Utils
3
4
  extend self
@@ -14,26 +15,26 @@ module Excon
14
15
  raise ArgumentError, '`datum` must be given unless called on a Connection'
15
16
  end
16
17
  if datum[:scheme] == UNIX
17
- '' << datum[:scheme] << '://' << datum[:socket]
18
+ "#{datum[:scheme]}://#{datum[:socket]}"
18
19
  else
19
- '' << datum[:scheme] << '://' << datum[:host] << port_string(datum)
20
+ "#{datum[:scheme]}://#{datum[:host]}#{port_string(datum)}"
20
21
  end
21
22
  end
22
23
 
23
24
  def request_uri(datum)
24
- connection_uri(datum) << datum[:path] << query_string(datum)
25
+ connection_uri(datum) + datum[:path] + query_string(datum)
25
26
  end
26
27
 
27
28
  def port_string(datum)
28
29
  if datum[:port].nil? || (datum[:omit_default_port] && ((datum[:scheme].casecmp('http') == 0 && datum[:port] == 80) || (datum[:scheme].casecmp('https') == 0 && datum[:port] == 443)))
29
30
  ''
30
31
  else
31
- ':' << datum[:port].to_s
32
+ ':' + datum[:port].to_s
32
33
  end
33
34
  end
34
35
 
35
36
  def query_string(datum)
36
- str = ''
37
+ str = String.new
37
38
  case datum[:query]
38
39
  when String
39
40
  str << '?' << datum[:query]
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Excon do
4
+ it 'has a version number' do
5
+ expect(Excon::VERSION).not_to be nil
6
+ end
7
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ # The variable file should be renamed to something better - starbelly
4
+ shared_examples_for "a web server" do |plugin, file, bind_str = nil|
5
+ plugin = plugin.to_sym unless plugin.is_a? Symbol
6
+
7
+ if plugin == :unicorn && RUBY_PLATFORM == "java"
8
+ before { skip("until unicorn supports jruby") }
9
+ end
10
+
11
+ abs_file = Object.send("#{plugin}_path", file)
12
+ instance = nil
13
+ args = { plugin => abs_file}
14
+ args[:bind] = bind_str unless bind_str.nil?
15
+
16
+ it "returns an instance" do
17
+ instance = Excon::Test::Server.new(args)
18
+ expect(instance).to be_instance_of Excon::Test::Server
19
+ end
20
+
21
+ it 'starts the server' do
22
+ expect(instance.start).to be true
23
+ end
24
+
25
+ it 'stops the server' do
26
+ expect(instance.stop).to be true
27
+ end
28
+ end
29
+
30
+ describe Excon::Test::Server do
31
+ context 'when webrick' do
32
+ it_should_behave_like "a web server", :webrick, 'basic.ru'
33
+ end
34
+
35
+ context 'when unicorn' do
36
+ it_should_behave_like "a web server", :unicorn, 'streaming.ru'
37
+ end
38
+
39
+ context "when unicorn is given a unix socket uri" do
40
+ socket_uri = 'unix:///tmp/unicorn.socket'
41
+ it_should_behave_like "a web server", :unicorn, 'streaming.ru', socket_uri
42
+ end
43
+
44
+ context 'when puma' do
45
+ it_should_behave_like "a web server", :puma, 'streaming.ru'
46
+ end
47
+
48
+ context 'when executable' do
49
+ it_should_behave_like "a web server", :exec, 'good.rb'
50
+ end
51
+ end
@@ -0,0 +1,126 @@
1
+ require 'excon'
2
+ require 'excon/test/server'
3
+
4
+ # This file was generated by the `rspec --init` command. Conventionally, all
5
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
6
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
7
+ # this file to always be loaded, without a need to explicitly require it in any
8
+ # files.
9
+ #
10
+ # Given that it is always loaded, you are encouraged to keep this file as
11
+ # light-weight as possible. Requiring heavyweight dependencies from this file
12
+ # will add to the boot time of your test suite on EVERY test run, even for an
13
+ # individual file that may not need all of that loaded. Instead, consider making
14
+ # a separate helper file that requires the additional dependencies and performs
15
+ # the additional setup, and require it from the spec files that actually need
16
+ # it.
17
+ #
18
+ # The `.rspec` file also contains a few flags that are not defaults but that
19
+ # users commonly want.
20
+ #
21
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
22
+ RSpec.configure do |config|
23
+ # rspec-expectations config goes here. You can use an alternate
24
+ # assertion/expectation library such as wrong or the stdlib/minitest
25
+ # assertions if you prefer.
26
+ config.expect_with :rspec do |expectations|
27
+ # This option will default to `true` in RSpec 4. It makes the `description`
28
+ # and `failure_message` of custom matchers include text for helper methods
29
+ # defined using `chain`, e.g.:
30
+ # be_bigger_than(2).and_smaller_than(4).description
31
+ # # => "be bigger than 2 and smaller than 4"
32
+ # ...rather than:
33
+ # # => "be bigger than 2"
34
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
35
+ end
36
+
37
+ # rspec-mocks config goes here. You can use an alternate test double
38
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
39
+ config.mock_with :rspec do |mocks|
40
+ # Prevents you from mocking or stubbing a method that does not exist on
41
+ # a real object. This is generally recommended, and will default to
42
+ # `true` in RSpec 4.
43
+ mocks.verify_partial_doubles = true
44
+ end
45
+
46
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
47
+ # have no way to turn it off -- the option exists only for backwards
48
+ # compatibility in RSpec 3). It causes shared context metadata to be
49
+ # inherited by the metadata hash of host groups and examples, rather than
50
+ # triggering implicit auto-inclusion in groups with matching metadata.
51
+ config.shared_context_metadata_behavior = :apply_to_host_groups
52
+
53
+ # The settings below are suggested to provide a good initial experience
54
+ # with RSpec, but feel free to customize to your heart's content.
55
+ =begin
56
+ # This allows you to limit a spec run to individual examples or groups
57
+ # you care about by tagging them with `:focus` metadata. When nothing
58
+ # is tagged with `:focus`, all examples get run. RSpec also provides
59
+ # aliases for `it`, `describe`, and `context` that include `:focus`
60
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
61
+ config.filter_run_when_matching :focus
62
+
63
+ # Allows RSpec to persist some state between runs in order to support
64
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
65
+ # you configure your source control system to ignore this file.
66
+ config.example_status_persistence_file_path = "spec/examples.txt"
67
+
68
+ # Limits the available syntax to the non-monkey patched syntax that is
69
+ # recommended. For more details, see:
70
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
71
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
72
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
73
+ config.disable_monkey_patching!
74
+
75
+ # This setting enables warnings. It's recommended, but in some cases may
76
+ # be too noisy due to issues in dependencies.
77
+ config.warnings = true
78
+
79
+ # Many RSpec users commonly either run the entire suite or an individual
80
+ # file, and it's useful to allow more verbose output when running an
81
+ # individual spec file.
82
+ if config.files_to_run.one?
83
+ # Use the documentation formatter for detailed output,
84
+ # unless a formatter has already been configured
85
+ # (e.g. via a command-line flag).
86
+ config.default_formatter = 'doc'
87
+ end
88
+
89
+ # Print the 10 slowest examples and example groups at the
90
+ # end of the spec run, to help surface which specs are running
91
+ # particularly slow.
92
+ config.profile_examples = 10
93
+
94
+ # Run specs in random order to surface order dependencies. If you find an
95
+ # order dependency and want to debug it, you can fix the order by providing
96
+ # the seed, which is printed after each run.
97
+ # --seed 1234
98
+ config.order = :random
99
+
100
+ # Seed global randomization in this process using the `--seed` CLI option.
101
+ # Setting this allows you to use `--seed` to deterministically reproduce
102
+ # test failures related to randomization by passing the same `--seed` value
103
+ # as the one that triggered the failure.
104
+ Kernel.srand config.seed
105
+ =end
106
+
107
+ end
108
+
109
+ # Todo: s/tests/specs when migration is complete
110
+ def get_abs_path(*parts)
111
+ File.join(File.expand_path('../..', __FILE__), 'tests', *parts)
112
+ end
113
+
114
+ def rackup_path(*parts)
115
+ get_abs_path('rackups', *parts)
116
+ end
117
+
118
+ def webrick_path(*parts) rackup_path(*parts); end
119
+
120
+ def unicorn_path(*parts) rackup_path(*parts); end
121
+
122
+ def puma_path(*parts) rackup_path(*parts); end
123
+
124
+ def exec_path(*parts)
125
+ get_abs_path('servers', *parts)
126
+ end
@@ -14,10 +14,6 @@ Shindo.tests('Excon basics (Authorization data redacted)') do
14
14
  !conn.inspect.include?(auth_header)
15
15
  end
16
16
 
17
- test("authorization header remains correct for #{desc}") do
18
- conn.data[:headers]['Authorization'] == auth_header
19
- end
20
-
21
17
  if conn.data[:password]
22
18
  test("password param concealed for #{desc}") do
23
19
  !conn.inspect.include?(conn.data[:password])
@@ -91,10 +91,23 @@ end
91
91
  Shindo.tests('Excon basics (Basic Auth Pass)') do
92
92
  with_rackup('basic_auth.ru') do
93
93
  basic_tests('http://test_user:test_password@127.0.0.1:9292')
94
+ user, pass, uri = ['test_user', 'test_password', 'http://127.0.0.1:9292'].map(&:freeze)
95
+
94
96
  tests('with frozen args').returns(200) do
95
- user, pass, uri = ['test_user', 'test_password', 'http://127.0.0.1:9292'].map(&:freeze)
96
- connection = Excon.new(uri, :user => user, :password => pass )
97
- response = connection.request(:method => :get, :path => '/content-length/100')
97
+ connection = Excon.new(uri, :method => :get, :password => pass, :path => '/content-length/100', :user => user)
98
+ response = connection.request
99
+ response.status
100
+ end
101
+
102
+ tests('with user/pass on request').returns(200) do
103
+ connection = Excon.new(uri, :method => :get, :path => '/content-length/100')
104
+ response = connection.request(:user => user, :password => pass)
105
+ response.status
106
+ end
107
+
108
+ tests('with user/pass on connection and request').returns(200) do
109
+ connection = Excon.new(uri, :method => :get, :password => 'incorrect_password', :path => '/content-length/100', :user => 'incorrect_user')
110
+ response = connection.request(user: user, password: pass)
98
111
  response.status
99
112
  end
100
113
  end
@@ -173,6 +173,8 @@ Shindo.tests('Excon instrumentation') do
173
173
 
174
174
  tests('authorization header REDACT') do
175
175
 
176
+ @auth_header = 'Basic dXNlcjpwYXNz'
177
+
176
178
  begin
177
179
  original_stderr = $stderr
178
180
  $stderr = @captured_stderr = StringIO.new
@@ -180,6 +182,9 @@ Shindo.tests('Excon instrumentation') do
180
182
  raises(Excon::Errors::SocketError) do
181
183
  @connection = Excon.new(
182
184
  'http://user:pass@127.0.0.1:9292',
185
+ :headers => {
186
+ 'Authorization' => @auth_header
187
+ },
183
188
  :instrumentor => Excon::StandardInstrumentor,
184
189
  :mock => true
185
190
  )
@@ -189,8 +194,6 @@ Shindo.tests('Excon instrumentation') do
189
194
  $stderr = original_stderr
190
195
  end
191
196
 
192
- @auth_header = 'Basic dXNlcjpwYXNz'
193
-
194
197
  test('does not appear in response') do
195
198
  !@captured_stderr.string.include?(@auth_header)
196
199
  end
@@ -234,9 +234,9 @@ end
234
234
  def with_rackup(name, host="127.0.0.1")
235
235
  unless RUBY_PLATFORM == 'java'
236
236
  GC.disable if RUBY_VERSION < '1.9'
237
- pid, w, r, e = Open4.popen4("rackup", "--host", host, rackup_path(name))
237
+ pid, w, r, e = Open4.popen4("rackup", "-s", "webrick", "--host", host, rackup_path(name))
238
238
  else
239
- pid, w, r, e = IO.popen4("rackup", "--host", host, rackup_path(name))
239
+ pid, w, r, e = IO.popen4("rackup", "-s", "webrick", "--host", host, rackup_path(name))
240
240
  end
241
241
  until e.gets =~ /HTTPServer#start:/; end
242
242
  yield
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: excon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.51.0
4
+ version: 0.52.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - dpiddy (Dan Peterson)
@@ -10,8 +10,22 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-07-08 00:00:00.000000000 Z
13
+ date: 2016-08-22 00:00:00.000000000 Z
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: 3.5.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: 3.5.0
15
29
  - !ruby/object:Gem::Dependency
16
30
  name: activesupport
17
31
  requirement: !ruby/object:Gem::Requirement
@@ -208,8 +222,16 @@ files:
208
222
  - lib/excon/socket.rb
209
223
  - lib/excon/ssl_socket.rb
210
224
  - lib/excon/standard_instrumentor.rb
225
+ - lib/excon/test/plugin/server/exec.rb
226
+ - lib/excon/test/plugin/server/puma.rb
227
+ - lib/excon/test/plugin/server/unicorn.rb
228
+ - lib/excon/test/plugin/server/webrick.rb
229
+ - lib/excon/test/server.rb
211
230
  - lib/excon/unix_socket.rb
212
231
  - lib/excon/utils.rb
232
+ - spec/excon_spec.rb
233
+ - spec/excon_test_server_spec.rb
234
+ - spec/spec_helper.rb
213
235
  - tests/authorization_header_tests.rb
214
236
  - tests/bad_tests.rb
215
237
  - tests/basic_tests.rb