excon 0.7.6 → 0.7.7

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.

@@ -2,6 +2,8 @@
2
2
 
3
3
  Http(s) EXtended CONnections
4
4
 
5
+ {<img src="https://secure.travis-ci.org/geemus/excon.png" />}[http://travis-ci.org/geemus/excon]
6
+
5
7
  == Getting Started
6
8
 
7
9
  Install the gem.
@@ -17,9 +19,9 @@ The simplest way to use excon is with one-off requests:
17
19
 
18
20
  response = Excon.get('http://geemus.com')
19
21
 
20
- Supported one-off request methods are #connect, #delete, #get, #head, #options, #post, #put, and #trace.
22
+ Supported one-off request methods are #connect, #delete, #get, #head, #options, #post, #put, and #trace.
21
23
 
22
- The returned response object has #body, #headers and #status attributes.
24
+ The returned response object has #body, #headers and #status attributes.
23
25
 
24
26
  Alternately you can create a connection object which is reusable across multiple requests (more performant!).
25
27
 
@@ -27,7 +29,7 @@ Alternately you can create a connection object which is reusable across multiple
27
29
  response_one = connection.get
28
30
  response_two = connection.post(:path => '/foo')
29
31
  response_three = connection.delete(:path => '/bar')
30
-
32
+
31
33
  Sometimes it is more convenient to specify the request type as an argument:
32
34
 
33
35
  response_four = connection.request(:method => :get, :path => '/more')
@@ -37,14 +39,14 @@ Both one-off and persistent connections support many other options. Here are a f
37
39
  # Custom headers
38
40
  Excon.get('http://geemus.com', :headers => {'Authorization' => 'Basic 0123456789ABCDEF'})
39
41
  connection.get(:headers => {'Authorization' => 'Basic 0123456789ABCDEF'})
40
-
42
+
41
43
  # Changing query strings
42
44
  connection = Excon.new('http://geemus.com/')
43
45
  connection.get(:query => {:foo => 'bar'})
44
-
46
+
45
47
  # POST body
46
48
  Excon.post('http://geemus.com', :body => 'language=ruby&class=fog')
47
-
49
+
48
50
  # request accepts either symbols or strings
49
51
  connection.request(:method => :get)
50
52
  connection.request(:method => 'GET')
@@ -59,7 +61,7 @@ You can stream responses by passing a block that will receive each chunk.
59
61
  puts chunk
60
62
  puts "Remaining: #{remaining_bytes.to_f / total_bytes}%"
61
63
  end
62
-
64
+
63
65
  Iterating over each chunk will allow you to do work on the response incrementally without buffering the entire response first. For very large responses this can lead to significant memory savings.
64
66
 
65
67
  == Proxy Support
@@ -71,7 +73,7 @@ You can specify a proxy URL that Excon will use with both HTTP and HTTPS connect
71
73
 
72
74
  The proxy URL must be fully specified, including scheme (e.g. "http://") and port.
73
75
 
74
- Excon will also use the environment variables "http_proxy" and "https_proxy" if they are present.
76
+ Excon will also use the environment variables "http_proxy" and "https_proxy" if they are present.
75
77
 
76
78
  If "https_proxy" is not set, the value of "http_proxy" will be used for both HTTP and HTTPS connections.
77
79
 
@@ -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.7.6'
17
- s.date = '2011-10-04'
16
+ s.version = '0.7.7'
17
+ s.date = '2011-11-24'
18
18
  s.rubyforge_project = 'excon'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -92,6 +92,7 @@ Gem::Specification.new do |s|
92
92
  lib/excon/response.rb
93
93
  lib/excon/socket.rb
94
94
  lib/excon/ssl_socket.rb
95
+ tests/bad_tests.rb
95
96
  tests/basic_tests.rb
96
97
  tests/header_tests.rb
97
98
  tests/idempotent_tests.rb
@@ -105,6 +106,7 @@ Gem::Specification.new do |s|
105
106
  tests/rackups/ssl.ru
106
107
  tests/rackups/thread_safety.ru
107
108
  tests/request_method_tests.rb
109
+ tests/servers/bad.rb
108
110
  tests/stub_tests.rb
109
111
  tests/test_helper.rb
110
112
  tests/thread_safety_tests.rb
@@ -1,6 +1,6 @@
1
1
  module Excon
2
2
  unless const_defined?(:VERSION)
3
- VERSION = '0.7.6'
3
+ VERSION = '0.7.7'
4
4
  end
5
5
 
6
6
  unless const_defined?(:CHUNK_SIZE)
@@ -76,7 +76,7 @@ module Excon
76
76
 
77
77
  # Messages for nicer exceptions, from rfc2616
78
78
  def self.status_error(request, response)
79
- @errors ||= {
79
+ @errors ||= {
80
80
  100 => [Excon::Errors::Continue, 'Continue'],
81
81
  101 => [Excon::Errors::SwitchingProtocols, 'Switching Protocols'],
82
82
  200 => [Excon::Errors::OK, 'OK'],
@@ -8,17 +8,22 @@ module Excon
8
8
  def_delegators(:@socket, :close, :close)
9
9
  def_delegators(:@socket, :readline, :readline)
10
10
 
11
- def initialize(params = {}, proxy = {})
11
+ def initialize(params = {}, proxy = nil)
12
12
  @params, @proxy = params, proxy
13
13
  @read_buffer, @write_buffer = '', ''
14
+ @eof = false
14
15
 
15
- @sockaddr = if @proxy
16
- ::Socket.sockaddr_in(@proxy[:port].to_i, @proxy[:host])
16
+ addrinfo = if @proxy
17
+ ::Socket.getaddrinfo(@proxy[:host], @proxy[:port].to_i, nil, ::Socket::Constants::SOCK_STREAM)
17
18
  else
18
- ::Socket.sockaddr_in(@params[:port].to_i, @params[:host])
19
- end
19
+ ::Socket.getaddrinfo(@params[:host], @params[:port].to_i, nil, ::Socket::Constants::SOCK_STREAM)
20
+ end.first
21
+
22
+ _, port, _, ip, a_family, s_type = addrinfo
20
23
 
21
- @socket = ::Socket.new(::Socket::Constants::AF_INET, ::Socket::Constants::SOCK_STREAM, 0)
24
+ @sockaddr = ::Socket.sockaddr_in(port, ip)
25
+
26
+ @socket = ::Socket.new(a_family, s_type, 0)
22
27
 
23
28
  connect
24
29
 
@@ -39,6 +44,8 @@ module Excon
39
44
  end
40
45
 
41
46
  def read(max_length=nil)
47
+ return nil if @eof
48
+
42
49
  begin
43
50
  if max_length
44
51
  until @read_buffer.length >= max_length
@@ -64,6 +71,7 @@ module Excon
64
71
  raise(Excon::Errors::Timeout.new("read timeout reached"))
65
72
  end
66
73
  rescue EOFError
74
+ @eof = true
67
75
  end
68
76
  if max_length
69
77
  @read_buffer.slice!(0, max_length)
@@ -0,0 +1,35 @@
1
+ Shindo.tests('Excon bad server interaction') do
2
+
3
+ with_server('bad') do
4
+
5
+ tests('bad server: causes EOFError') do
6
+
7
+ tests('with no content length and no chunking') do
8
+ tests('without a block') do
9
+ tests('response.body').returns('hello') do
10
+ connection = Excon.new('http://127.0.0.1:9292')
11
+
12
+ connection.request(:method => :get, :path => '/eof/no_content_length_and_no_chunking').body
13
+ end
14
+ end
15
+
16
+ tests('with a block') do
17
+ tests('body from chunks').returns('hello') do
18
+ connection = Excon.new('http://127.0.0.1:9292')
19
+
20
+ body = ""
21
+ block = lambda {|chunk, remaining, total| body << chunk }
22
+
23
+ connection.request(:method => :get, :path => '/eof/no_content_length_and_no_chunking', &block)
24
+
25
+ body
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -3,45 +3,45 @@ Shindo.tests('Excon response header support') do
3
3
  with_rackup('response_header.ru') do
4
4
 
5
5
  tests('Response#get_header') do
6
- connection = Excon.new('http://foo.com:8080', :proxy => 'http://localhost:9292')
6
+ connection = Excon.new('http://foo.com:8080', :proxy => 'http://127.0.0.1:9292')
7
7
  response = connection.request(:method => :get, :path => '/foo')
8
8
 
9
9
  tests('with variable header capitalization') do
10
-
10
+
11
11
  tests('response.get_header("mixedcase-header")').returns('MixedCase') do
12
12
  response.get_header("mixedcase-header")
13
13
  end
14
-
14
+
15
15
  tests('response.get_header("uppercase-header")').returns('UPPERCASE') do
16
16
  response.get_header("uppercase-header")
17
17
  end
18
-
18
+
19
19
  tests('response.get_header("lowercase-header")').returns('lowercase') do
20
20
  response.get_header("lowercase-header")
21
21
  end
22
-
22
+
23
23
  end
24
-
24
+
25
25
  tests('when provided key capitalization varies') do
26
-
26
+
27
27
  tests('response.get_header("MIXEDCASE-HEADER")').returns('MixedCase') do
28
28
  response.get_header("MIXEDCASE-HEADER")
29
29
  end
30
-
30
+
31
31
  tests('response.get_header("MiXeDcAsE-hEaDeR")').returns('MixedCase') do
32
32
  response.get_header("MiXeDcAsE-hEaDeR")
33
33
  end
34
-
34
+
35
35
  end
36
-
36
+
37
37
  tests('when header is unavailable') do
38
-
38
+
39
39
  tests('response.get_header("missing")').returns(nil) do
40
40
  response.get_header("missing")
41
41
  end
42
-
42
+
43
43
  end
44
-
44
+
45
45
  end
46
46
 
47
47
  end
@@ -1,7 +1,13 @@
1
1
  Shindo.tests('Excon request idempotencey') do
2
2
  Excon.mock = true
3
3
 
4
+ after do
5
+ # flush any existing stubs after each test
6
+ Excon.stubs.clear
7
+ end
8
+
4
9
  tests("Non-idempotent call with an erroring socket").raises(Excon::Errors::SocketError) do
10
+ run_count = 0
5
11
  Excon.stub({:method => :get}) { |params|
6
12
  run_count += 1
7
13
  if run_count < 4 # First 3 calls fail.
@@ -15,8 +21,6 @@ Shindo.tests('Excon request idempotencey') do
15
21
  response = connection.request(:method => :get, :path => '/some-path')
16
22
  end
17
23
 
18
- Excon.stubs.pop
19
-
20
24
  tests("Idempotent request with socket erroring first 3 times").returns(200) do
21
25
  run_count = 0
22
26
  Excon.stub({:method => :get}) { |params|
@@ -33,8 +37,6 @@ Shindo.tests('Excon request idempotencey') do
33
37
  response.status
34
38
  end
35
39
 
36
- Excon.stubs.pop
37
-
38
40
  tests("Idempotent request with socket erroring first 5 times").raises(Excon::Errors::SocketError) do
39
41
  run_count = 0
40
42
  Excon.stub({:method => :get}) { |params|
@@ -51,6 +53,5 @@ Shindo.tests('Excon request idempotencey') do
51
53
  response.status
52
54
  end
53
55
 
54
- Excon.stubs.pop
55
56
  Excon.mock = false
56
57
  end
@@ -1,5 +1,7 @@
1
1
  require 'sinatra'
2
2
 
3
+ require 'rack/head' # workaround for rbx thread safety issue (most likely autoload related)
4
+
3
5
  class App < Sinatra::Base
4
6
  get('/id/:id/wait/:wait') do |id, wait|
5
7
  sleep(wait.to_i)
@@ -3,29 +3,29 @@ Shindo.tests('Excon request methods') do
3
3
  with_rackup('request_methods.ru') do
4
4
 
5
5
  tests 'one-offs' do
6
-
6
+
7
7
  tests('Excon.get').returns('GET') do
8
8
  Excon.get('http://127.0.0.1:9292').body
9
9
  end
10
-
10
+
11
11
  tests('Excon.post').returns('POST') do
12
12
  Excon.post('http://127.0.0.1:9292').body
13
13
  end
14
-
14
+
15
15
  end
16
-
16
+
17
17
  tests 'with a connection object' do
18
-
18
+
19
19
  connection = Excon.new('http://127.0.0.1:9292')
20
-
20
+
21
21
  tests('connection.get').returns('GET') do
22
22
  connection.get.body
23
23
  end
24
-
24
+
25
25
  tests('connection.post').returns('POST') do
26
26
  connection.post.body
27
27
  end
28
-
28
+
29
29
  end
30
30
 
31
31
  end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "eventmachine"
4
+
5
+ module BadServer
6
+ def receive_data(data)
7
+ case data
8
+ when %r{^GET /eof/no_content_length_and_no_chunking\s}
9
+ send_data "HTTP/1.1 200 OK\r\n"
10
+ send_data "\r\n"
11
+ send_data "hello"
12
+ close_connection(true)
13
+ end
14
+ end
15
+ end
16
+
17
+ EM.run do
18
+ EM.start_server("127.0.0.1", 9292, BadServer)
19
+ $stderr.puts "ready"
20
+ end
@@ -94,6 +94,7 @@ Shindo.tests('Excon stubs') do
94
94
  end
95
95
  end
96
96
 
97
+ Excon.stubs.clear
97
98
  Excon.mock = false
98
99
 
99
100
  tests('mock = false') do
@@ -73,3 +73,17 @@ def with_rackup(name)
73
73
  ensure
74
74
  Process.kill(9, pid)
75
75
  end
76
+
77
+ def server_path(*parts)
78
+ File.expand_path(File.join(File.dirname(__FILE__), 'servers', *parts))
79
+ end
80
+
81
+ def with_server(name)
82
+ GC.disable
83
+ pid, w, r, e = Open4.popen4(server_path("#{name}.rb"))
84
+ until e.gets =~ /ready/; end
85
+ yield
86
+ ensure
87
+ GC.enable
88
+ Process.kill(9, pid)
89
+ end
metadata CHANGED
@@ -1,89 +1,67 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: excon
3
- version: !ruby/object:Gem::Version
4
- hash: 15
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.7
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 7
9
- - 6
10
- version: 0.7.6
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - geemus (Wesley Beary)
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-10-04 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2011-11-24 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: open4
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &70352462409660 !ruby/object:Gem::Requirement
24
17
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 3
29
- segments:
30
- - 0
31
- version: "0"
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
32
22
  type: :development
33
- version_requirements: *id001
34
- - !ruby/object:Gem::Dependency
35
- name: rake
36
23
  prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *70352462409660
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70352462407680 !ruby/object:Gem::Requirement
38
28
  none: false
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- hash: 3
43
- segments:
44
- - 0
45
- version: "0"
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
46
33
  type: :development
47
- version_requirements: *id002
48
- - !ruby/object:Gem::Dependency
49
- name: shindo
50
34
  prerelease: false
51
- requirement: &id003 !ruby/object:Gem::Requirement
35
+ version_requirements: *70352462407680
36
+ - !ruby/object:Gem::Dependency
37
+ name: shindo
38
+ requirement: &70352462405960 !ruby/object:Gem::Requirement
52
39
  none: false
53
- requirements:
54
- - - "="
55
- - !ruby/object:Gem::Version
56
- hash: 23
57
- segments:
58
- - 0
59
- - 2
60
- - 0
40
+ requirements:
41
+ - - =
42
+ - !ruby/object:Gem::Version
61
43
  version: 0.2.0
62
44
  type: :development
63
- version_requirements: *id003
64
- - !ruby/object:Gem::Dependency
65
- name: sinatra
66
45
  prerelease: false
67
- requirement: &id004 !ruby/object:Gem::Requirement
46
+ version_requirements: *70352462405960
47
+ - !ruby/object:Gem::Dependency
48
+ name: sinatra
49
+ requirement: &70352462404780 !ruby/object:Gem::Requirement
68
50
  none: false
69
- requirements:
70
- - - ">="
71
- - !ruby/object:Gem::Version
72
- hash: 3
73
- segments:
74
- - 0
75
- version: "0"
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
76
55
  type: :development
77
- version_requirements: *id004
56
+ prerelease: false
57
+ version_requirements: *70352462404780
78
58
  description: EXtended http(s) CONnections
79
59
  email: geemus@gmail.com
80
60
  executables: []
81
-
82
61
  extensions: []
83
-
84
- extra_rdoc_files:
62
+ extra_rdoc_files:
85
63
  - README.rdoc
86
- files:
64
+ files:
87
65
  - Gemfile
88
66
  - README.rdoc
89
67
  - Rakefile
@@ -113,6 +91,7 @@ files:
113
91
  - lib/excon/response.rb
114
92
  - lib/excon/socket.rb
115
93
  - lib/excon/ssl_socket.rb
94
+ - tests/bad_tests.rb
116
95
  - tests/basic_tests.rb
117
96
  - tests/header_tests.rb
118
97
  - tests/idempotent_tests.rb
@@ -126,41 +105,33 @@ files:
126
105
  - tests/rackups/ssl.ru
127
106
  - tests/rackups/thread_safety.ru
128
107
  - tests/request_method_tests.rb
108
+ - tests/servers/bad.rb
129
109
  - tests/stub_tests.rb
130
110
  - tests/test_helper.rb
131
111
  - tests/thread_safety_tests.rb
132
112
  homepage: https://github.com/geemus/excon
133
113
  licenses: []
134
-
135
114
  post_install_message:
136
- rdoc_options:
115
+ rdoc_options:
137
116
  - --charset=UTF-8
138
- require_paths:
117
+ require_paths:
139
118
  - lib
140
- required_ruby_version: !ruby/object:Gem::Requirement
119
+ required_ruby_version: !ruby/object:Gem::Requirement
141
120
  none: false
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- hash: 3
146
- segments:
147
- - 0
148
- version: "0"
149
- required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
126
  none: false
151
- requirements:
152
- - - ">="
153
- - !ruby/object:Gem::Version
154
- hash: 3
155
- segments:
156
- - 0
157
- version: "0"
127
+ requirements:
128
+ - - ! '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
158
131
  requirements: []
159
-
160
132
  rubyforge_project: excon
161
- rubygems_version: 1.8.5
133
+ rubygems_version: 1.8.10
162
134
  signing_key:
163
135
  specification_version: 2
164
136
  summary: speed, persistence, http(s)
165
137
  test_files: []
166
-