async-http 0.50.7 → 0.50.8

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: 7e2b32bb7262cafc68c516d881d6f3a551597248b06b627ae150111dcfa2b656
4
- data.tar.gz: 63f025a564598ec263413f70b9f4a9561a52d1ebbde4d1b2e66c4c9a5a461b89
3
+ metadata.gz: 6140b4806e8fff4a017e4d2973e2d6ecd28bc248069774d351b13fc5ea907ecf
4
+ data.tar.gz: 9eef40decca9b155053f7419993d705e280d0ea51e385dc030efebe6d20d4933
5
5
  SHA512:
6
- metadata.gz: a2d4dad8cdbf23281345f4ab8e5d7d0b58f83f86513940aa108ba292b82defd2ab5bb23b8fd117618ecc0be1a7ecc1d74a81f65582be18362c5bd7d82072f26f
7
- data.tar.gz: bef0076a4130b928e1ffd7f42abf15647d639b6ee125de1f71f50d50ae6ede8631f0e11b8c85b455916f3e5417113907de93a9d69e79ac281804d121480c587b
6
+ metadata.gz: dc926ac38b9d1bf6860ff23282f9c90eb78b965c881fae8130501e0cb4260c757bcf9bb8ee634674b2c3a37b013496ae08a332e54309e0f90979779197505d2c
7
+ data.tar.gz: b1fb1c1cbbea6b31bdeccaec48972bff12b58f86c8d6b1e5d42f36e389d3c7d5040839d8a74359cc835002e15631bc754a168d8ae643814bfe71e1ea0eadbc7d
data/.travis.yml CHANGED
@@ -11,6 +11,8 @@ addons:
11
11
  packages:
12
12
  - wrk
13
13
 
14
+ script: bundle exec rspec
15
+
14
16
  matrix:
15
17
  include:
16
18
  - rvm: 2.4
data/README.md CHANGED
@@ -160,9 +160,9 @@ Here is a basic example of a client/server running in the same reactor:
160
160
  ```ruby
161
161
  #!/usr/bin/env ruby
162
162
 
163
+ require 'async'
163
164
  require 'async/http/server'
164
165
  require 'async/http/client'
165
- require 'async/reactor'
166
166
  require 'async/http/endpoint'
167
167
  require 'async/http/protocol/response'
168
168
 
@@ -175,7 +175,7 @@ end
175
175
  server = Async::HTTP::Server.new(app, endpoint)
176
176
  client = Async::HTTP::Client.new(endpoint)
177
177
 
178
- Async::Reactor.run do |task|
178
+ Async do |task|
179
179
  server_task = task.async do
180
180
  server.run
181
181
  end
data/async-http.gemspec CHANGED
@@ -27,6 +27,8 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  # spec.add_dependency("openssl")
29
29
 
30
+ spec.add_development_dependency "bake-bundler"
31
+
30
32
  spec.add_development_dependency "async-rspec", "~> 1.10"
31
33
  spec.add_development_dependency "async-container", "~> 0.14.0"
32
34
 
@@ -36,5 +38,4 @@ Gem::Specification.new do |spec|
36
38
  spec.add_development_dependency "covered"
37
39
  spec.add_development_dependency "bundler"
38
40
  spec.add_development_dependency "rspec", "~> 3.6"
39
- spec.add_development_dependency "rake"
40
41
  end
data/bake/async/http.rb CHANGED
@@ -21,7 +21,7 @@ def fetch(url, method:)
21
21
  format_body = proc do |body, terminal|
22
22
  if body
23
23
  if length = body.length
24
- terminal.print(:body, "body with length", :length, length, "B")
24
+ terminal.print(:body, "body with length ", :length, length, "B")
25
25
  else
26
26
  terminal.print(:body, "body without length")
27
27
  end
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'async'
4
+ require 'async/clock'
5
+ require 'async/barrier'
6
+ require_relative '../../lib/async/http/endpoint'
7
+ require_relative '../../lib/async/http/client'
8
+
9
+ Async do
10
+ url = "https://static.openfoodfacts.org/data/en.openfoodfacts.org.products.csv"
11
+
12
+ endpoint = Async::HTTP::Endpoint.parse(url)
13
+ client = Async::HTTP::Client.new(endpoint)
14
+
15
+ headers = {'user-agent' => 'curl/7.69.1', 'accept' => '*/*'}
16
+
17
+ file = File.open("products.csv", "w")
18
+ Async.logger.info(self) {"Saving download to #{Dir.pwd}"}
19
+
20
+ begin
21
+ response = client.head(endpoint.path, headers)
22
+ content_length = nil
23
+
24
+ if response.success?
25
+ unless response.headers['accept-ranges'].include?('bytes')
26
+ raise "Does not advertise support for accept-ranges: bytes!"
27
+ end
28
+
29
+ unless content_length = response.body&.length
30
+ raise "Could not determine length of response!"
31
+ end
32
+ end
33
+ ensure
34
+ response&.close
35
+ end
36
+
37
+ Async.logger.info(self) {"Content length: #{content_length/(1024**2)}MiB"}
38
+
39
+ parts = []
40
+ offset = 0
41
+ chunk_size = 1024*1024
42
+
43
+ start_time = Async::Clock.now
44
+ amount = 0
45
+
46
+ while offset < content_length
47
+ byte_range_start = offset
48
+ byte_range_end = [offset + chunk_size, content_length].min
49
+ parts << (byte_range_start...byte_range_end)
50
+
51
+ offset += chunk_size
52
+ end
53
+
54
+ Async.logger.info(self) {"Breaking download into #{parts.size} parts..."}
55
+
56
+ barrier = Async::Barrier.new
57
+
58
+ while !parts.empty?
59
+ barrier.async do
60
+ part = parts.shift
61
+
62
+ Async.logger.info(self) {"Issuing range request range: bytes=#{part.min}-#{part.max}"}
63
+
64
+ response = client.get(endpoint.path, [
65
+ ["range", "bytes=#{part.min}-#{part.max-1}"],
66
+ *headers
67
+ ])
68
+
69
+ if response.success?
70
+ Async.logger.info(self) {"Got response: #{response}... writing data for #{part}."}
71
+ written = file.pwrite(response.read, part.min)
72
+
73
+ amount += written
74
+
75
+ duration = Async::Clock.now - start_time
76
+ Async.logger.info(self) {"Rate: #{((amount.to_f/(1024**2))/duration).round(2)}MiB/s"}
77
+ end
78
+ end
79
+ end
80
+
81
+ barrier.wait
82
+ ensure
83
+ client&.close
84
+ end
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'async'
4
+ require 'async/http/internet'
5
+
6
+ Async do |parent|
7
+ internet = Async::HTTP::Internet.new
8
+ connection = nil
9
+
10
+ child = parent.async do
11
+ response = internet.get("https://utopia-falcon-heroku.herokuapp.com/beer/index")
12
+ connection = response.connection
13
+
14
+ response.each do |chunk|
15
+ Async.logger.info(response) {chunk}
16
+ end
17
+ ensure
18
+ Async.logger.info(response) {"Closing response..."}
19
+ response&.close
20
+ end
21
+
22
+ parent.sleep(5)
23
+
24
+ Async.logger.info(parent) {"Killing #{child}..."}
25
+ child.stop
26
+ ensure
27
+ internet&.close
28
+ end
@@ -103,36 +103,53 @@ module Async
103
103
  # As we cache pool, it's possible these pool go bad (e.g. closed by remote host). In this case, we need to try again. It's up to the caller to impose a timeout on this. If this is the last attempt, we force a new connection.
104
104
  connection = @pool.acquire
105
105
 
106
- response = request.call(connection)
106
+ response = make_response(request, connection)
107
107
 
108
- # The connection won't be released until the body is completely read/released.
109
- ::Protocol::HTTP::Body::Streamable.wrap(response) do
110
- @pool.release(connection)
111
- end
108
+ # This signals that the ensure block below should not try to release the connection, because it's bound into the response which will be returned:
109
+ connection = nil
112
110
 
113
111
  return response
114
112
  rescue Protocol::RequestFailed
115
113
  # This is a specific case where the entire request wasn't sent before a failure occurred. So, we can even resend non-idempotent requests.
116
- @pool.release(connection) if connection
114
+ if connection
115
+ @pool.release(connection)
116
+ connection = nil
117
+ end
117
118
 
118
119
  if attempt < @retries
119
120
  retry
120
121
  else
121
122
  raise
122
123
  end
123
- rescue
124
- @pool.release(connection) if connection
124
+ rescue Errno::ECONNRESET, Errno::EPIPE, IOError
125
+ if connection
126
+ @pool.release(connection)
127
+ connection = nil
128
+ end
125
129
 
126
130
  if request.idempotent? and attempt < @retries
127
131
  retry
128
132
  else
129
133
  raise
130
134
  end
135
+ ensure
136
+ @pool.release(connection) if connection
131
137
  end
132
138
  end
133
139
 
134
140
  protected
135
141
 
142
+ def make_response(request, connection)
143
+ response = request.call(connection)
144
+
145
+ # The connection won't be released until the body is completely read/released.
146
+ ::Protocol::HTTP::Body::Streamable.wrap(response) do
147
+ @pool.release(connection)
148
+ end
149
+
150
+ return response
151
+ end
152
+
136
153
  def make_pool(connection_limit)
137
154
  Async::Pool::Controller.wrap(limit: connection_limit) do
138
155
  Async.logger.debug(self) {"Making connection to #{@endpoint.inspect}"}
@@ -22,6 +22,6 @@
22
22
 
23
23
  module Async
24
24
  module HTTP
25
- VERSION = "0.50.7"
25
+ VERSION = "0.50.8"
26
26
  end
27
27
  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.50.7
4
+ version: 0.50.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-21 00:00:00.000000000 Z
11
+ date: 2020-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.11.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: bake-bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: async-rspec
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -192,20 +206,6 @@ dependencies:
192
206
  - - "~>"
193
207
  - !ruby/object:Gem::Version
194
208
  version: '3.6'
195
- - !ruby/object:Gem::Dependency
196
- name: rake
197
- requirement: !ruby/object:Gem::Requirement
198
- requirements:
199
- - - ">="
200
- - !ruby/object:Gem::Version
201
- version: '0'
202
- type: :development
203
- prerelease: false
204
- version_requirements: !ruby/object:Gem::Requirement
205
- requirements:
206
- - - ">="
207
- - !ruby/object:Gem::Version
208
- version: '0'
209
209
  description:
210
210
  email:
211
211
  - samuel.williams@oriontransfer.co.nz
@@ -219,13 +219,13 @@ files:
219
219
  - ".travis.yml"
220
220
  - Gemfile
221
221
  - README.md
222
- - Rakefile
223
222
  - async-http.gemspec
224
223
  - bake.rb
225
224
  - bake/async/http.rb
226
225
  - bake/async/http/h2spec.rb
227
226
  - examples/compare/Gemfile
228
227
  - examples/compare/benchmark.rb
228
+ - examples/download/chunked.rb
229
229
  - examples/fetch/Gemfile
230
230
  - examples/fetch/Gemfile.lock
231
231
  - examples/fetch/README.md
@@ -234,6 +234,7 @@ files:
234
234
  - examples/fetch/public/stream.js
235
235
  - examples/google/search.rb
236
236
  - examples/request.rb
237
+ - examples/stream/stop.rb
237
238
  - examples/trenni/Gemfile
238
239
  - examples/trenni/streaming.rb
239
240
  - examples/upload/client.rb
data/Rakefile DELETED
@@ -1,9 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new
5
-
6
- task :default => :spec
7
-
8
- # Load all rake tasks:
9
- import(*Dir.glob('tasks/**/*.rake'))