async-http 0.48.2 → 0.49.0

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: '0899a35a93ac5e933f7187c1882ff12882a71bd0f9cc9de70822968a3cbbe524'
4
- data.tar.gz: 708d8334a3963fa28b6b628394a7429bd5bfd76df93ac7def6fe9a0d70b89933
3
+ metadata.gz: 6e9889b252683ee3e3a2fdb7e41c776615d88105425d03880dd76ba3a7fa7b4f
4
+ data.tar.gz: ff700f16b6f5caa0ebf3d7d48f01ce89d903d5670cf189b6856f25b7238e91ea
5
5
  SHA512:
6
- metadata.gz: d0633dfbaadea54ea15d24b9d6646c21a7b57405eefae1491d5cb176a857df50076dff59c64a7f3d41eee8c9fb8e005f5d860bae807247b3caf2876beddce033
7
- data.tar.gz: a4251adb92b19fd2196f193d6c5f39d158610e9e782c5fcdcc6057b6c892c9036309447905729c46b755ced9dd64ab2379d836727e43707ce45f24eb2f3b1fe9
6
+ metadata.gz: fefc876e105b822b446527c42cfd909ea9123dc194bd142bf8f4ee7eae92ac71a4ca444532b97ab96de996552ac757dc10403eb4bb8bcfdb286273b092c14b4e
7
+ data.tar.gz: 1a64d6556647c666b29d91b012a6826c6cc973683c512437a7255c58d74a03a4c083f22cffa3f4a20e4873bad4f45662437135be3945a1500869d5683b4b094c
data/Gemfile CHANGED
@@ -1,8 +1,10 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in async-io.gemspec
4
3
  gemspec
5
4
 
5
+ # gem "async", path: "../async"
6
+ # gem "async-io", path: "../async-io"
7
+
6
8
  # gem "protocol-http", path: "../protocol-http"
7
9
  # gem "protocol-http1", path: "../protocol-http1"
8
10
  # gem "protocol-http2", path: "../protocol-http2"
@@ -10,4 +12,5 @@ gemspec
10
12
 
11
13
  group :development do
12
14
  gem 'pry'
15
+ gem 'ruby-prof', '~> 0.18'
13
16
  end
data/README.md CHANGED
@@ -41,7 +41,7 @@ require 'async/http/internet'
41
41
 
42
42
  data = {'life' => 42}
43
43
 
44
- Async.run do
44
+ Async do
45
45
  # Make a new internet:
46
46
  internet = Async::HTTP::Internet.new
47
47
 
@@ -72,7 +72,7 @@ Here is an example showing how to download a file and save it to a local path:
72
72
  require 'async'
73
73
  require 'async/http/internet'
74
74
 
75
- Async.run do
75
+ Async do
76
76
  # Make a new internet:
77
77
  internet = Async::HTTP::Internet.new
78
78
 
@@ -98,7 +98,7 @@ require 'async/http/server'
98
98
  require 'async/http/client'
99
99
  require 'async/reactor'
100
100
  require 'async/http/endpoint'
101
- require 'async/http/response'
101
+ require 'async/http/protocol/response'
102
102
 
103
103
  endpoint = Async::HTTP::Endpoint.parse('http://127.0.0.1:9294')
104
104
 
data/async-http.gemspec CHANGED
@@ -16,17 +16,17 @@ Gem::Specification.new do |spec|
16
16
  spec.executables = spec.files.grep(%r{^bin/}) {|f| File.basename(f)}
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.add_dependency("async", "~> 1.19")
20
- spec.add_dependency("async-io", "~> 1.25")
19
+ spec.add_dependency("async", "~> 1.23")
20
+ spec.add_dependency("async-io", "~> 1.27.0")
21
21
 
22
- spec.add_dependency("protocol-http", "~> 0.12.0")
23
- spec.add_dependency("protocol-http1", "~> 0.9.0")
24
- spec.add_dependency("protocol-http2", "~> 0.9.0")
22
+ spec.add_dependency("protocol-http", "~> 0.13.0")
23
+ spec.add_dependency("protocol-http1", "~> 0.10.0")
24
+ spec.add_dependency("protocol-http2", "~> 0.10.0")
25
25
 
26
26
  # spec.add_dependency("openssl")
27
27
 
28
28
  spec.add_development_dependency "async-rspec", "~> 1.10"
29
- spec.add_development_dependency "async-container", "~> 0.14"
29
+ spec.add_development_dependency "async-container", "~> 0.14.0"
30
30
 
31
31
  spec.add_development_dependency "rack-test"
32
32
 
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "async"
4
+ require "async/clock"
5
+ require "protocol/http/middleware"
6
+ require_relative "../../lib/async/http"
7
+
8
+ URL = "https://www.google.com/search"
9
+ ENDPOINT = Async::HTTP::Endpoint.parse(URL)
10
+
11
+ class Google < Protocol::HTTP::Middleware
12
+ def search(term)
13
+ Async.logger.info(self) {"Searching for #{term}..."}
14
+
15
+ self.get("/search?q=#{term}", {"user-agent" => "Hi Google!"})
16
+ end
17
+ end
18
+
19
+ terms = %w{thoughtful fear size payment lethal modern recognise face morning sulky mountainous contain science snow uncle skirt truthful door travel snails closed rotten halting creator teeny-tiny beautiful cherries unruly level follow strip team things suggest pretty warm end cannon bad pig consider airport strengthen youthful fog three walk furry pickle moaning fax book ruddy sigh plate cakes shame stem faulty bushes dislike train sleet one colour behavior bitter suit count loutish squeak learn watery orange idiotic seat wholesale omniscient nostalgic arithmetic instruct committee puffy program cream cake whistle rely encourage war flagrant amusing fluffy prick utter wacky occur daily son check}
20
+
21
+ if count = ENV['COUNT']&.to_i
22
+ terms = terms.first(count)
23
+ end
24
+
25
+ Async do |task|
26
+ client = Async::HTTP::Client.new(ENDPOINT)
27
+ google = Google.new(client)
28
+
29
+ google.search("null").finish
30
+
31
+ duration = Async::Clock.measure do
32
+ counts = terms.map do |term|
33
+ task.async do
34
+ response = google.search(term)
35
+ [term, response.read.scan(term).count]
36
+ end
37
+ end.map(&:wait).to_h
38
+
39
+ pp counts
40
+ end
41
+
42
+ pp duration
43
+ ensure
44
+ google.close
45
+ end
data/examples/request.rb CHANGED
@@ -10,7 +10,7 @@ require 'async/http/endpoint'
10
10
 
11
11
  # Async.logger.level = Logger::DEBUG
12
12
 
13
- Async.run do |task|
13
+ Async do |task|
14
14
  endpoint = Async::HTTP::Endpoint.parse("https://www.google.com")
15
15
 
16
16
  client = Async::HTTP::Client.new(endpoint)
@@ -8,7 +8,7 @@ require 'async/http/body/delayed'
8
8
  require 'async/http/client'
9
9
  require 'async/http/endpoint'
10
10
 
11
- Async.run do
11
+ Async do
12
12
  endpoint = Async::HTTP::Endpoint.parse("http://localhost:9222")
13
13
  client = Async::HTTP::Client.new(endpoint, Async::HTTP::Protocol::HTTP2)
14
14
 
@@ -10,7 +10,7 @@ endpoint = Async::HTTP::Endpoint.parse('http://127.0.0.1:9222', reuse_port: true
10
10
 
11
11
  Async.logger.level = Logger::DEBUG
12
12
 
13
- Async.run do
13
+ Async do
14
14
  server = Async::HTTP::Server.for(endpoint, protocol) do |request|
15
15
  Protocol::HTTP::Response[200, {}, request.body]
16
16
  end
@@ -4,7 +4,7 @@ require 'async'
4
4
  require 'async/http/body/file'
5
5
  require 'async/http/internet'
6
6
 
7
- Async.run do
7
+ Async do
8
8
  internet = Async::HTTP::Internet.new
9
9
 
10
10
  headers = [
@@ -126,11 +126,11 @@ module Async
126
126
 
127
127
  protected
128
128
 
129
- def make_pool(connection_limit = nil)
129
+ def make_pool(connection_limit)
130
130
  Pool.new(connection_limit) do
131
131
  Async.logger.debug(self) {"Making connection to #{@endpoint.inspect}"}
132
132
 
133
- @protocol.client(IO::Stream.new(@endpoint.connect))
133
+ @protocol.client(@endpoint.connect)
134
134
  end
135
135
  end
136
136
  end
@@ -161,21 +161,8 @@ module Async
161
161
  end
162
162
  end
163
163
 
164
- def tcp_options
165
- options = @options.dup
166
-
167
- options.delete(:scheme)
168
- options.delete(:port)
169
- options.delete(:hostname)
170
- options.delete(:ssl_context)
171
- options.delete(:alpn_protocols)
172
- options.delete(:protocol)
173
-
174
- return options
175
- end
176
-
177
164
  def build_endpoint(endpoint = nil)
178
- endpoint ||= Async::IO::Endpoint.tcp(self.hostname, port, tcp_options)
165
+ endpoint ||= tcp_endpoint
179
166
 
180
167
  if secure?
181
168
  # Wrap it in SSL:
@@ -204,8 +191,8 @@ module Async
204
191
  def each
205
192
  return to_enum unless block_given?
206
193
 
207
- self.endpoint.each do |endpoint|
208
- yield self.class.new(@url, endpoint, @options)
194
+ self.tcp_endpoint.each do |endpoint|
195
+ yield self.class.new(@url, endpoint, **@options)
209
196
  end
210
197
  end
211
198
 
@@ -220,6 +207,25 @@ module Async
220
207
  def hash
221
208
  self.key.hash
222
209
  end
210
+
211
+ protected
212
+
213
+ def tcp_options
214
+ options = @options.dup
215
+
216
+ options.delete(:scheme)
217
+ options.delete(:port)
218
+ options.delete(:hostname)
219
+ options.delete(:ssl_context)
220
+ options.delete(:alpn_protocols)
221
+ options.delete(:protocol)
222
+
223
+ return options
224
+ end
225
+
226
+ def tcp_endpoint
227
+ Async::IO::Endpoint.tcp(self.hostname, port, **tcp_options)
228
+ end
223
229
  end
224
230
  end
225
231
  end
@@ -45,6 +45,7 @@ module Async
45
45
  @limit = limit
46
46
 
47
47
  @constructor = block
48
+ @guard = Async::Semaphore.new(1)
48
49
  end
49
50
 
50
51
  # The number of allocated resources.
@@ -54,7 +55,7 @@ module Async
54
55
 
55
56
  # Whether there are resources which are currently in use.
56
57
  def busy?
57
- @resources.collect do |_,usage|
58
+ @resources.collect do |_, usage|
58
59
  return true if usage > 0
59
60
  end
60
61
 
@@ -138,6 +139,10 @@ module Async
138
139
 
139
140
  Async.logger.debug(self) {"Wait for resource #{resource}"}
140
141
 
142
+ if resource.multiplex
143
+ @available.signal
144
+ end
145
+
141
146
  return resource
142
147
  end
143
148
 
@@ -165,10 +170,12 @@ module Async
165
170
  end
166
171
  end
167
172
 
168
- if !@limit or self.active < @limit
169
- Async.logger.debug(self) {"No resources resources, allocating new one..."}
170
-
171
- return create
173
+ @guard.acquire do
174
+ if @limit.nil? or self.active < @limit
175
+ Async.logger.debug(self) {"No resources resources, allocating new one..."}
176
+
177
+ return create
178
+ end
172
179
  end
173
180
 
174
181
  return nil
@@ -31,12 +31,16 @@ module Async
31
31
  true
32
32
  end
33
33
 
34
- def self.client(stream)
35
- HTTP1::Client.new(stream, VERSION)
34
+ def self.client(peer)
35
+ stream = IO::Stream.new(peer, sync: false)
36
+
37
+ return HTTP1::Client.new(stream, VERSION)
36
38
  end
37
39
 
38
- def self.server(stream)
39
- HTTP1::Server.new(stream, VERSION)
40
+ def self.server(peer)
41
+ stream = IO::Stream.new(peer, sync: false)
42
+
43
+ return HTTP1::Server.new(stream, VERSION)
40
44
  end
41
45
 
42
46
  def self.names
@@ -70,8 +70,7 @@ module Async
70
70
  end
71
71
 
72
72
  def reusable?
73
- @stream && !@stream.closed?
74
- # !(self.closed? || @stream.closed?)
73
+ @persistent && @stream && !@stream.closed?
75
74
  end
76
75
 
77
76
  def close
@@ -30,12 +30,16 @@ module Async
30
30
  false
31
31
  end
32
32
 
33
- def self.client(stream)
34
- HTTP1::Client.new(stream, VERSION)
33
+ def self.client(peer)
34
+ stream = IO::Stream.new(peer, sync: false)
35
+
36
+ return HTTP1::Client.new(stream, VERSION)
35
37
  end
36
38
 
37
- def self.server(stream)
38
- HTTP1::Server.new(stream, VERSION)
39
+ def self.server(peer)
40
+ stream = IO::Stream.new(peer, sync: false)
41
+
42
+ return HTTP1::Server.new(stream, VERSION)
39
43
  end
40
44
 
41
45
  def self.names
@@ -30,12 +30,16 @@ module Async
30
30
  true
31
31
  end
32
32
 
33
- def self.client(stream)
34
- HTTP1::Client.new(stream, VERSION)
33
+ def self.client(peer)
34
+ stream = IO::Stream.new(peer, sync: false)
35
+
36
+ return HTTP1::Client.new(stream, VERSION)
35
37
  end
36
38
 
37
- def self.server(stream)
38
- HTTP1::Server.new(stream, VERSION)
39
+ def self.server(peer)
40
+ stream = IO::Stream.new(peer, sync: false)
41
+
42
+ return HTTP1::Server.new(stream, VERSION)
39
43
  end
40
44
 
41
45
  def self.names
@@ -45,7 +45,9 @@ module Async
45
45
  ::Protocol::HTTP2::Settings::ENABLE_CONNECT_PROTOCOL => 1,
46
46
  }
47
47
 
48
- def self.client(stream, settings = CLIENT_SETTINGS)
48
+ def self.client(peer, settings = CLIENT_SETTINGS)
49
+ stream = IO::Stream.new(peer, sync: true, deferred: true)
50
+
49
51
  client = Client.new(stream)
50
52
 
51
53
  client.send_connection_preface(settings)
@@ -54,7 +56,9 @@ module Async
54
56
  return client
55
57
  end
56
58
 
57
- def self.server(stream, settings = SERVER_SETTINGS)
59
+ def self.server(peer, settings = SERVER_SETTINGS)
60
+ stream = IO::Stream.new(peer, sync: true, deferred: true)
61
+
58
62
  server = Server.new(stream)
59
63
 
60
64
  server.read_connection_preface(settings)
@@ -72,12 +76,12 @@ module Async
72
76
  ::Protocol::HTTP2::Settings::ENABLE_PUSH => 1,
73
77
  )
74
78
 
75
- def self.client(stream, settings = CLIENT_SETTINGS)
76
- HTTP2.client(stream, settings)
79
+ def self.client(peer, settings = CLIENT_SETTINGS)
80
+ HTTP2.client(peer, settings)
77
81
  end
78
82
 
79
- def self.server(stream, settings = SERVER_SETTINGS)
80
- HTTP2.server(stream, settings)
83
+ def self.server(peer, settings = SERVER_SETTINGS)
84
+ HTTP2.server(peer, settings)
81
85
  end
82
86
 
83
87
  def self.names
@@ -74,12 +74,16 @@ module Async
74
74
  @write_frame_guard.acquire do
75
75
  super
76
76
  end
77
+
78
+ @stream.flush
77
79
  end
78
80
 
79
81
  def write_frames(&block)
80
82
  @write_frame_guard.acquire do
81
83
  super
82
84
  end
85
+
86
+ @stream.flush
83
87
  end
84
88
 
85
89
  def read_in_background(task: Task.current)
@@ -91,7 +95,7 @@ module Async
91
95
  self.consume_window
92
96
  self.read_frame
93
97
  end
94
- rescue EOFError, Errno::ECONNRESET, Errno::EPIPE, Async::Wrapper::Cancelled
98
+ rescue IOError, EOFError, Errno::ECONNRESET, Errno::EPIPE, Async::Wrapper::Cancelled
95
99
  # Ignore.
96
100
  ensure
97
101
  close($!)
@@ -50,11 +50,14 @@ module Async
50
50
  end
51
51
 
52
52
  def close(error = nil)
53
+ # This invokes Framer#close which closes the stream:
53
54
  super
54
55
 
55
- # Stop the request loop:
56
- @requests.enqueue nil
57
- @requests = nil
56
+ if @requests
57
+ # Stop the request loop:
58
+ @requests.enqueue nil
59
+ @requests = nil
60
+ end
58
61
  end
59
62
 
60
63
  def each
@@ -55,9 +55,9 @@ module Async
55
55
  nil => HTTP11,
56
56
  }
57
57
 
58
- def self.protocol_for(stream)
58
+ def self.protocol_for(peer)
59
59
  # alpn_protocol is only available if openssl v1.0.2+
60
- name = stream.io.alpn_protocol
60
+ name = peer.alpn_protocol
61
61
 
62
62
  Async.logger.debug(self) {"Negotiating protocol #{name.inspect}..."}
63
63
 
@@ -68,12 +68,12 @@ module Async
68
68
  end
69
69
  end
70
70
 
71
- def self.client(stream)
72
- protocol_for(stream).client(stream)
71
+ def self.client(peer)
72
+ protocol_for(peer).client(peer)
73
73
  end
74
74
 
75
- def self.server(stream)
76
- protocol_for(stream).server(stream)
75
+ def self.server(peer)
76
+ protocol_for(peer).server(peer)
77
77
  end
78
78
 
79
79
  # Supported Application Layer Protocol Negotiation names:
@@ -44,8 +44,7 @@ module Async
44
44
  attr :scheme
45
45
 
46
46
  def accept(peer, address, task: Task.current)
47
- stream = Async::IO::Stream.new(peer)
48
- connection = @protocol.server(stream)
47
+ connection = @protocol.server(peer)
49
48
 
50
49
  Async.logger.debug(self) {"Incoming connnection from #{address.inspect} to #{@protocol}"}
51
50
 
@@ -62,6 +61,8 @@ module Async
62
61
  # If this returns nil, we assume that the connection has been hijacked.
63
62
  self.call(request)
64
63
  end
64
+ ensure
65
+ connection&.close
65
66
  end
66
67
 
67
68
  def run
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module HTTP
23
- VERSION = "0.48.2"
23
+ VERSION = "0.49.0"
24
24
  end
25
25
  end
data/tasks/server.rake CHANGED
@@ -17,7 +17,7 @@ task :google do
17
17
  require 'async'
18
18
  require 'pry'
19
19
 
20
- Async.run do
20
+ Async do
21
21
  endpoint = Async::HTTP::Endpoint.parse("https://www.google.com")
22
22
  peer = endpoint.connect
23
23
  stream = Async::IO::Stream.new(peer)
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.48.2
4
+ version: 0.49.0
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-08-13 00:00:00.000000000 Z
11
+ date: 2019-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async
@@ -16,70 +16,70 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.19'
19
+ version: '1.23'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.19'
26
+ version: '1.23'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: async-io
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.25'
33
+ version: 1.27.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.25'
40
+ version: 1.27.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: protocol-http
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.12.0
47
+ version: 0.13.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.12.0
54
+ version: 0.13.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: protocol-http1
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.9.0
61
+ version: 0.10.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.9.0
68
+ version: 0.10.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: protocol-http2
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.9.0
75
+ version: 0.10.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.9.0
82
+ version: 0.10.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: async-rspec
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0.14'
103
+ version: 0.14.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0.14'
110
+ version: 0.14.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rack-test
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -199,6 +199,7 @@ files:
199
199
  - examples/fetch/config.ru
200
200
  - examples/fetch/public/index.html
201
201
  - examples/fetch/public/stream.js
202
+ - examples/google/search.rb
202
203
  - examples/request.rb
203
204
  - examples/trenni/Gemfile
204
205
  - examples/trenni/streaming.rb
@@ -263,7 +264,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
263
264
  - !ruby/object:Gem::Version
264
265
  version: '0'
265
266
  requirements: []
266
- rubygems_version: 3.0.3
267
+ rubygems_version: 3.0.6
267
268
  signing_key:
268
269
  specification_version: 4
269
270
  summary: A HTTP client and server library.