excon 0.4.0 → 0.5.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/Gemfile.lock +55 -0
- data/README.rdoc +12 -14
- data/benchmarks/downcase-eq-eq_vs_casecmp.rb +169 -0
- data/benchmarks/has_key-vs-hash[key].rb +177 -0
- data/benchmarks/implicit_block-vs-explicit_block.rb +98 -0
- data/benchmarks/string_ranged_index.rb +87 -0
- data/excon.gemspec +13 -6
- data/lib/excon.rb +25 -36
- data/lib/excon/connection.rb +12 -12
- data/lib/excon/errors.rb +5 -1
- data/lib/excon/response.rb +43 -43
- data/tests/basic_tests.rb +39 -0
- data/tests/rackups/basic.ru +9 -0
- data/tests/{config.ru → rackups/thread_safety.ru} +0 -0
- data/tests/test_helper.rb +5 -5
- data/tests/thread_safety_tests.rb +28 -0
- metadata +20 -13
- data/tests/threaded_tests.rb +0 -24
data/Gemfile.lock
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
excon (0.4.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
addressable (2.2.2)
|
10
|
+
crack (0.1.8)
|
11
|
+
curb (0.7.8)
|
12
|
+
curl_ffi (0.0.8)
|
13
|
+
ffi
|
14
|
+
em-http-request (0.2.15)
|
15
|
+
addressable (>= 2.0.0)
|
16
|
+
eventmachine (>= 0.12.9)
|
17
|
+
eventmachine (0.12.10)
|
18
|
+
ffi (0.6.3)
|
19
|
+
rake (>= 0.8.7)
|
20
|
+
formatador (0.0.16)
|
21
|
+
httparty (0.6.1)
|
22
|
+
crack (= 0.1.8)
|
23
|
+
mime-types (1.16)
|
24
|
+
open4 (1.0.1)
|
25
|
+
rack (1.2.1)
|
26
|
+
rake (0.8.7)
|
27
|
+
rest-client (1.6.1)
|
28
|
+
mime-types (>= 1.16)
|
29
|
+
shindo (0.2.0)
|
30
|
+
formatador (>= 0.0.16)
|
31
|
+
sinatra (1.1.0)
|
32
|
+
rack (~> 1.1)
|
33
|
+
tilt (~> 1.1)
|
34
|
+
streamly_ffi (0.2.6)
|
35
|
+
curl_ffi
|
36
|
+
tach (0.0.8)
|
37
|
+
formatador (>= 0.0.16)
|
38
|
+
tilt (1.1)
|
39
|
+
typhoeus (0.2.0)
|
40
|
+
|
41
|
+
PLATFORMS
|
42
|
+
ruby
|
43
|
+
|
44
|
+
DEPENDENCIES
|
45
|
+
curb
|
46
|
+
em-http-request
|
47
|
+
excon!
|
48
|
+
httparty
|
49
|
+
open4
|
50
|
+
rest-client
|
51
|
+
shindo (= 0.2.0)
|
52
|
+
sinatra
|
53
|
+
streamly_ffi
|
54
|
+
tach (= 0.0.8)
|
55
|
+
typhoeus
|
data/README.rdoc
CHANGED
@@ -6,47 +6,45 @@ Http(s) EXtended CONnections
|
|
6
6
|
|
7
7
|
sudo gem install excon
|
8
8
|
|
9
|
-
Now you are ready to get started
|
9
|
+
Now you are ready to get started using one off requests.
|
10
10
|
|
11
11
|
require 'rubygems'
|
12
12
|
require 'excon'
|
13
13
|
Excon.get('http://geemus.com')
|
14
14
|
|
15
|
-
|
15
|
+
The returned response object has #body, #headers and #status attributes. Supported one off requests are #connect, #delete, #get, #head, #options, #post, #put, and #trace
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
You can also create a connection to try and keep open across multiple requests (more performant!).
|
17
|
+
You can also create a connection to reuse across multiple requests (more performant!).
|
20
18
|
|
21
19
|
connection = Excon.new('http://geemus.com')
|
22
20
|
connection.request(:method => 'GET')
|
23
21
|
|
24
|
-
|
22
|
+
Both one off and persistent connections also support many other options, for example:
|
25
23
|
|
26
24
|
Excon.get('http://geemus.com', :headers => {'Authorization' => 'Basic 0123456789ABCDEF'})
|
27
25
|
# or
|
28
26
|
connection.request(:method => 'GET', :headers => {'Authorization' => 'Basic 0123456789ABCDEF'})
|
29
27
|
|
30
|
-
|
28
|
+
You can also stream responses by passing a block that will receive each chunk.
|
31
29
|
|
32
30
|
Excon.get('http://geemus.com') {|chunk| p chunk }
|
33
31
|
|
34
|
-
|
32
|
+
These options can be combined to make pretty much any request you might need.
|
35
33
|
|
36
34
|
== HTTPS/SSL Issues
|
37
35
|
|
38
|
-
|
36
|
+
By default excon will try to verify peer certificates when using ssl for https, unfortunately on some operating systems the defaults will not work. This will likely manifest itself as something like "Excon::Errors::SocketError: SSL_connect returned=1 ..."
|
37
|
+
|
38
|
+
If you have the misfortune of running into this problem you have a couple options. First, if you have certificates in a location that defaults fail to locate you can set a different path to certificates:
|
39
39
|
|
40
|
-
require 'rubygems'
|
41
|
-
require 'excon'
|
42
40
|
Excon.ssl_ca_path = '/path/to/certs'
|
43
41
|
|
44
|
-
or,
|
42
|
+
or failing that, you can turn off peer verification (less secure):
|
45
43
|
|
46
|
-
require 'rubygems'
|
47
|
-
require 'excon'
|
48
44
|
Excon.ssl_verify_peer = false
|
49
45
|
|
46
|
+
Either of these should allow you to work around the socket error and continue with getting your work done.
|
47
|
+
|
50
48
|
== Copyright
|
51
49
|
|
52
50
|
(The MIT License)
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# Copied from my benchmark_hell repo: github.com/sgonyea/benchmark_hell
|
2
|
+
|
3
|
+
require 'benchmark'
|
4
|
+
|
5
|
+
iters = 1000000
|
6
|
+
|
7
|
+
comp = "hello"
|
8
|
+
hello = "HelLo"
|
9
|
+
|
10
|
+
puts 'String#downcase == vs. String#casecmp'
|
11
|
+
Benchmark.bmbm do |x|
|
12
|
+
x.report('String#downcase1') do
|
13
|
+
iters.times.each do
|
14
|
+
hello.downcase == comp
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
x.report('String#downcase2') do
|
19
|
+
iters.times.each do
|
20
|
+
"HelLo".downcase == "hello"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
x.report('String#downcase3') do
|
25
|
+
iters.times.each do
|
26
|
+
var = "HelLo"
|
27
|
+
var.downcase!
|
28
|
+
var == "hello"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
x.report('casecmp1') do
|
33
|
+
iters.times.each do
|
34
|
+
hello.casecmp(comp).zero?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
x.report('casecmp1-1') do
|
39
|
+
iters.times.each do
|
40
|
+
hello.casecmp(comp) == 0
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
x.report('casecmp2') do
|
45
|
+
iters.times.each do
|
46
|
+
"HelLo".casecmp(comp).zero?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
x.report('casecmp2-1') do
|
51
|
+
iters.times.each do
|
52
|
+
"HelLo".casecmp(comp) == 0
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
=begin
|
58
|
+
rvm exec bash -c 'echo && echo $RUBY_VERSION && echo && ruby downcase-eq-eq_vs_casecmp.rb'
|
59
|
+
|
60
|
+
jruby-1.5.6
|
61
|
+
|
62
|
+
String#downcase == vs. String#casecmp
|
63
|
+
Rehearsal ----------------------------------------------------
|
64
|
+
String#downcase1 0.461000 0.000000 0.461000 ( 0.387000)
|
65
|
+
String#downcase2 0.269000 0.000000 0.269000 ( 0.269000)
|
66
|
+
String#downcase3 0.224000 0.000000 0.224000 ( 0.224000)
|
67
|
+
casecmp1 0.157000 0.000000 0.157000 ( 0.157000)
|
68
|
+
casecmp1-1 0.153000 0.000000 0.153000 ( 0.153000)
|
69
|
+
casecmp2 0.163000 0.000000 0.163000 ( 0.163000)
|
70
|
+
casecmp2-1 0.163000 0.000000 0.163000 ( 0.163000)
|
71
|
+
------------------------------------------- total: 1.590000sec
|
72
|
+
|
73
|
+
user system total real
|
74
|
+
String#downcase1 0.190000 0.000000 0.190000 ( 0.191000)
|
75
|
+
String#downcase2 0.225000 0.000000 0.225000 ( 0.225000)
|
76
|
+
String#downcase3 0.190000 0.000000 0.190000 ( 0.190000)
|
77
|
+
casecmp1 0.125000 0.000000 0.125000 ( 0.125000)
|
78
|
+
casecmp1-1 0.127000 0.000000 0.127000 ( 0.127000)
|
79
|
+
casecmp2 0.144000 0.000000 0.144000 ( 0.144000)
|
80
|
+
casecmp2-1 0.147000 0.000000 0.147000 ( 0.147000)
|
81
|
+
|
82
|
+
macruby-0.7.1
|
83
|
+
|
84
|
+
String#downcase == vs. String#casecmp
|
85
|
+
Rehearsal ----------------------------------------------------
|
86
|
+
String#downcase1 2.340000 0.040000 2.380000 ( 1.765141)
|
87
|
+
String#downcase2 5.510000 0.100000 5.610000 ( 3.893249)
|
88
|
+
String#downcase3 4.200000 0.080000 4.280000 ( 3.031621)
|
89
|
+
casecmp1 0.270000 0.000000 0.270000 ( 0.267613)
|
90
|
+
casecmp1-1 0.190000 0.000000 0.190000 ( 0.188848)
|
91
|
+
casecmp2 1.450000 0.020000 1.470000 ( 1.027956)
|
92
|
+
casecmp2-1 1.380000 0.030000 1.410000 ( 0.951474)
|
93
|
+
------------------------------------------ total: 15.610000sec
|
94
|
+
|
95
|
+
user system total real
|
96
|
+
String#downcase1 2.350000 0.040000 2.390000 ( 1.774292)
|
97
|
+
String#downcase2 5.890000 0.120000 6.010000 ( 4.214038)
|
98
|
+
String#downcase3 4.530000 0.090000 4.620000 ( 3.286059)
|
99
|
+
casecmp1 0.270000 0.000000 0.270000 ( 0.271119)
|
100
|
+
casecmp1-1 0.190000 0.000000 0.190000 ( 0.189462)
|
101
|
+
casecmp2 1.540000 0.030000 1.570000 ( 1.104751)
|
102
|
+
casecmp2-1 1.440000 0.030000 1.470000 ( 0.999689)
|
103
|
+
|
104
|
+
rbx-head
|
105
|
+
|
106
|
+
String#downcase == vs. String#casecmp
|
107
|
+
Rehearsal ----------------------------------------------------
|
108
|
+
String#downcase1 0.702746 0.005229 0.707975 ( 0.621969)
|
109
|
+
String#downcase2 0.701429 0.001617 0.703046 ( 0.691833)
|
110
|
+
String#downcase3 1.042835 0.002952 1.045787 ( 0.953992)
|
111
|
+
casecmp1 0.654571 0.002239 0.656810 ( 0.480158)
|
112
|
+
casecmp1-1 0.484706 0.001105 0.485811 ( 0.398601)
|
113
|
+
casecmp2 0.564140 0.001579 0.565719 ( 0.545332)
|
114
|
+
casecmp2-1 0.554889 0.001153 0.556042 ( 0.539569)
|
115
|
+
------------------------------------------- total: 4.721190sec
|
116
|
+
|
117
|
+
user system total real
|
118
|
+
String#downcase1 0.491199 0.001081 0.492280 ( 0.493727)
|
119
|
+
String#downcase2 0.631059 0.001018 0.632077 ( 0.629885)
|
120
|
+
String#downcase3 0.968867 0.002504 0.971371 ( 0.976734)
|
121
|
+
casecmp1 0.364496 0.000434 0.364930 ( 0.365262)
|
122
|
+
casecmp1-1 0.373140 0.000562 0.373702 ( 0.374136)
|
123
|
+
casecmp2 0.487644 0.001057 0.488701 ( 0.490302)
|
124
|
+
casecmp2-1 0.469868 0.001178 0.471046 ( 0.472220)
|
125
|
+
|
126
|
+
ruby-1.8.7-p330
|
127
|
+
|
128
|
+
String#downcase == vs. String#casecmp
|
129
|
+
Rehearsal ----------------------------------------------------
|
130
|
+
String#downcase1 0.780000 0.000000 0.780000 ( 0.783979)
|
131
|
+
String#downcase2 0.950000 0.000000 0.950000 ( 0.954109)
|
132
|
+
String#downcase3 0.960000 0.000000 0.960000 ( 0.960554)
|
133
|
+
casecmp1 0.440000 0.000000 0.440000 ( 0.442546)
|
134
|
+
casecmp1-1 0.490000 0.000000 0.490000 ( 0.487795)
|
135
|
+
casecmp2 0.530000 0.000000 0.530000 ( 0.535819)
|
136
|
+
casecmp2-1 0.570000 0.000000 0.570000 ( 0.574653)
|
137
|
+
------------------------------------------- total: 4.720000sec
|
138
|
+
|
139
|
+
user system total real
|
140
|
+
String#downcase1 0.780000 0.000000 0.780000 ( 0.780692)
|
141
|
+
String#downcase2 0.980000 0.010000 0.990000 ( 0.982925)
|
142
|
+
String#downcase3 0.960000 0.000000 0.960000 ( 0.961501)
|
143
|
+
casecmp1 0.440000 0.000000 0.440000 ( 0.444528)
|
144
|
+
casecmp1-1 0.490000 0.000000 0.490000 ( 0.487437)
|
145
|
+
casecmp2 0.540000 0.000000 0.540000 ( 0.537686)
|
146
|
+
casecmp2-1 0.570000 0.000000 0.570000 ( 0.574253)
|
147
|
+
|
148
|
+
ruby-1.9.2-p136
|
149
|
+
|
150
|
+
String#downcase == vs. String#casecmp
|
151
|
+
Rehearsal ----------------------------------------------------
|
152
|
+
String#downcase1 0.750000 0.000000 0.750000 ( 0.750523)
|
153
|
+
String#downcase2 1.190000 0.000000 1.190000 ( 1.193346)
|
154
|
+
String#downcase3 1.030000 0.010000 1.040000 ( 1.036435)
|
155
|
+
casecmp1 0.640000 0.000000 0.640000 ( 0.640327)
|
156
|
+
casecmp1-1 0.480000 0.000000 0.480000 ( 0.484709) # With all this crap running, some flukes pop out
|
157
|
+
casecmp2 0.820000 0.000000 0.820000 ( 0.822223)
|
158
|
+
casecmp2-1 0.660000 0.000000 0.660000 ( 0.664190)
|
159
|
+
------------------------------------------- total: 5.580000sec
|
160
|
+
|
161
|
+
user system total real
|
162
|
+
String#downcase1 0.760000 0.000000 0.760000 ( 0.759816)
|
163
|
+
String#downcase2 1.150000 0.010000 1.160000 ( 1.150792)
|
164
|
+
String#downcase3 1.000000 0.000000 1.000000 ( 1.005549)
|
165
|
+
casecmp1 0.650000 0.000000 0.650000 ( 0.644021)
|
166
|
+
casecmp1-1 0.490000 0.000000 0.490000 ( 0.494456)
|
167
|
+
casecmp2 0.820000 0.000000 0.820000 ( 0.817689)
|
168
|
+
casecmp2-1 0.680000 0.000000 0.680000 ( 0.685121)
|
169
|
+
=end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# Copied from my benchmark_hell repo: github.com/sgonyea/benchmark_hell
|
2
|
+
|
3
|
+
require 'benchmark'
|
4
|
+
|
5
|
+
iters = 1000000
|
6
|
+
hash = {
|
7
|
+
'some_key' => 'some_val',
|
8
|
+
'nil_key' => nil
|
9
|
+
}
|
10
|
+
|
11
|
+
puts 'Hash#has_key vs. Hash#[]'
|
12
|
+
Benchmark.bmbm do |x|
|
13
|
+
x.report('Hash#has_key') do
|
14
|
+
iters.times.each do
|
15
|
+
hash.has_key? 'some_key'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
x.report('Hash#has_key (if statement)') do
|
20
|
+
iters.times.each do
|
21
|
+
if hash.has_key?('other_key')
|
22
|
+
"hooray!"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
x.report('Hash#has_key (non-existant)') do
|
28
|
+
iters.times.each do
|
29
|
+
hash.has_key? 'other_key'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
x.report('Hash#[]') do
|
34
|
+
iters.times.each do
|
35
|
+
hash['some_key']
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
x.report('Hash#[] (if statement)') do
|
40
|
+
iters.times.each do
|
41
|
+
if hash['some_key']
|
42
|
+
"hooray!"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
x.report('Hash#[] (non-existant)') do
|
48
|
+
iters.times.each do
|
49
|
+
hash['other_key']
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
x.report('Hash#has_key (if statement) explicit nil check') do
|
54
|
+
iters.times.each do
|
55
|
+
if hash.has_key?('nil_key') && !hash['nil_key'].nil?
|
56
|
+
"hooray!"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
x.report('Hash#has_key (if statement) implicit nil check') do
|
63
|
+
iters.times.each do
|
64
|
+
if hash.has_key?('nil_key') && hash['nil_key']
|
65
|
+
"hooray!"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
x.report('Hash#[] (if statement with nil)') do
|
71
|
+
iters.times.each do
|
72
|
+
if hash['nil_key']
|
73
|
+
"hooray!"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
=begin
|
80
|
+
|
81
|
+
$ rvm exec bash -c 'echo $RUBY_VERSION && ruby has_key-vs-hash\[key\].rb'
|
82
|
+
|
83
|
+
jruby-1.5.6
|
84
|
+
Hash#has_key vs. Hash#[]
|
85
|
+
Rehearsal ---------------------------------------------------------------
|
86
|
+
Hash#has_key 0.410000 0.000000 0.410000 ( 0.341000)
|
87
|
+
Hash#has_key (if statement) 0.145000 0.000000 0.145000 ( 0.145000)
|
88
|
+
Hash#has_key (non-existant) 0.116000 0.000000 0.116000 ( 0.116000)
|
89
|
+
Hash#[] 0.189000 0.000000 0.189000 ( 0.189000)
|
90
|
+
Hash#[] (if statement) 0.176000 0.000000 0.176000 ( 0.176000)
|
91
|
+
Hash#[] (non-existant) 0.302000 0.000000 0.302000 ( 0.302000)
|
92
|
+
------------------------------------------------------ total: 1.338000sec
|
93
|
+
|
94
|
+
user system total real
|
95
|
+
Hash#has_key 0.128000 0.000000 0.128000 ( 0.128000)
|
96
|
+
Hash#has_key (if statement) 0.128000 0.000000 0.128000 ( 0.128000)
|
97
|
+
Hash#has_key (non-existant) 0.153000 0.000000 0.153000 ( 0.153000)
|
98
|
+
Hash#[] 0.206000 0.000000 0.206000 ( 0.206000)
|
99
|
+
Hash#[] (if statement) 0.182000 0.000000 0.182000 ( 0.182000)
|
100
|
+
Hash#[] (non-existant) 0.252000 0.000000 0.252000 ( 0.252000)
|
101
|
+
|
102
|
+
macruby-0.7.1
|
103
|
+
Hash#has_key vs. Hash#[]
|
104
|
+
Rehearsal ---------------------------------------------------------------
|
105
|
+
Hash#has_key 2.530000 0.050000 2.580000 ( 1.917643)
|
106
|
+
Hash#has_key (if statement) 2.590000 0.050000 2.640000 ( 1.935221)
|
107
|
+
Hash#has_key (non-existant) 2.580000 0.050000 2.630000 ( 1.964230)
|
108
|
+
Hash#[] 2.240000 0.040000 2.280000 ( 1.640999)
|
109
|
+
Hash#[] (if statement) 3.620000 0.070000 3.690000 ( 2.530248)
|
110
|
+
Hash#[] (non-existant) 2.060000 0.040000 2.100000 ( 1.473487)
|
111
|
+
----------------------------------------------------- total: 15.920000sec
|
112
|
+
|
113
|
+
user system total real
|
114
|
+
Hash#has_key 2.230000 0.030000 2.260000 ( 1.661843)
|
115
|
+
Hash#has_key (if statement) 2.180000 0.040000 2.220000 ( 1.605644)
|
116
|
+
Hash#has_key (non-existant) 2.160000 0.040000 2.200000 ( 1.582561)
|
117
|
+
Hash#[] 2.160000 0.030000 2.190000 ( 1.581448)
|
118
|
+
Hash#[] (if statement) 3.440000 0.070000 3.510000 ( 2.393421)
|
119
|
+
Hash#[] (non-existant) 2.330000 0.040000 2.370000 ( 1.699338)
|
120
|
+
|
121
|
+
rbx-head
|
122
|
+
Hash#has_key vs. Hash#[]
|
123
|
+
Rehearsal ---------------------------------------------------------------
|
124
|
+
Hash#has_key 0.660584 0.004932 0.665516 ( 0.508601)
|
125
|
+
Hash#has_key (if statement) 0.261708 0.000532 0.262240 ( 0.263021)
|
126
|
+
Hash#has_key (non-existant) 0.265908 0.000827 0.266735 ( 0.259509)
|
127
|
+
Hash#[] 0.396607 0.001189 0.397796 ( 0.372997)
|
128
|
+
Hash#[] (if statement) 0.553003 0.001589 0.554592 ( 0.543859)
|
129
|
+
Hash#[] (non-existant) 0.323748 0.000884 0.324632 ( 0.319055)
|
130
|
+
------------------------------------------------------ total: 2.471511sec
|
131
|
+
|
132
|
+
user system total real
|
133
|
+
Hash#has_key 0.332239 0.000819 0.333058 ( 0.333809)
|
134
|
+
Hash#has_key (if statement) 0.284344 0.000521 0.284865 ( 0.285330)
|
135
|
+
Hash#has_key (non-existant) 0.339695 0.001301 0.340996 ( 0.324259)
|
136
|
+
Hash#[] 0.298555 0.000368 0.298923 ( 0.299557)
|
137
|
+
Hash#[] (if statement) 0.392755 0.000773 0.393528 ( 0.395473)
|
138
|
+
Hash#[] (non-existant) 0.277721 0.000464 0.278185 ( 0.278540)
|
139
|
+
|
140
|
+
ruby-1.8.7-p330
|
141
|
+
Hash#has_key vs. Hash#[]
|
142
|
+
Rehearsal ---------------------------------------------------------------
|
143
|
+
Hash#has_key 0.450000 0.000000 0.450000 ( 0.450143)
|
144
|
+
Hash#has_key (if statement) 0.440000 0.000000 0.440000 ( 0.448278)
|
145
|
+
Hash#has_key (non-existant) 0.420000 0.000000 0.420000 ( 0.416959)
|
146
|
+
Hash#[] 0.450000 0.000000 0.450000 ( 0.450727)
|
147
|
+
Hash#[] (if statement) 0.550000 0.000000 0.550000 ( 0.555043)
|
148
|
+
Hash#[] (non-existant) 0.530000 0.000000 0.530000 ( 0.527189)
|
149
|
+
------------------------------------------------------ total: 2.840000sec
|
150
|
+
|
151
|
+
user system total real
|
152
|
+
Hash#has_key 0.440000 0.000000 0.440000 ( 0.447746)
|
153
|
+
Hash#has_key (if statement) 0.450000 0.000000 0.450000 ( 0.450331)
|
154
|
+
Hash#has_key (non-existant) 0.420000 0.000000 0.420000 ( 0.419157)
|
155
|
+
Hash#[] 0.450000 0.000000 0.450000 ( 0.454438)
|
156
|
+
Hash#[] (if statement) 0.570000 0.000000 0.570000 ( 0.563948)
|
157
|
+
Hash#[] (non-existant) 0.520000 0.000000 0.520000 ( 0.527866)
|
158
|
+
|
159
|
+
ruby-1.9.2-p136
|
160
|
+
Hash#has_key vs. Hash#[]
|
161
|
+
Rehearsal ---------------------------------------------------------------
|
162
|
+
Hash#has_key 0.690000 0.000000 0.690000 ( 0.691657)
|
163
|
+
Hash#has_key (if statement) 0.630000 0.000000 0.630000 ( 0.638418)
|
164
|
+
Hash#has_key (non-existant) 0.640000 0.000000 0.640000 ( 0.637510)
|
165
|
+
Hash#[] 0.580000 0.000000 0.580000 ( 0.584500)
|
166
|
+
Hash#[] (if statement) 0.840000 0.010000 0.850000 ( 0.837541)
|
167
|
+
Hash#[] (non-existant) 0.810000 0.000000 0.810000 ( 0.811598)
|
168
|
+
------------------------------------------------------ total: 4.200000sec
|
169
|
+
|
170
|
+
user system total real
|
171
|
+
Hash#has_key 0.690000 0.000000 0.690000 ( 0.694192)
|
172
|
+
Hash#has_key (if statement) 0.640000 0.000000 0.640000 ( 0.641729)
|
173
|
+
Hash#has_key (non-existant) 0.630000 0.000000 0.630000 ( 0.634470)
|
174
|
+
Hash#[] 0.580000 0.000000 0.580000 ( 0.587844)
|
175
|
+
Hash#[] (if statement) 0.830000 0.000000 0.830000 ( 0.832323)
|
176
|
+
Hash#[] (non-existant) 0.790000 0.010000 0.800000 ( 0.791689)
|
177
|
+
=end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# Copied from my benchmark_hell repo: github.com/sgonyea/benchmark_hell
|
2
|
+
|
3
|
+
require 'benchmark'
|
4
|
+
|
5
|
+
iters = 1000000
|
6
|
+
|
7
|
+
def do_explicit(&block)
|
8
|
+
var = "hello"
|
9
|
+
block.call(var)
|
10
|
+
end
|
11
|
+
|
12
|
+
def do_implicit
|
13
|
+
var = "hello"
|
14
|
+
yield(var)
|
15
|
+
end
|
16
|
+
|
17
|
+
puts 'explicit block vs implicit'
|
18
|
+
Benchmark.bmbm do |x|
|
19
|
+
x.report('explicit') do
|
20
|
+
iters.times.each do
|
21
|
+
do_explicit {|var|
|
22
|
+
var << "goodbye"
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
x.report('implicit') do
|
28
|
+
iters.times.each do
|
29
|
+
do_implicit {|var|
|
30
|
+
var << "goodbye"
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
=begin
|
37
|
+
rvm exec bash -c 'echo && echo $RUBY_VERSION && echo && ruby implicit_block-vs-explicit_block.rb'
|
38
|
+
|
39
|
+
jruby-1.5.6
|
40
|
+
|
41
|
+
explicit block vs implicit
|
42
|
+
Rehearsal --------------------------------------------
|
43
|
+
explicit 1.163000 0.000000 1.163000 ( 1.106000)
|
44
|
+
implicit 0.499000 0.000000 0.499000 ( 0.499000)
|
45
|
+
----------------------------------- total: 1.662000sec
|
46
|
+
|
47
|
+
user system total real
|
48
|
+
explicit 0.730000 0.000000 0.730000 ( 0.730000)
|
49
|
+
implicit 0.453000 0.000000 0.453000 ( 0.453000)
|
50
|
+
|
51
|
+
macruby-0.7.1
|
52
|
+
|
53
|
+
explicit block vs implicit
|
54
|
+
Rehearsal --------------------------------------------
|
55
|
+
explicit 5.070000 0.130000 5.200000 ( 3.546388)
|
56
|
+
implicit 3.140000 0.050000 3.190000 ( 2.255986)
|
57
|
+
----------------------------------- total: 8.390000sec
|
58
|
+
|
59
|
+
user system total real
|
60
|
+
explicit 5.340000 0.140000 5.480000 ( 3.774963)
|
61
|
+
implicit 3.170000 0.060000 3.230000 ( 2.279951)
|
62
|
+
|
63
|
+
rbx-head
|
64
|
+
|
65
|
+
explicit block vs implicit
|
66
|
+
Rehearsal --------------------------------------------
|
67
|
+
explicit 1.270136 0.006507 1.276643 ( 1.181588)
|
68
|
+
implicit 0.839831 0.002203 0.842034 ( 0.820849)
|
69
|
+
----------------------------------- total: 2.118677sec
|
70
|
+
|
71
|
+
user system total real
|
72
|
+
explicit 0.960593 0.001526 0.962119 ( 0.966404)
|
73
|
+
implicit 0.700361 0.001126 0.701487 ( 0.703591)
|
74
|
+
|
75
|
+
ruby-1.8.7-p330
|
76
|
+
|
77
|
+
explicit block vs implicit
|
78
|
+
Rehearsal --------------------------------------------
|
79
|
+
explicit 3.970000 0.000000 3.970000 ( 3.985157)
|
80
|
+
implicit 1.560000 0.000000 1.560000 ( 1.567599)
|
81
|
+
----------------------------------- total: 5.530000sec
|
82
|
+
|
83
|
+
user system total real
|
84
|
+
explicit 3.990000 0.010000 4.000000 ( 4.002637)
|
85
|
+
implicit 1.560000 0.000000 1.560000 ( 1.560901)
|
86
|
+
|
87
|
+
ruby-1.9.2-p136
|
88
|
+
|
89
|
+
explicit block vs implicit
|
90
|
+
Rehearsal --------------------------------------------
|
91
|
+
explicit 2.620000 0.010000 2.630000 ( 2.633762)
|
92
|
+
implicit 1.080000 0.000000 1.080000 ( 1.076809)
|
93
|
+
----------------------------------- total: 3.710000sec
|
94
|
+
|
95
|
+
user system total real
|
96
|
+
explicit 2.630000 0.010000 2.640000 ( 2.637658)
|
97
|
+
implicit 1.070000 0.000000 1.070000 ( 1.073589)
|
98
|
+
=end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# Copied from my benchmark_hell repo: github.com/sgonyea/benchmark_hell
|
2
|
+
|
3
|
+
require 'benchmark'
|
4
|
+
|
5
|
+
iters = 1000000
|
6
|
+
|
7
|
+
string = "Test String OMG"
|
8
|
+
|
9
|
+
puts 'String ranged index vs. "coordinates"'
|
10
|
+
Benchmark.bmbm do |x|
|
11
|
+
x.report('ranged index') do
|
12
|
+
iters.times.each do
|
13
|
+
text = string[2..9]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
x.report('coordinates') do
|
18
|
+
iters.times.each do
|
19
|
+
text = string[2, 9]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
=begin
|
25
|
+
rvm exec bash -c 'echo && echo $RUBY_VERSION && echo && ruby string_ranged_index.rb'
|
26
|
+
|
27
|
+
|
28
|
+
jruby-1.5.6
|
29
|
+
|
30
|
+
String ranged index vs. "coordinates"
|
31
|
+
Rehearsal ------------------------------------------------
|
32
|
+
ranged index 0.419000 0.000000 0.419000 ( 0.372000)
|
33
|
+
coordinates 0.167000 0.000000 0.167000 ( 0.167000)
|
34
|
+
--------------------------------------- total: 0.586000sec
|
35
|
+
|
36
|
+
user system total real
|
37
|
+
ranged index 0.158000 0.000000 0.158000 ( 0.159000)
|
38
|
+
coordinates 0.125000 0.000000 0.125000 ( 0.125000)
|
39
|
+
|
40
|
+
macruby-0.7.1
|
41
|
+
|
42
|
+
String ranged index vs. "coordinates"
|
43
|
+
Rehearsal ------------------------------------------------
|
44
|
+
ranged index 1.490000 0.030000 1.520000 ( 1.061326)
|
45
|
+
coordinates 1.410000 0.030000 1.440000 ( 0.973640)
|
46
|
+
--------------------------------------- total: 2.960000sec
|
47
|
+
|
48
|
+
user system total real
|
49
|
+
ranged index 1.520000 0.030000 1.550000 ( 1.081424)
|
50
|
+
coordinates 1.480000 0.030000 1.510000 ( 1.029214)
|
51
|
+
|
52
|
+
rbx-head
|
53
|
+
|
54
|
+
String ranged index vs. "coordinates"
|
55
|
+
Rehearsal ------------------------------------------------
|
56
|
+
ranged index 1.333304 0.009398 1.342702 ( 1.229629)
|
57
|
+
coordinates 0.306087 0.000603 0.306690 ( 0.303538)
|
58
|
+
--------------------------------------- total: 1.649392sec
|
59
|
+
|
60
|
+
user system total real
|
61
|
+
ranged index 0.923626 0.001597 0.925223 ( 0.927411)
|
62
|
+
coordinates 0.298910 0.000533 0.299443 ( 0.300255)
|
63
|
+
|
64
|
+
ruby-1.8.7-p330
|
65
|
+
|
66
|
+
String ranged index vs. "coordinates"
|
67
|
+
Rehearsal ------------------------------------------------
|
68
|
+
ranged index 0.730000 0.000000 0.730000 ( 0.738612)
|
69
|
+
coordinates 0.660000 0.000000 0.660000 ( 0.660689)
|
70
|
+
--------------------------------------- total: 1.390000sec
|
71
|
+
|
72
|
+
user system total real
|
73
|
+
ranged index 0.750000 0.000000 0.750000 ( 0.746172)
|
74
|
+
coordinates 0.640000 0.000000 0.640000 ( 0.640687)
|
75
|
+
|
76
|
+
ruby-1.9.2-p136
|
77
|
+
|
78
|
+
String ranged index vs. "coordinates"
|
79
|
+
Rehearsal ------------------------------------------------
|
80
|
+
ranged index 0.670000 0.000000 0.670000 ( 0.679046)
|
81
|
+
coordinates 0.620000 0.000000 0.620000 ( 0.622257)
|
82
|
+
--------------------------------------- total: 1.290000sec
|
83
|
+
|
84
|
+
user system total real
|
85
|
+
ranged index 0.680000 0.000000 0.680000 ( 0.686510)
|
86
|
+
coordinates 0.620000 0.000000 0.620000 ( 0.624269)
|
87
|
+
=end
|
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.
|
17
|
-
s.date = '2011-
|
16
|
+
s.version = '0.5.0'
|
17
|
+
s.date = '2011-02-11'
|
18
18
|
s.rubyforge_project = 'excon'
|
19
19
|
|
20
20
|
## Make sure your summary is short. The description may be as long
|
@@ -27,7 +27,7 @@ Gem::Specification.new do |s|
|
|
27
27
|
## a custom homepage, consider using your GitHub URL or the like.
|
28
28
|
s.authors = ["geemus (Wesley Beary)"]
|
29
29
|
s.email = 'geemus@gmail.com'
|
30
|
-
s.homepage = '
|
30
|
+
s.homepage = 'https://github.com/geemus/excon'
|
31
31
|
|
32
32
|
## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
|
33
33
|
## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
|
@@ -54,7 +54,7 @@ Gem::Specification.new do |s|
|
|
54
54
|
## those that are only needed during development
|
55
55
|
# s.add_development_dependency('DEVDEPNAME', [">= 1.1.0", "< 2.0.0"])
|
56
56
|
s.add_development_dependency('open4')
|
57
|
-
s.add_development_dependency('shindo', '0.
|
57
|
+
s.add_development_dependency('shindo', '0.2.0')
|
58
58
|
s.add_development_dependency('sinatra')
|
59
59
|
|
60
60
|
## Leave this section as-is. It will be automatically generated from the
|
@@ -63,15 +63,20 @@ Gem::Specification.new do |s|
|
|
63
63
|
# = MANIFEST =
|
64
64
|
s.files = %w[
|
65
65
|
Gemfile
|
66
|
+
Gemfile.lock
|
66
67
|
README.rdoc
|
67
68
|
Rakefile
|
68
69
|
benchmarks/class_vs_lambda.rb
|
69
70
|
benchmarks/concat_vs_insert.rb
|
70
71
|
benchmarks/concat_vs_interpolate.rb
|
71
72
|
benchmarks/cr_lf.rb
|
73
|
+
benchmarks/downcase-eq-eq_vs_casecmp.rb
|
72
74
|
benchmarks/excon_vs.rb
|
75
|
+
benchmarks/has_key-vs-hash[key].rb
|
73
76
|
benchmarks/headers_split_vs_match.rb
|
77
|
+
benchmarks/implicit_block-vs-explicit_block.rb
|
74
78
|
benchmarks/merging.rb
|
79
|
+
benchmarks/string_ranged_index.rb
|
75
80
|
benchmarks/strip_newline.rb
|
76
81
|
benchmarks/vs_stdlib.rb
|
77
82
|
excon.gemspec
|
@@ -79,9 +84,11 @@ Gem::Specification.new do |s|
|
|
79
84
|
lib/excon/connection.rb
|
80
85
|
lib/excon/errors.rb
|
81
86
|
lib/excon/response.rb
|
82
|
-
tests/
|
87
|
+
tests/basic_tests.rb
|
88
|
+
tests/rackups/basic.ru
|
89
|
+
tests/rackups/thread_safety.ru
|
83
90
|
tests/test_helper.rb
|
84
|
-
tests/
|
91
|
+
tests/thread_safety_tests.rb
|
85
92
|
]
|
86
93
|
# = MANIFEST =
|
87
94
|
|
data/lib/excon.rb
CHANGED
@@ -12,44 +12,16 @@ require 'excon/errors'
|
|
12
12
|
require 'excon/response'
|
13
13
|
|
14
14
|
module Excon
|
15
|
-
|
16
15
|
unless const_defined?(:VERSION)
|
17
|
-
VERSION = '0.
|
16
|
+
VERSION = '0.5.0'
|
18
17
|
end
|
19
18
|
|
20
19
|
unless const_defined?(:CHUNK_SIZE)
|
21
20
|
CHUNK_SIZE = 1048576 # 1 megabyte
|
22
21
|
end
|
23
22
|
|
24
|
-
def self.ssl_ca_path
|
25
|
-
@ssl_ca_path
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.ssl_ca_path=(new_ssl_ca_path)
|
29
|
-
@ssl_ca_path = new_ssl_ca_path
|
30
|
-
end
|
31
|
-
|
32
|
-
# setup ssl defaults based on platform
|
33
|
-
case Config::CONFIG['host_os']
|
34
|
-
when /mswin|win32|dos|cygwin|mingw/i
|
35
|
-
@ssl_verify_peer = false
|
36
|
-
else
|
37
|
-
@ssl_verify_peer = true
|
38
|
-
end
|
39
|
-
|
40
|
-
# Status of ssl peer verification
|
41
|
-
def self.ssl_verify_peer
|
42
|
-
@ssl_verify_peer
|
43
|
-
end
|
44
|
-
|
45
|
-
# change the status of ssl peer verification
|
46
|
-
def self.ssl_verify_peer=(new_ssl_verify_peer)
|
47
|
-
@ssl_verify_peer = new_ssl_verify_peer
|
48
|
-
end
|
49
|
-
|
50
23
|
# @see Connection#initialize
|
51
|
-
#
|
52
|
-
#
|
24
|
+
# Initializes a new keep-alive session for a given remote host
|
53
25
|
# @param [String] url The destination URL
|
54
26
|
# @param [Hash<Symbol, >] params One or more option params to set on the Connection instance
|
55
27
|
# @return [Connection] A new Excon::Connection instance
|
@@ -57,12 +29,29 @@ module Excon
|
|
57
29
|
Excon::Connection.new(url, params)
|
58
30
|
end
|
59
31
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
32
|
+
# Class-level instance variables and generic HTTP methods
|
33
|
+
class << self
|
34
|
+
# @return [String] The filesystem path to the SSL Certificate Authority
|
35
|
+
attr_accessor :ssl_ca_path
|
36
|
+
|
37
|
+
# @return [true, false] Whether or not to verify the peer's SSL certificate / chain
|
38
|
+
attr_reader :ssl_verify_peer
|
39
|
+
|
40
|
+
# setup ssl defaults based on platform
|
41
|
+
@ssl_verify_peer = Config::CONFIG['host_os'] !~ /mswin|win32|dos|cygwin|mingw/i
|
42
|
+
|
43
|
+
%w{connect delete get head options post put trace}.each do |method|
|
44
|
+
eval <<-DEF
|
45
|
+
def #{method}(url, params = {}, &block)
|
46
|
+
new(url).request(params.merge!(:method => :#{method}), &block)
|
47
|
+
end
|
48
|
+
DEF
|
49
|
+
end
|
66
50
|
end
|
67
51
|
|
52
|
+
# Change the status of ssl peer verification
|
53
|
+
# @see Excon#ssl_verify_peer (attr_reader)
|
54
|
+
def self.ssl_verify_peer=(new_ssl_verify_peer)
|
55
|
+
@ssl_verify_peer = new_ssl_verify_peer && true || false
|
56
|
+
end
|
68
57
|
end
|
data/lib/excon/connection.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module Excon
|
2
2
|
class Connection
|
3
|
-
|
4
3
|
attr_reader :connection
|
5
4
|
|
6
5
|
CR_NL = "\r\n"
|
7
6
|
HTTP_1_1 = " HTTP/1.1\r\n"
|
7
|
+
FORCE_ENC = String.respond_to?(:force_encoding)
|
8
8
|
|
9
9
|
# Initializes a new Connection instance
|
10
10
|
# @param [String] url The destination URL
|
@@ -26,6 +26,7 @@ module Excon
|
|
26
26
|
:query => uri.query,
|
27
27
|
:scheme => uri.scheme
|
28
28
|
}.merge!(params)
|
29
|
+
|
29
30
|
@socket_key = '' << @connection[:host] << ':' << @connection[:port].to_s
|
30
31
|
reset
|
31
32
|
end
|
@@ -45,10 +46,10 @@ module Excon
|
|
45
46
|
# connection has defaults, merge in new params to override
|
46
47
|
params = @connection.merge(params)
|
47
48
|
params[:headers] = @connection[:headers].merge(params[:headers] || {})
|
48
|
-
params[:headers]['Host'] ||=
|
49
|
+
params[:headers]['Host'] ||= '' << params[:host] << ':' << params[:port].to_s
|
49
50
|
|
50
51
|
# if path is empty or doesn't start with '/', insert one
|
51
|
-
unless params[:path][0
|
52
|
+
unless params[:path][0, 1] == '/'
|
52
53
|
params[:path].insert(0, '/')
|
53
54
|
end
|
54
55
|
|
@@ -83,11 +84,9 @@ module Excon
|
|
83
84
|
params[:headers]['Content-Length'] = case params[:body]
|
84
85
|
when File
|
85
86
|
params[:body].binmode
|
86
|
-
File.size(params[:body]
|
87
|
+
File.size(params[:body])
|
87
88
|
when String
|
88
|
-
|
89
|
-
params[:body].force_encoding('BINARY')
|
90
|
-
end
|
89
|
+
params[:body].force_encoding('BINARY') if FORCE_ENC
|
91
90
|
params[:body].length
|
92
91
|
else
|
93
92
|
0
|
@@ -119,16 +118,18 @@ module Excon
|
|
119
118
|
|
120
119
|
# read the response
|
121
120
|
response = Excon::Response.parse(socket, params, &block)
|
121
|
+
|
122
122
|
if response.headers['Connection'] == 'close'
|
123
123
|
reset
|
124
124
|
end
|
125
|
+
|
125
126
|
response
|
126
127
|
rescue => socket_error
|
127
128
|
reset
|
128
129
|
raise(Excon::Errors::SocketError.new(socket_error))
|
129
130
|
end
|
130
131
|
|
131
|
-
if params
|
132
|
+
if params.has_key?(:expects) && ![*params[:expects]].include?(response.status)
|
132
133
|
reset
|
133
134
|
raise(Excon::Errors.status_error(params, response))
|
134
135
|
else
|
@@ -136,7 +137,7 @@ module Excon
|
|
136
137
|
end
|
137
138
|
|
138
139
|
rescue => request_error
|
139
|
-
if params
|
140
|
+
if params.has_key?(:idempotent) &&
|
140
141
|
(request_error.is_a?(Excon::Errors::SocketError) ||
|
141
142
|
(request_error.is_a?(Excon::Errors::HTTPStatusError) && response.status != 404))
|
142
143
|
retries_remaining ||= 4
|
@@ -155,8 +156,7 @@ module Excon
|
|
155
156
|
(old_socket = sockets.delete(@socket_key)) && old_socket.close
|
156
157
|
end
|
157
158
|
|
158
|
-
|
159
|
-
|
159
|
+
private
|
160
160
|
def connect
|
161
161
|
new_socket = TCPSocket.open(@connection[:host], @connection[:port])
|
162
162
|
|
@@ -194,7 +194,7 @@ module Excon
|
|
194
194
|
end
|
195
195
|
|
196
196
|
def closed?
|
197
|
-
sockets
|
197
|
+
sockets.has_key?(@socket_key) && sockets[@socket_key].closed?
|
198
198
|
end
|
199
199
|
|
200
200
|
def socket
|
data/lib/excon/errors.rb
CHANGED
@@ -7,7 +7,11 @@ module Excon
|
|
7
7
|
attr_reader :socket_error
|
8
8
|
|
9
9
|
def initialize(socket_error=nil)
|
10
|
-
|
10
|
+
if socket_error.message =~ /certificate verify failed/
|
11
|
+
super('Unable to verify certificate, please set `Excon.ssl_ca_path = path_to_certs` or `Excon.ssl_verify_peer = false` (less secure).')
|
12
|
+
else
|
13
|
+
super(socket_error.message)
|
14
|
+
end
|
11
15
|
set_backtrace(socket_error.backtrace)
|
12
16
|
@socket_error = socket_error
|
13
17
|
end
|
data/lib/excon/response.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
module Excon
|
2
2
|
class Response
|
3
|
+
attr_accessor :body, :headers, :status
|
3
4
|
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
def initialize(attrs={})
|
6
|
+
@body = attrs[:body] || ''
|
7
|
+
@headers = attrs[:headers] || {}
|
8
|
+
@status = attrs[:status]
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
+
def self.parse(socket, params={})
|
12
|
+
response = new(:status => socket.readline[9, 11].to_i)
|
11
13
|
|
12
|
-
response.status = socket.readline[9..11].to_i
|
13
14
|
while true
|
14
|
-
data = socket.readline.chop!
|
15
|
+
(data = socket.readline).chop!
|
16
|
+
|
15
17
|
unless data.empty?
|
16
18
|
key, value = data.split(': ')
|
17
19
|
response.headers[key] = value
|
@@ -20,53 +22,51 @@ module Excon
|
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
|
-
unless params[:method].to_s.
|
24
|
-
if !block || (params[:expects] && ![*params[:expects]].include?(response.status))
|
25
|
-
response.body = ''
|
26
|
-
block = Concatenator.new(response.body)
|
27
|
-
end
|
25
|
+
unless params[:method].to_s.casecmp('HEAD') == 0
|
28
26
|
|
29
|
-
if response.headers
|
27
|
+
if response.headers.has_key?('Transfer-Encoding') && response.headers['Transfer-Encoding'].casecmp('chunked') == 0
|
30
28
|
while true
|
31
29
|
chunk_size = socket.readline.chop!.to_i(16)
|
32
|
-
|
33
|
-
if chunk_size
|
34
|
-
|
30
|
+
|
31
|
+
break if chunk_size < 1
|
32
|
+
# 2 == "/r/n".length
|
33
|
+
(chunk = socket.read(chunk_size+2)).chop!
|
34
|
+
|
35
|
+
if block_given?
|
36
|
+
yield chunk
|
35
37
|
else
|
36
|
-
|
38
|
+
response.body << chunk
|
37
39
|
end
|
38
40
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
41
|
+
|
42
|
+
elsif response.headers.has_key?('Connection') && response.headers['Connection'].casecmp('close') == 0
|
43
|
+
chunk = socket.read
|
44
|
+
|
45
|
+
if block_given?
|
46
|
+
yield chunk
|
47
|
+
else
|
48
|
+
response.body << chunk
|
49
|
+
end
|
50
|
+
|
51
|
+
elsif response.headers.has_key?('Content-Length')
|
42
52
|
remaining = response.headers['Content-Length'].to_i
|
53
|
+
|
43
54
|
while remaining > 0
|
44
|
-
|
55
|
+
chunk = socket.read([CHUNK_SIZE, remaining].min)
|
56
|
+
|
57
|
+
if block_given?
|
58
|
+
yield chunk
|
59
|
+
else
|
60
|
+
response.body << chunk
|
61
|
+
end
|
62
|
+
|
45
63
|
remaining -= CHUNK_SIZE
|
46
64
|
end
|
47
65
|
end
|
48
66
|
end
|
49
67
|
|
50
|
-
response
|
51
|
-
end
|
52
|
-
|
53
|
-
attr_accessor :body, :headers, :status
|
54
|
-
|
55
|
-
def initialize(attributes = {})
|
56
|
-
@body = attributes[:body] || ''
|
57
|
-
@headers = attributes[:headers] || {}
|
58
|
-
@status = attributes[:status]
|
59
|
-
end
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
class Concatenator
|
64
|
-
def initialize(string)
|
65
|
-
@string = string
|
68
|
+
return response
|
66
69
|
end
|
67
70
|
|
68
|
-
|
69
|
-
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
71
|
+
end # class Response
|
72
|
+
end # module Excon
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
+
|
3
|
+
with_rackup('basic.ru') do
|
4
|
+
Shindo.tests('Excon basics') do
|
5
|
+
tests('GET /content-length/100') do
|
6
|
+
|
7
|
+
connection = Excon.new('http://127.0.0.1:9292')
|
8
|
+
response = connection.request(:method => 'GET', :path => '/content-length/100')
|
9
|
+
|
10
|
+
tests('response.status').returns(200) do
|
11
|
+
response.status
|
12
|
+
end
|
13
|
+
|
14
|
+
tests("response.headers['Connection']").returns('Keep-Alive') do
|
15
|
+
response.headers['Connection']
|
16
|
+
end
|
17
|
+
|
18
|
+
tests("response.headers['Content-Length']").returns('100') do
|
19
|
+
response.headers['Content-Length']
|
20
|
+
end
|
21
|
+
|
22
|
+
tests("response.headers['Content-Type']").returns('text/html;charset=utf-8') do
|
23
|
+
response.headers['Content-Type']
|
24
|
+
end
|
25
|
+
|
26
|
+
test("Time.parse(response.headers['Date']).is_a?(Time)") do
|
27
|
+
Time.parse(response.headers['Date']).is_a?(Time)
|
28
|
+
end
|
29
|
+
|
30
|
+
test("!!(response.headers['Server'] =~ /^WEBrick/)") do
|
31
|
+
!!(response.headers['Server'] =~ /^WEBrick/)
|
32
|
+
end
|
33
|
+
|
34
|
+
tests("response.body").returns('x' * 100) do
|
35
|
+
response.body
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
File without changes
|
data/tests/test_helper.rb
CHANGED
@@ -3,13 +3,13 @@ require 'bundler'
|
|
3
3
|
|
4
4
|
Bundler.require(:default, :development)
|
5
5
|
|
6
|
-
def
|
7
|
-
File.expand_path(File.join(File.dirname(__FILE__), *parts))
|
6
|
+
def rackup_path(*parts)
|
7
|
+
File.expand_path(File.join(File.dirname(__FILE__), 'rackups', *parts))
|
8
8
|
end
|
9
9
|
|
10
|
-
def with_rackup(
|
11
|
-
pid, w, r, e = Open4.popen4("rackup #{
|
12
|
-
|
10
|
+
def with_rackup(name)
|
11
|
+
pid, w, r, e = Open4.popen4("rackup #{rackup_path(name)}")
|
12
|
+
until e.gets =~ /HTTPServer#start:/; end
|
13
13
|
yield
|
14
14
|
ensure
|
15
15
|
Process.kill(9, pid)
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
+
|
3
|
+
with_rackup('thread_safety.ru') do
|
4
|
+
Shindo.tests('Excon thread safety') do
|
5
|
+
connection = Excon.new('http://127.0.0.1:9292')
|
6
|
+
|
7
|
+
long_thread = Thread.new {
|
8
|
+
response = connection.request(:method => 'GET', :path => '/id/1/wait/2')
|
9
|
+
Thread.current[:success] = response.body == '1'
|
10
|
+
}
|
11
|
+
|
12
|
+
short_thread = Thread.new {
|
13
|
+
response = connection.request(:method => 'GET', :path => '/id/2/wait/1')
|
14
|
+
Thread.current[:success] = response.body == '2'
|
15
|
+
}
|
16
|
+
|
17
|
+
long_thread.join
|
18
|
+
short_thread.join
|
19
|
+
|
20
|
+
test('long_thread') do
|
21
|
+
long_thread[:success]
|
22
|
+
end
|
23
|
+
|
24
|
+
test('short_thread') do
|
25
|
+
short_thread[:success]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
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:
|
5
|
-
prerelease:
|
4
|
+
hash: 11
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 5
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.5.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-
|
18
|
+
date: 2011-02-11 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -40,12 +40,12 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - "="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
hash:
|
43
|
+
hash: 23
|
44
44
|
segments:
|
45
45
|
- 0
|
46
|
-
-
|
47
|
-
-
|
48
|
-
version: 0.
|
46
|
+
- 2
|
47
|
+
- 0
|
48
|
+
version: 0.2.0
|
49
49
|
type: :development
|
50
50
|
version_requirements: *id002
|
51
51
|
- !ruby/object:Gem::Dependency
|
@@ -72,15 +72,20 @@ extra_rdoc_files:
|
|
72
72
|
- README.rdoc
|
73
73
|
files:
|
74
74
|
- Gemfile
|
75
|
+
- Gemfile.lock
|
75
76
|
- README.rdoc
|
76
77
|
- Rakefile
|
77
78
|
- benchmarks/class_vs_lambda.rb
|
78
79
|
- benchmarks/concat_vs_insert.rb
|
79
80
|
- benchmarks/concat_vs_interpolate.rb
|
80
81
|
- benchmarks/cr_lf.rb
|
82
|
+
- benchmarks/downcase-eq-eq_vs_casecmp.rb
|
81
83
|
- benchmarks/excon_vs.rb
|
84
|
+
- benchmarks/has_key-vs-hash[key].rb
|
82
85
|
- benchmarks/headers_split_vs_match.rb
|
86
|
+
- benchmarks/implicit_block-vs-explicit_block.rb
|
83
87
|
- benchmarks/merging.rb
|
88
|
+
- benchmarks/string_ranged_index.rb
|
84
89
|
- benchmarks/strip_newline.rb
|
85
90
|
- benchmarks/vs_stdlib.rb
|
86
91
|
- excon.gemspec
|
@@ -88,11 +93,13 @@ files:
|
|
88
93
|
- lib/excon/connection.rb
|
89
94
|
- lib/excon/errors.rb
|
90
95
|
- lib/excon/response.rb
|
91
|
-
- tests/
|
96
|
+
- tests/basic_tests.rb
|
97
|
+
- tests/rackups/basic.ru
|
98
|
+
- tests/rackups/thread_safety.ru
|
92
99
|
- tests/test_helper.rb
|
93
|
-
- tests/
|
100
|
+
- tests/thread_safety_tests.rb
|
94
101
|
has_rdoc: true
|
95
|
-
homepage:
|
102
|
+
homepage: https://github.com/geemus/excon
|
96
103
|
licenses: []
|
97
104
|
|
98
105
|
post_install_message:
|
@@ -121,7 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
128
|
requirements: []
|
122
129
|
|
123
130
|
rubyforge_project: excon
|
124
|
-
rubygems_version: 1.
|
131
|
+
rubygems_version: 1.5.0
|
125
132
|
signing_key:
|
126
133
|
specification_version: 2
|
127
134
|
summary: speed, persistence, http(s)
|
data/tests/threaded_tests.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
|
2
|
-
|
3
|
-
with_rackup do
|
4
|
-
Shindo.tests do
|
5
|
-
test('threaded requests') do
|
6
|
-
connection = Excon.new('http://127.0.0.1:9292')
|
7
|
-
|
8
|
-
long_thread = Thread.new {
|
9
|
-
response = connection.request(:method => 'GET', :path => '/id/1/wait/2')
|
10
|
-
Thread.current[:success] = response.body == '1'
|
11
|
-
}
|
12
|
-
|
13
|
-
short_thread = Thread.new {
|
14
|
-
response = connection.request(:method => 'GET', :path => '/id/2/wait/1')
|
15
|
-
Thread.current[:success] = response.body == '2'
|
16
|
-
}
|
17
|
-
|
18
|
-
long_thread.join
|
19
|
-
short_thread.join
|
20
|
-
|
21
|
-
long_thread[:success] && short_thread[:success]
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|