async-http 0.38.1 → 0.38.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83a5e5bd7e766404f4011a11d61d6cfcc75d1cff40c1822895f21f71ccf91925
4
- data.tar.gz: ecdde5ee1128a0ee9f947a1da217c683fda1c65c281dba0694ff72749a31ca9f
3
+ metadata.gz: 4de4d97aa888d6458d22577150d9d7bb24d90fbfbe29c5c81d106874d0451098
4
+ data.tar.gz: bdf58708f82a9135b1d5a3ead916b3eb4a2766d79852304259de317e01896bfd
5
5
  SHA512:
6
- metadata.gz: ce5c4265e43776b208ef51ebcb5b54b84f0b86e7d8d52dbccf3905869fc6094ec88d74b6afb35eba557ffcae0699dae5f130e7b72f507ac989c28e2904e55fbb
7
- data.tar.gz: 74b16c8ad259f0aaded61ef8094d26043354b717d299c3de04b2a4aab0169b74ebc2808f889ff284468a5ffabd4ad1a2f0e988dd67b268d3a8660303df9b7fe3
6
+ metadata.gz: ca58c3bea25933b04cf306130ff31f3e0770fa0964b2411942fac897eb70862a30668bebaee6eaf22a92e571c178e47be27b39b510679889a3f36b0124054bf0
7
+ data.tar.gz: a1182f2f385ba1bf529511085ae8523faae36267a54586101bcbdf0b225d475285661830d8cfc323ecf310094979e30a6115ee6cab94bcaa87025b72644eaceb
data/README.md CHANGED
@@ -123,6 +123,50 @@ Async::Reactor.run do |task|
123
123
  end
124
124
  ```
125
125
 
126
+ ### Advanced Verification
127
+
128
+ You can hook into SSL certificate verification to improve server verification.
129
+
130
+ ```ruby
131
+ require 'async'
132
+ require 'async/http'
133
+
134
+ # These are generated from the certificate chain that the server presented.
135
+ trusted_fingerprints = {
136
+ "dac9024f54d8f6df94935fb1732638ca6ad77c13" => true,
137
+ "e6a3b45b062d509b3382282d196efe97d5956ccb" => true,
138
+ "07d63f4c05a03f1c306f9941b8ebf57598719ea2" => true,
139
+ "e8d994f44ff20dc78dbff4e59d7da93900572bbf" => true,
140
+ }
141
+
142
+ Async do
143
+ endpoint = Async::HTTP::URLEndpoint.parse("https://www.codeotaku.com/index")
144
+
145
+ # This is a quick hack/POC:
146
+ ssl_context = endpoint.ssl_context
147
+
148
+ ssl_context.verify_callback = proc do |verified, store_context|
149
+ certificate = store_context.current_cert
150
+ fingerprint = OpenSSL::Digest::SHA1.new(certificate.to_der).to_s
151
+
152
+ if trusted_fingerprints.include? fingerprint
153
+ true
154
+ else
155
+ Async.logger.warn("Untrusted Certificate Fingerprint"){fingerprint}
156
+ false
157
+ end
158
+ end
159
+
160
+ endpoint = endpoint.with(ssl_context: ssl_context)
161
+
162
+ client = Async::HTTP::Client.new(endpoint)
163
+
164
+ response = client.get(endpoint.path)
165
+
166
+ pp response.status, response.headers.fields, response.read
167
+ end
168
+ ```
169
+
126
170
  ## Performance
127
171
 
128
172
  On a 4-core 8-thread i7, running `ab` which uses discrete (non-keep-alive) connections:
@@ -0,0 +1,5 @@
1
+
2
+ source 'https://rubygems.org'
3
+
4
+ gem "trenni"
5
+ gem "async-http"
@@ -0,0 +1,35 @@
1
+
2
+ require 'trenni/template'
3
+
4
+ require 'async'
5
+ require 'async/http/body/writable'
6
+
7
+ # The template, using inline text. The sleep could be anything - database query, HTTP request, redis, etc.
8
+ buffer = Trenni::Buffer.new(<<-EOF)
9
+ The "\#{self[:count]} bottles of \#{self[:drink]} on the wall" song!
10
+
11
+ <?r self[:count].downto(1) do |index| ?>
12
+ \#{index} bottles of \#{self[:drink]} on the wall,
13
+ \#{index} bottles of \#{self[:drink]},
14
+ take one down, and pass it around,
15
+ \#{index - 1} bottles of \#{self[:drink]} on the wall.
16
+
17
+ <?r Async::Task.current.sleep(1) ?>
18
+ <?r end ?>
19
+ EOF
20
+
21
+ template = Trenni::Template.new(buffer)
22
+
23
+ Async do
24
+ body = Async::HTTP::Body::Writable.new
25
+
26
+ generator = Async do
27
+ template.to_string({count: 100, drink: 'coffee'}, body)
28
+ end
29
+
30
+ while chunk = body.read
31
+ $stdout.write chunk
32
+ end
33
+
34
+ generator.wait
35
+ end.wait
@@ -32,6 +32,8 @@ module Async
32
32
  return body
33
33
  elsif body.is_a? Array
34
34
  return self.new(body)
35
+ elsif body.is_a?(String)
36
+ return self.new([body])
35
37
  elsif body
36
38
  return self.for(body)
37
39
  end
@@ -28,6 +28,11 @@ require_relative 'middleware'
28
28
  module Async
29
29
  module HTTP
30
30
  class Client
31
+ # Provides a robust interface to a server.
32
+ # * If there are no connections, it will create one.
33
+ # * If there are already connections, it will reuse it.
34
+ # * If a request fails, it will retry it up to N times if it was idempotent.
35
+ # The client object will never become unusable. It internally manages persistent connections (or non-persistent connections if that's required).
31
36
  def initialize(endpoint, protocol = endpoint.protocol, scheme = endpoint.scheme, authority = endpoint.authority, retries: 3, connection_limit: nil)
32
37
  @endpoint = endpoint
33
38
  @protocol = protocol
@@ -91,7 +96,6 @@ module Async
91
96
  # This is a specific case where the entire request wasn't sent before a failure occurred. So, we can even resend non-idempotent requests.
92
97
  @pool.release(connection) if connection
93
98
 
94
- attempt += 1
95
99
  if attempt < @retries
96
100
  retry
97
101
  else
@@ -34,10 +34,15 @@ module Async
34
34
  self.new(url, **options)
35
35
  end
36
36
 
37
+ # @option scheme [String] the scheme to use, overrides the URL scheme.
38
+ # @option port [Integer] the port to bind to, overrides the URL port.
39
+ # @option hostname [String] the hostname to use, overrides the URL hostname.
40
+ # @option ssl_context [OpenSSL::SSL::SSLContext] the context to use for TLS.
41
+ # @option alpn_protocols [Array<String>] the alpn protocols to negotiate.
37
42
  def initialize(url, endpoint = nil, **options)
38
43
  super(**options)
39
44
 
40
- raise ArgumentError.new("URL must be absolute (include scheme, host): #{url}") unless url.absolute?
45
+ raise ArgumentError, "URL must be absolute (include scheme, host): #{url}" unless url.absolute?
41
46
 
42
47
  @url = url
43
48
  @endpoint = endpoint
@@ -143,10 +148,15 @@ module Async
143
148
  end
144
149
 
145
150
  def tcp_options
146
- {
147
- reuse_port: self.reuse_port,
148
- timeout: self.timeout,
149
- }
151
+ options = @options.dup
152
+
153
+ options.delete(:scheme)
154
+ options.delete(:port)
155
+ options.delete(:hostname)
156
+ options.delete(:ssl_context)
157
+ options.delete(:alpn_protocols)
158
+
159
+ return options
150
160
  end
151
161
 
152
162
  def build_endpoint(endpoint = nil)
@@ -172,8 +182,8 @@ module Async
172
182
  endpoint.bind(*args, &block)
173
183
  end
174
184
 
175
- def connect(*args, &block)
176
- endpoint.connect(*args, &block)
185
+ def connect(&block)
186
+ endpoint.connect(&block)
177
187
  end
178
188
 
179
189
  def each
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module HTTP
23
- VERSION = "0.38.1"
23
+ VERSION = "0.38.2"
24
24
  end
25
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-http
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.38.1
4
+ version: 0.38.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-20 00:00:00.000000000 Z
11
+ date: 2019-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -144,6 +144,8 @@ files:
144
144
  - examples/fetch/public/index.html
145
145
  - examples/fetch/public/stream.js
146
146
  - examples/request.rb
147
+ - examples/trenni/Gemfile
148
+ - examples/trenni/streaming.rb
147
149
  - examples/upload/client.rb
148
150
  - examples/upload/data.txt
149
151
  - examples/upload/server.rb
@@ -219,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
219
221
  - !ruby/object:Gem::Version
220
222
  version: '0'
221
223
  requirements: []
222
- rubygems_version: 3.0.2
224
+ rubygems_version: 3.0.3
223
225
  signing_key:
224
226
  specification_version: 4
225
227
  summary: A HTTP client and server library.