excon 0.5.8 → 0.6.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.

data/README.rdoc CHANGED
@@ -27,7 +27,10 @@ Both one off and persistent connections also support many other options, for exa
27
27
 
28
28
  You can also stream responses by passing a block that will receive each chunk.
29
29
 
30
- Excon.get('http://geemus.com') {|chunk| p chunk }
30
+ Excon.get('http://geemus.com') do |chunk, remaining_bytes, total_bytes|
31
+ puts chunk
32
+ puts "Remaining: #{remaining_bytes.to_f / total_bytes}%"
33
+ end
31
34
 
32
35
  These options can be combined to make pretty much any request you might need.
33
36
 
data/changelog.txt CHANGED
@@ -1,3 +1,10 @@
1
+ 0.6.0 03/30/11
2
+ ==============
3
+
4
+ * basic support for using proxies. thanks mattsa
5
+ * yield remaining/total bytes to streaming block. thanks nate
6
+ * minor optimizations/cleanup
7
+
1
8
  0.5.8 03/24/11
2
9
  ==============
3
10
 
data/excon.gemspec CHANGED
@@ -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.5.8'
17
- s.date = '2011-03-24'
16
+ s.version = '0.6.0'
17
+ s.date = '2011-03-30'
18
18
  s.rubyforge_project = 'excon'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -89,8 +89,10 @@ Gem::Specification.new do |s|
89
89
  lib/excon/errors.rb
90
90
  lib/excon/response.rb
91
91
  tests/basic_tests.rb
92
+ tests/proxy_tests.rb
92
93
  tests/query_string_tests.rb
93
94
  tests/rackups/basic.ru
95
+ tests/rackups/proxy.ru
94
96
  tests/rackups/query_string.ru
95
97
  tests/rackups/thread_safety.ru
96
98
  tests/stub_tests.rb
data/lib/excon.rb CHANGED
@@ -13,7 +13,7 @@ require 'excon/response'
13
13
 
14
14
  module Excon
15
15
  unless const_defined?(:VERSION)
16
- VERSION = '0.5.8'
16
+ VERSION = '0.6.0'
17
17
  end
18
18
 
19
19
  unless const_defined?(:CHUNK_SIZE)
@@ -1,6 +1,6 @@
1
1
  module Excon
2
2
  class Connection
3
- attr_reader :connection
3
+ attr_reader :connection, :proxy
4
4
 
5
5
  CR_NL = "\r\n"
6
6
  HTTP_1_1 = " HTTP/1.1\r\n"
@@ -16,18 +16,23 @@ module Excon
16
16
  # @option params [Fixnum] :port The port on which to connect, to the destination host
17
17
  # @option params [Hash] :query Default query; appended to the 'scheme://host:port/path/' in the form of '?key=value'. Will only be used if params[:query] is not supplied to Connection#request
18
18
  # @option params [String] :scheme The protocol; 'https' causes OpenSSL to be used
19
+ # @option params [String] :proxy Proxy server; e.g. 'http://myproxy.com:8888'
19
20
  def initialize(url, params = {})
20
21
  uri = URI.parse(url)
21
22
  @connection = {
22
23
  :headers => {},
23
24
  :host => uri.host,
24
25
  :path => uri.path,
25
- :port => uri.port,
26
+ :port => uri.port.to_s,
26
27
  :query => uri.query,
27
28
  :scheme => uri.scheme
28
29
  }.merge!(params)
29
30
 
30
- @socket_key = '' << @connection[:host] << ':' << @connection[:port].to_s
31
+ if params.has_key?(:proxy)
32
+ @connection[:headers]['Proxy-Connection'] ||= 'Keep-Alive'
33
+ setup_proxy(params[:proxy])
34
+ end
35
+ @socket_key = '' << @connection[:host] << ':' << @connection[:port]
31
36
  reset
32
37
  end
33
38
 
@@ -46,7 +51,7 @@ module Excon
46
51
  # connection has defaults, merge in new params to override
47
52
  params = @connection.merge(params)
48
53
  params[:headers] = @connection[:headers].merge(params[:headers] || {})
49
- params[:headers]['Host'] ||= '' << params[:host] << ':' << params[:port].to_s
54
+ params[:headers]['Host'] ||= '' << params[:host] << ':' << params[:port]
50
55
 
51
56
  # if path is empty or doesn't start with '/', insert one
52
57
  unless params[:path][0, 1] == '/'
@@ -64,7 +69,11 @@ module Excon
64
69
  end
65
70
 
66
71
  # start with "METHOD /path"
67
- request = params[:method].to_s.upcase << ' ' << params[:path]
72
+ request = params[:method].to_s.upcase << ' '
73
+ if @proxy
74
+ request << params[:scheme] << '://' << params[:host] << ':' << params[:port]
75
+ end
76
+ request << params[:path]
68
77
 
69
78
  # add query to path, if there is one
70
79
  case params[:query]
@@ -73,15 +82,12 @@ module Excon
73
82
  when Hash
74
83
  request << '?'
75
84
  for key, values in params[:query]
76
- case values
77
- when nil
85
+ if values.nil?
78
86
  request << key.to_s << '&'
79
- when Array
80
- values.each do |value|
87
+ else
88
+ for value in [*values]
81
89
  request << key.to_s << '=' << CGI.escape(value.to_s) << '&'
82
90
  end
83
- else
84
- request << key.to_s << '=' << CGI.escape(values.to_s) << '&'
85
91
  end
86
92
  end
87
93
  request.chop! # remove trailing '&'
@@ -180,7 +186,7 @@ module Excon
180
186
 
181
187
  private
182
188
  def connect
183
- new_socket = TCPSocket.open(@connection[:host], @connection[:port])
189
+ new_socket = open_socket
184
190
 
185
191
  if @connection[:scheme] == 'https'
186
192
  # create ssl context
@@ -219,6 +225,15 @@ module Excon
219
225
 
220
226
  new_socket
221
227
  end
228
+
229
+ def open_socket
230
+ if @proxy
231
+ socket = TCPSocket.open(@proxy[:host], @proxy[:port])
232
+ else
233
+ socket = TCPSocket.open(@connection[:host], @connection[:port])
234
+ end
235
+ socket
236
+ end
222
237
 
223
238
  def socket
224
239
  sockets[@socket_key] ||= connect
@@ -227,6 +242,18 @@ module Excon
227
242
  def sockets
228
243
  Thread.current[:_excon_sockets] ||= {}
229
244
  end
245
+
246
+ def setup_proxy(proxy)
247
+ uri = URI.parse(proxy)
248
+ unless uri.host and uri.port and uri.scheme
249
+ raise Excon::Errors::ProxyParseError, "Proxy is invalid"
250
+ end
251
+ @proxy = {
252
+ :host => uri.host,
253
+ :port => uri.port,
254
+ :scheme => uri.scheme
255
+ }
256
+ end
230
257
 
231
258
  end
232
259
  end
data/lib/excon/errors.rb CHANGED
@@ -17,6 +17,8 @@ module Excon
17
17
  end
18
18
  end
19
19
 
20
+ class ProxyParseError < Error; end
21
+
20
22
  class HTTPStatusError < Error
21
23
  attr_reader :request, :response
22
24
 
@@ -44,7 +44,7 @@ module Excon
44
44
  else
45
45
  remaining = content_length
46
46
  while remaining > 0
47
- yield socket.read([CHUNK_SIZE, remaining].min)
47
+ yield socket.read([CHUNK_SIZE, remaining].min), [remaining - CHUNK_SIZE, 0].max, content_length
48
48
  remaining -= CHUNK_SIZE
49
49
  end
50
50
  end
@@ -0,0 +1,64 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ Shindo.tests('Excon proxy support') do
4
+
5
+ tests('proxy configuration') do
6
+
7
+ tests('no proxy') do
8
+ connection = Excon.new('http://foo.com')
9
+
10
+ tests('connection.proxy').returns(nil) do
11
+ connection.proxy
12
+ end
13
+ end
14
+
15
+ tests('with fully-specified proxy: https://myproxy.net:8080') do
16
+ connection = Excon.new('http://foo.com', :proxy => 'https://myproxy.net:8080')
17
+
18
+ tests('connection.proxy.host').returns('myproxy.net') do
19
+ connection.proxy[:host]
20
+ end
21
+
22
+ tests('connection.proxy.port').returns(8080) do
23
+ connection.proxy[:port]
24
+ end
25
+
26
+ tests('connection.proxy.scheme').returns('https') do
27
+ connection.proxy[:scheme]
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ with_rackup('proxy.ru') do
34
+
35
+ tests('http proxying: http://foo.com:8080') do
36
+ connection = Excon.new('http://foo.com:8080', :proxy => 'http://localhost:9292')
37
+ response = connection.request(:method => :get, :path => '/bar', :query => {:alpha => 'kappa'})
38
+
39
+ tests('response.status').returns(200) do
40
+ response.status
41
+ end
42
+
43
+ # must be absolute form for proxy requests
44
+ tests('sent Request URI').returns('http://foo.com:8080/bar?alpha=kappa') do
45
+ response.headers['Sent-Request-Uri']
46
+ end
47
+
48
+ tests('sent Host header').returns('foo.com:8080') do
49
+ response.headers['Sent-Host']
50
+ end
51
+
52
+ tests('sent Proxy-Connection header').returns('Keep-Alive') do
53
+ response.headers['Sent-Proxy-Connection']
54
+ end
55
+
56
+ tests('response.body (proxied content)').returns('proxied content') do
57
+ response.body
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+
@@ -31,11 +31,11 @@ with_rackup('query_string.ru') do
31
31
  response = connection.request(:method => :get, :path => '/query', :query => {:foo => 'bar', :me => nil})
32
32
  query_string = response.body[7..-1] # query string sent
33
33
 
34
- tests("query string sent includes 'foo=bar'").returns(true) do
34
+ test("query string sent includes 'foo=bar'") do
35
35
  query_string.split('&').include?('foo=bar')
36
36
  end
37
37
 
38
- tests("query string sent includes 'me'").returns(true) do
38
+ test("query string sent includes 'me'") do
39
39
  query_string.split('&').include?('me')
40
40
  end
41
41
 
@@ -46,11 +46,11 @@ with_rackup('query_string.ru') do
46
46
  response = connection.request(:method => :get, :path => '/query', :query => {:foo => 'bar', :me => 'too'})
47
47
  query_string = response.body[7..-1] # query string sent
48
48
 
49
- tests("query string sent includes 'foo=bar'").returns(true) do
49
+ test("query string sent includes 'foo=bar'") do
50
50
  query_string.split('&').include?('foo=bar')
51
51
  end
52
52
 
53
- tests("query string sent includes 'me=too'").returns(true) do
53
+ test("query string sent includes 'me=too'") do
54
54
  query_string.split('&').include?('me=too')
55
55
  end
56
56
 
@@ -0,0 +1,12 @@
1
+ require 'sinatra'
2
+
3
+ class App < Sinatra::Base
4
+ get '/bar' do
5
+ headers "Sent-Request-Uri" => request.env['REQUEST_URI'].to_s,
6
+ "Sent-Host" => request.env['HTTP_HOST'].to_s,
7
+ "Sent-Proxy-Connection" => request.env['HTTP_PROXY_CONNECTION'].to_s
8
+ 'proxied content'
9
+ end
10
+ end
11
+
12
+ run App
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: excon
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 5
9
- - 8
10
- version: 0.5.8
8
+ - 6
9
+ - 0
10
+ version: 0.6.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - geemus (Wesley Beary)
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-03-24 00:00:00 -07:00
18
+ date: 2011-03-30 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -111,8 +111,10 @@ files:
111
111
  - lib/excon/errors.rb
112
112
  - lib/excon/response.rb
113
113
  - tests/basic_tests.rb
114
+ - tests/proxy_tests.rb
114
115
  - tests/query_string_tests.rb
115
116
  - tests/rackups/basic.ru
117
+ - tests/rackups/proxy.ru
116
118
  - tests/rackups/query_string.ru
117
119
  - tests/rackups/thread_safety.ru
118
120
  - tests/stub_tests.rb